lalahop

Auto-hébergement sur Raspberry Pi

Aujourd'hui, je vais vous faire un feedback sur comment monter son petit serveur @home avec un Raspberry Pi. Je sais que le sujet est éculé, c'est pourquoi je vais me focaliser sur les problèmes spécifiques que j'ai rencontré. Problèmes qui sont d'ailleurs plus liés à mon FAI qu'au Raspberry Pi.

Table des matières

Ça pue, c'est pas libre !

Bon, je vais affamer ce troll immédiatement.

Oui, le GPU utilise un blob propriétaire, oui, c'est mal, oui, ce genre de pratique doit cesser. Oui, Broadcom a tenté, fin 2012, de faire croire qu'ils avaient ouvert leur blob mais il n'en est rien : seul un binding maladroit en userland a été fournis à la communauté. Oui, c'est une pratique de merde.

Ceux qui, comme moi au début, pensent que c'est modérément grave pour un usage serveur qui ne fait pas usage du GPU se trompent : « L’une des tâches du bootloader est d’initialiser le matériel. Dans le cas de la Raspberry Pi, il n’y a pas de bootloader. Le SoC est la fusion d’un cœur ARM et d’un GPU (Graphics Processing Unit ou processeur graphique). Or, c’est le GPU qui cherche et charge son firmware propriétaire depuis la carde SD, initialise le système et passe le relai au processeur ARM et au noyau Linux. [...] le bootloader et toute la partie « pilotage du matériel » est l’affaire du VideoCore et non du processeur. ». Source : GNU Linux Magazine France numéro 156 pages 66 et 71.

Nuançons quand même : un desktop, un laptop ou un ordinateur de poche (mais si vous savez, un ordinateur qui fait aussi téléphone, pas intelligent du tout) est-il mieux ?

  • Sur votre desktop/laptop, vous pouvez avoir des OS libres, parfois tous vos drivers libres, toute votre installation en logiciels libres. Et votre BIOS/UEFI alors ? Pouvez-vous utiliser Coreboot sur votre machine et l'avez-vous fait ? Et quid du firmware de certains composants (lecteur/graveur CD/DVD/BD, disque dur/SSD, carte réseau, ...) ?
  • Sur votre ordinateur de poche, vous pouvez avoir des OS libres, tous vos firmwares libres dans de rares cas, toute votre installation en logiciels libres. Et la puce baseband ? Celle qui émet et reçoit sur le réseau dont personne ne connaît les spécifications ?
  • Et dans tous les cas, que ça soit desktop, laptop, ordinateur de poche ou Raspberry Pi, savez-vous à quoi servent tous les circuits, toutes les puces ? Aucune d'elle ne peut vous nuire ? Pouvez-vous le savoir ? Avez-vous les plans et les spécifications ? Non, ce n'est pas de l'Open Hardware.

Ce que j'essaye d'écrire, c'est que vous ne pouvez pas avoir beaucoup plus confiance en votre PC, en votre laptop et encore moins en votre ordinateur de proche qu'en votre Raspberry Pi. Tout est question de compromis. Certes, le RPi, c'est un blob propriétaire bien ancré dans le système. Un compromis de plus ...

Notons qu'il existe des concurrents plus libres au RPi, voir : Single-board computers - Free Software Foundation, par exemple : OLinuXino, la RaspBerry Pi version Open Source sur LinuxFr. La prochaine fois, je prendrai ça ...

C'est ni stable ni fiable

Vu le prix, oui, forcement, le RPi est limité sur la qualité de ses composants : il supporte assez mal les variations de tension, y compris sur les GPIO (contrairement à Arduino), il ne pulse pas sur les ports USB, il n'y a pas d'horloge (ça se règle avec NTP), les cartes SD ne sont pas forcement de bonne qualité, ...

Notons que l'impact de la plupart des problèmes qui seront engendrés par ces manques peut être limité par des sauvegardes régulières (et, en usage serveur, la redondance contribue à limiter les dégâts quand ça casse, j'y reviendrai) comme il se doit. À titre personnel, cela fait une quarantaine de jours que mon RPi tourne sans problèmes comme serveur. Pourtant je n'ai pas d'onduleur sur cette installation, je n'ai pas investi dans une carte SD de classe internationale hors de prix et je ne crois pas à la chance.

Usages ?

Du coup, un serveur perso à la maison pour faire quoi ?

Rien d'extraordinaire :

  • un DNSd qui fait autorité sur ma zone ;
  • tout ce qu'il faut pour faire du mail (SMTPd,IMAPd,SPF,DKIM, ...) pour une seule BAL ;
  • un serveur de messagerie instantanée (XMPP/Jabber) pour un seul utilisateur ;
  • un HTTPd pour fournir quelques pages statiques (et peut-être un aggrégateur de flux RSS, donc dynamique, à voir);
  • un screen+irssi pour IRC

J'entrevois d'autres usages persos comme un dépôt git ou du partage de fichiers (autre que scp+HTTP quoi) pour, peut-être, éventuellement, un jour.

Pour ceux qui croient encore qu'il faut une machine de guerre comme pour jouer au dernier Crysis pour se faire un petit serveur pour les usages sus-cités, bah non ... un RPi c'est déjà trop : le CPU passe son temps à ne rien faire et environ 270 Mo de RAM sont utilisés sur les 496 Mo disponibles (les 16 Mo restants vont pour le GPU, j'y reviendrai). Ça donne un ordre d'idée, non ? 🙂

Les grandes lignes pour transformer son RPi en serveur

J'utilise Raspbian et un RPi modèle B.

  • Donner un mot de passe (fort, of course) au compte root (en utilisant sudo), supprimer le compte pi, créer un compte utilisateur "normal" bien à vous.
  • Affecter le minimum de mémoire au GPU : « gpu_mem=16 » dans /boot/config.txt.
  • ÉDIT du 05/05/2014 à 23h15 : Désactiver le swap dans un fichier (cat /proc/swaps). Fin de l'édit
  • Faire les mises à jour (sauf si l'installation est fraîche, of course) :
    apt-get -y update && apt-get -y upgrade &&  apt-get -y dist-upgrade && apt-get -y autoremove && apt-get -y autoclean
  • Activer IPv6 :
    echo ipv6 >> /etc/modules
  • Changer (ou pas) d'IO scheduler pour un scheduler plus adapté aux mémoires flash :
    sed -i 's/deadline/noop/g' /boot/cmdline.txt

    L'intérêt de cette manipulation fait souvent débat de ce que j'ai vu dans les forums. Je vous conseille de tester vous même car cela dépend de la carte SD. Pour moi, le résultat est sans appel :

    Avec le scheduler deadline :

    dd if=/dev/zero of=test bs=1M count=512
    512+0 enregistrements lus
    512+0 enregistrements écrits
    536870912 octets (537 MB) copiés, 91,9373 s, 5,8 MB/s
     
    rm test
     
    timeout -s2 60 dd if=/dev/zero of=test
    631065+0 enregistrements lus
    631065+0 enregistrements écrits
    323105280 octets (323 MB) copiés, 65,3899 s, 4,9 MB/s

    Avec le scheduler NOOP :

    dd if=/dev/zero of=test bs=1M count=512
    512+0 enregistrements lus
    512+0 enregistrements écrits
    536870912 octets (537 MB) copiés, 86,9908 s, 6,2 MB/s
     
    rm test
     
    timeout -s2 60 dd if=/dev/zero of=test
    732674+0 enregistrements lus
    732674+0 enregistrements écrits
    375129088 octets (375 MB) copiés, 60,4063 s, 6,2 MB/s

    De plus, j'ai un sentiment d'une meilleure réactivité du système, en cas de fortes lectures/écritures avec le scheduler noop.

  • Désinstaller l'inutile pour un serveur (gain : 575 Mo) :
    apt-get autoremove --purge gnome-* lxde-* xserver-* desktop-* midori consolekit hicolor-icon-theme leafpad vim-* aptitude aptitude-common aspell aspell-en xarchiver wpagui tsconf scratch samba-common nfs-common ppp openbox omxplayer notification-daemon network-manager netsurf-common mupdf ncdu bluez cifs-utils dictionaries-common dillo dnsmasq-base fbset galculator gksu gpicview lightdm lightdm-gtk-greeter lxappearance lxinput lxpanel lxmenu-data lxpolkit lxrandr lxsession lxsession-edit lxshortcut lxtask lxterminal obex-data-server obexd-client gtk2-engines idle idle3 penguinspuzzle triggerhappy gcc g++ gdb gdbserver libraspberrypi0 libraspberrypi-bin libraspberrypi-dev libraspberrypi-doc isc-dhcp-client alsa-base alsa-utils wireless-tools wpasupplicant xinit strace xterm blt firmware-* lksctp-tools xkb-data kbd fontconfig-config fonts-freefont-ttf ttf-freefont ttf-dejavu-core libblas3 libatlas3-base
  • Installer votre indispensable (screen/tmux, vim/nano/emacs, bash/dash/zsh, ...).
  • Installer vos logiciels serveur et les configurer avec vos réglages habituels (exemple pour SSH : mettre en place l'auth par clé, désactiver l'auth par mot de passe, désactiver le root login, ...).
  • Redémarrer le RPi pour prendre en compte certains changements (comme le split mémoire ou l'activation d'IPv6, par exemple).

Les problèmes

Un manque de neutralité

Hé oui ... À mon grand regret, je suis chez un Fournisseur d'Accès à son Intranet au lieu d'être chez un Fournisseur d'accès à Internet. Du coup, j'ai une addresse IPv4 publique, pas d'IPv6, pas d'IP fixe, des ports bloqués en sortie (notamment le 25, néccessaire pour monter un serveur mail) et, cerise sur le gateau, les connexions entrantes (pour ceux qui parle l'iptables : état NEW) sont interdites, seules les réponses à une demande interne (RELATED,ESTABLISHED) sont autorisées ... Le top du top pour s'auto-héberger quoi. :@

Il n'y a pas 36 façons de résoudre ce problème : soutenir les FAI associatifs et prendre un VPN chez l'un d'eux (à l'heure actuelle, à ma connaissance, seul FDN et Tetaneutral.net ont un tel service, c'est aussi en projet chez ARN et Franciliens.net). Pour l'instant, mon choix s'est porté sur un VPN FDN.

Les démons UDP et l'effet VPN

Au boot, BIND et NTPd seront lancés avant que le VPN ne soit initialisé. L'interface tun sera donc montée et adressée bien après le lancement des démons. Pour une raison qui m'échappe, alors que j'ai demandé à ces deux démons d'écouter sur n'importe quelle interface, cela ne marche pas et ils n'écoutent pas sur l'interface tun quand elle devient up. Pourtant, tous les démons basés exclusivement sur TCP (nginx, sshd, postfix, dovecot, ...) fonctionnent très bien avec ce VPN.

Symptômes : NTPd ne se connecte pas aux serveurs de temps externes. BIND n'accepte aucune connexion, udp ou tcp, en v4 ... mais répond parfaitement en v6, udp comme tcp.

Oui, vous pouvez modifier l'ordre de démarrage des différents démons pour les faire passer après OpenVPN mais ça ne fonctionnera probablement pas : c'est une histoire de timing ... Si OpenVPN arrive à monter le tunnel avant que les démons soient lancés, c'est bon, sinon non.

Oui, vous pouvez demander à OpenVPN d'exécuter un script à la fin de la mise en place du tunnel pour relancer BIND et NTPd mais je trouve ça assez bof ... Pour BIND, ce n'est pas trop dérangeant (un notify sera simplement envoyé aux secondaires, rien de méchant donc) mais un restart de NTPd lui fait recommencer tout son algorithme d'obtention du temps à partir de 0, au risque de surcharger les serveurs sur lesquels vous vous synchronisez (surtout moi et mes déconnexions forcées régulières (toutes les 6H ...) ...)

Notez que l'option « persist-tun » d'OpenVPN n'est pas destinée à cet usage mais sert à ne pas détruire la tun lors d'un ping-restart.

Je résous le problème de deux manières différentes, une pour chaque démon.

BIND

BIND dispose d'une directive de configuration, « interface-interval », qui permet de rafraîchir la liste des interfaces toutes les <interface-interval> minutes. Par défaut, BIND actualise la liste des interfaces toutes les 60 minutes. Je configure cette option à 1 (dans named.conf.options, classique). Cela veut dire qu'au boot, BIND découvrira la tun au maximum 1 minute après qu'OpenVPN ait monté le tunnel.

NTPd

NTPd dispose lui aussi d'une option « -U X » qui permet de donner un intervalle, en secondes cette fois-ci, entre deux rafraichissements de la liste des interfaces. Par défaut, c'est 5 minutes. Mais ce n'est pas l'option qui convient ici et ce, pour deux raisons :

  1. D'abord car un délai insuffisant signifie qu'à chaque deconnexion, NTPd actualisera la liste des interfaces ... et recommencera donc son algorithme d'obtention du temps à 0. Un délai trop long et il mettra beaucoup de temps à configurer l'horloge au boot alors que c'est là que nous en avons le plus besoin (le RPi n'ayant pas d'horloge hardware).
  2. Ensuite car j'ai constaté que la désactivation de cette option fait que NTPd répond en v6. Avec cette option activée, il écoute bien mais ne répond pas alors qu'il n'y a pourtant aucune directive « ignore » dans son fichier de configuration. Je n'explique pas ce phénomène mais je peux le reproduire sur deux machines qui n'ont rien en commun.

Du coup, comme je ne prévois pas de redistribuer le temps à l'extérieur de mon réseau, je n'ai pas besoin d'écouter sur l'interface du VPN. Ma solution est donc de désactiver l'actualisation de la liste des interfaces et de faire en sorte que NTPd ne sorte pas par le VPN grâce à l'ajout de routes statiques plus précises.

Pour désactiver l'actualisation règulière de la liste des interfaces, il suffit d'ajouter « -U 0 » dans la variable « NTPD_OPTS » dans /etc/default/ntp.

Pour les routes, il suffit de les faire ajouter par OpenVPN, c'est le plus simple et le plus cohérent, selon moi. Cela se fait donc dans le fichier de configuration de votre VPN. Exemple :

# Pour NTPd
route 145.238.203.14 255.255.255.255 <IP_GATEWAY_DE_VOTRE_RÉSEAU>
route 192.93.2.20 255.255.255.255  <IP_GATEWAY_DE_VOTRE_RÉSEAU>

Raccourcir le chemin

Comme votre serveur est derrière un VPN, cela veut dire que, depuis votre réseau local, vos requêtes vers votre serveur sortiront par Internet jusqu'à votre fournisseur VPN puis remonterons votre VPN pour atteindre votre serveur. Même chose au retour. Ce n'est pas top ... Vu que le serveur est sur le même réseau privé (ou dans une DMZ), autant ne pas sortir de ce réseau.

On peut utiliser le fichier hosts. Exemple : 192.168.1.42 serveur.mondomaine.example

On peut ajouter une route. Exemple : ip r a <IP VPN>/32 via 192.168.1.42 dev eth0

La première méthode est plus pratique. Mais si vous avez des laptop ? Vous voudrez sans doute une configuration qui marche autant chez vous qu'à l'extérieur de votre réseau personnel. Il suffit de jouer avec iptables sur la passerelle de votre réseau. Exemple :

# Quand un PC du réseau local veut s'adresser à l'IP VPN, on le redirige vers l'ip locale et privée du RPi
iptables -t nat -A PREROUTING -i eth1 -s 192.168.1.0/24 -d <IP_VPN>/32 -j DNAT --to-destination 192.168.1.42

# Pour que la redirection précédente fonctionne, il faut aussi remplacer l'IP source par celle de la gateway
iptables -t nat -A POSTROUTING -o eth1 -s 192.168.1.0/24 -d 192.168.1.42/32 -j SNAT --to-source 192.168.1.254

# Optionnel : léger contrôle ...
iptables -t filter -A FORWARD -i eth1 -o eth1 -s 192.168.1.0/24 -d 192.168.1.42/32 -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT
iptables -t filter -A FORWARD -i eth1 -o eth1 -s 192.168.1.42/32 -d 192.168.1.0/24 -m state --state RELATED,ESTABLISHED -j ACCEPT

OpenDNSSEC/SoftHSM

Le package softhsm présent dans les dépôts segfault lors de son l'initialisation (SO PIN, USER PIN, segfault). En compilant une version plus récente, j'arrive à configurer SoftHSM et OpenDNSSEC mais ce dernier ne signe pas ma zone car il rencontre une erreur :

[adapter] error parsing RR at line 17 (Syntax error, could not parse the RR): �������������������������������������������������������������������������� [je coupe ici mais y'en a encore un bon paquet]

La ligne 17 ne contient rien de spécial si ce n'est que c'est la fin du fichier de zone ... Ce fichier de zone peut être signé par une autre installation d'OpenDNSSEC (sur une architecture amd64) donc il n'est pas en cause. Même en compilant la dernière version, avec les dernières lib, ça ne juste marche pas. Je ne sais pas comment résoudre ce problème. C'est donc une autre machine qui signe ma zone et la transfère à mon RPi pour que ce dernier la serve à tous les Internets.

Prolongements (aka ce qu'il reste à faire)

  • Mettre en place un minimum de redondance : une autre machine, quelque part, avec les mêmes services, pour combler les éventuelles pannes de la première. Je sais que les principaux services sont résistants aux pannes (queue de mails pendant quelques jours si bien configuré, TTL dans le DNS, ...) mais quid des serveurs mal-configurés (il faut s'adapter à la diversité d'Internet), des pannes longues (déménagement, panne hardware sérieuse, panne locale des réseaux (électrique, boucle locale, réseau de votre FAI, ... )) ? Les pannes longues et sérieuses, ça n'arrive pas qu'aux autres. Et puis, c'est intéressant à creuser.
  • Mettre en place un peu plus de sécurité. Le chiffrement de la carte SD me tente pas mal. 😀
  • Comme tout cela n'est pas simple à mettre en place et encore moins à maintenir dans la durée pour tout un chacun, malgré les solutions clé en main (comme Yunohost), qu'il faut bien évidemment continuer d'encourager, il convient aussi de monter des associations locales à taille humaine pour proposer de l'hébergement en communauté. Comme on fait des FAI associatifs quoi. Oui, je sais qu'il en existe déjà un certain nombre mais plus c'est mieux et surtout il faudrait peut-être proposer des VM ?

Reproche

Je n'ai qu'un reproche majeur à faire à la Raspberry Fondation (en plus du blob propriétaire et de la tentative de faire croire qu'il est passé sous licence libre, bien sûr 😛 ) : pourquoi avoir foutu des LED qui pulsent autant et pourquoi on ne peut pas les contrôler de manière logicielle comme sur un WRT54GL ?! Illuminer la moitié d'une pièce avec une carte discrète par sa taille c'est vraiment super ...

Sources