Blog

Auto-hébergement : initiation et pérégrinations

Jan. 20, 2020

L'[auto-hébergement]() me permet de répondre à trois demandes, à savoir, mes préoccupations concernant mes données personnelles, ma curiosité technologique et le temps à perdre. Je synthétise ici mon expérience, résultat de deux ans d'essais et découvertes, à l'attention de nouveaux amateurs. # Matériel Je fis mes premières armes sur des machines d'[Amazon EC2](https://en.wikipedia.org/wiki/Amazon_Elastic_Compute_Cloud), disposant de crédits pour ce faire. Cependant, ces solutions conviennent davantage à des professionnels, tant dans les moyens mis à disposition que dans les propositions commerciales. En outre, la recherche d'indépendance étant au cœur de ma démarche vers l'auto-hébergement, la dépendance à Amazon restait inconfortable. Je résiliai donc et cherchai autre chose. La première pierre ajoutée à l'édifice fut une carte [Raspberry Pi 3](https://www.raspberrypi.org/). La coquetterie accompagnera cet achat d'un boîtier muni d'un ventilateur. En ajoutant une carte mémoire de 64 Go, cet investissement me coûta 73,06 €. ![Raspberry Pi avec un boîtier comporant un ventilateur](https://i.imgur.com/94gpXki.png) Une fois le colis arrivé, le premier objectif fut de pouvoir se connecter en SSH à la carte. La [documentation](https://projects.raspberrypi.org/en/projects/raspberry-pi-setting-up) officielle de la carte permet cela aisément. Par sécurité, il convient de modifier le nom d'utilisateur (`pi` par défaut), associé à un mot de passe robuste. Rapidement, les premiers problèmes survinrent. En l'occurrence, il s'agit de la connexion à un [serveur NTP / NTS](https://fr.wikipedia.org/wiki/Network_Time_Protocol), pour paramétrer automatiquement et précisément l'heure et la date de la carte. Le symptôme le plus critique était l'impossibilité d'établir des connexions sécurisées, le [protocole SSL](https://fr.wikipedia.org/wiki/Transport_Layer_Security) reposant sur des concordances temporelles. Trouver la solution se révéla être un défi de taille, qui se conclut par un contournement trouvé sur [Stack Overflow](https://stackoverflow.com/) : ``` sudo date -s "$(wget -qSO- --max-redirect=0 google.com 2>&1 | grep Date: | cut -d' ' -f5-8)Z" ``` Une fois ces désagréments réglés, et quelques logiciels basiques installés, les choses sérieuses commencèrent. # Site Internet ## Infrastructure serveur Ma première page personnelle était hébergée statiquement sur un serveur de [ByetHost](https://byet.host/) (qui offrait en outre un accès à un serveur FTP personnel), puis sur le service [Pages](https://pages.github.com/) de [GitHub](https://github.com/). Aller plus loin nécessitait alors une architecture dynamique, que j'esquissai en [PHP](https://www.php.net/manual/fr/intro-whatis.php). Assez vite le besoin d'une structure logicielle se fit sentir, tant pour la propreté du code que pour les performances et la sécurité. Je connaissais alors [Laravel](https://laravel.com/), basé sur PHP, mais préférai utiliser [Django](https://www.djangoproject.com/), basé sur Python. Django s'intègre aussi très facilement à un serveur [Apache](https://httpd.apache.org/). La plupart des tutoriels disponibles proposent de configurer directement le fichier `apache2.conf`, mais il est possible d'inclure le serveur Django dans un VirtualHost. Les directives à renseigner sont les suivantes : - `WSGIScriptAlias` - `WSGIDaemonProcess` - `WSGIProcessGroup` Outre l'élégance apportée, cela permet aussi de filtrer les requêtes ayant accès au serveur par nom de domaine et les port, ce qui permet la coexistence de plusieurs services. Un dernier avantage de Django est sa modularité. Le serveur fonctionne comme un regroupement d'applications, qu'il est facile d'installer et de désinstaller. **Remarque :** la migration vers Django 3.0.2 nécessite une version de Python supérieure à 3.6, or le module WSGI, qui permet la jonction entre Django et Apache, ne possède qu'un paquet pour Python 3.5 (`libapache2-mod-wsgi-py3`). La solution consiste à compiler manuellement WSGI, comme l'indiquent ces tutoriels : - [Serve Python 3.7 with `mod_wsgi` on Ubuntu 16](https://medium.com/@garethbjohnson/serve-python-3-7-with-mod-wsgi-on-ubuntu-16-d9c7ab79e03a) - [Quick Installation Guide — mod_wsgi 4.7.0 documentation](https://modwsgi.readthedocs.io/en/develop/user-guides/quick-installation-guide.html) ## Certification La sécurisation du site via le protocole SSL nécessitait premièrement un nom de domaine. J'achetai donc `chalier.fr` sur [Amazon Route 53](https://aws.amazon.com/fr/route53/). Deuxièmement, il me fallait des certificats signés par une autorité de confiance. ~~[SSL For Free](https://www.sslforfree.com/) propose ce service gratuitement et efficacement.~~ __Mise à jour : SSL For Free est désormais détenu par [ZeroSSL](https://zerossl.com/), réduisant grandement les fonctionnalités accessibles gratuitement, notamment la possibilité de certifier une *wildcard* (enregistrement DNS de la forme `*.domaine.tld`, représentant tous les sous-domaines). De plus, j'ai pu remarquer que la certification offerte était en réalité l'oeuvre de [Let's Encrypt](https://letsencrypt.org/fr/), autorité de certification de la fondation Linux, dont les services sont gratuits. J'utilise donc désormais Let's Encrypt.__ Une fois signés, les certificats sont faciles à installer avec Apache, qui peut gérer directement la redirection HTTP vers HTTPS. ## Routage Là réside une part importante de l'auto-hébergement : la mise en disponibilité du serveur sur Internet. Ma carte était connectée au réseau local, mais indisponible depuis l'extérieur. Il fallait pour cela définir des règles de **redirection de ports**, via la fonction NAT de mon routeur. Mais je rencontrai deux problèmes. Premièrement, l'attribution d'une **adresse IP locale** statique semblait dysfonctionnelle. Malgré mes nombreuses tentatives, il arrivait à ma [Livebox](https://fr.wikipedia.org/wiki/Livebox) [Orange](https://www.orange.fr/portail) de changer arbitrairement l'adresse de ma carte Raspberry Pi sur le réseau local. Résoudre le problème nécessita un script Bash vérifiant périodiquement si l'adresse IP locale avait changé ; le cas échéant, une commande permet d'envoyer une requête pour demander de nouveau l'adresse précédente : ``` sudo ifconfig eth0 192.168.1.7 netmask 255.255.255.0 ``` Deuxièmement, l'**adresse IP publique** de la Livebox était fréquemment modifiée par Orange, de sorte que le champ A du DNS ne pouvait pas suivre. Orange vend un service de [DNS dynamique](https://fr.wikipedia.org/wiki/DNS_dynamique), mais il est possible de se débrouiller sans. Encore une fois, grâce à un script Bash vérifiant périodiquement si l'adresse IP publique avait changé ; le cas échéant, l'[interface de ligne de commande AWS](https://aws.amazon.com/fr/cli/) permet de mettre à jour manuellement le DNS. Dans le futur, les seules modifications du système de routage seront les ports redirigés via NAT. Les sous-domaines de `chalier.fr` , renseignés dans le DNS comme entrées CNAME redirigeant vers l'entrée principale A du domaine Apex, suivront toutes les mises à jour automatiquement. ## Sécurité Assez rapidement, des premiers faisceaux de requêtes automatiques prirent le serveur pour cible. Ces robots cherchent les routes publiques laissées ouvertes par des utilisateurs imprudents, notamment en essayant les routes communes de [WordPress](https://fr.wordpress.com/). L'installation de [Fail2ban](https://fr.wikipedia.org/wiki/Fail2ban) permet de régler ce genre de problèmes. Aussi, il est recommandé d'effectuer des sauvegardes régulières des données du serveur, idéalement automatiquement, et de stocker ces sauvegardes sur un disque distant du serveur ! # Communications L'étape suivante fut l'implémentation de services de communications. Je fis une première tentative avec NodeJs ([chrab](https://github.com/ychalier/chrab) sur GitHub), mais le résultat s'avéra manquer de fiabilité pour un usage autre que récréatif. Je me décidai donc d'installer des logiciels existants. ## Courriels Pour les courriels, je suivis un [tutoriel](https://samhobbs.co.uk/2013/12/raspberry-pi-email-server-part-1-postfix) de Sam Hobbs, accompagnant l'installation de [Postfix](http://www.postfix.org/) (serveur SMTP) et [Dovecot](https://www.dovecot.org/) (serveur IMAP). Cette installation se révéla un peu difficile, principalement par l'impossibilité d'effectuer des tests contrôlés. En outre, le port 25 n'est pas ouvrable chez Orange ([contrairement aux autres FAI](https://yunohost.org/#/isp_fr)). Il est nécessaire de relayer son serveur SMTP au [relais SMTP d'Orange](https://yunohost.org/#/isp_orange_fr). Si cela paraît compromettre la confidentialité des courriels, ces derniers ne sont pas protégés et auraient tout de même été surveillable par le FAI. La meilleure solution à ce problème est d'utiliser la norme [OpenPGP](https://fr.wikipedia.org/wiki/OpenPGP). Une fois les serveurs en place, se posa la question des clients à utiliser. J'optai pour [Thunderbird](https://www.thunderbird.net/fr/) (Windows et Linux) et [K-9 Mail](https://k9mail.github.io/) (Android). Le support d'OpenPGP nécessite l'extension [Enigmail](https://addons.thunderbird.net/fr/thunderbird/addon/enigmail/) pour le premier et l'application [OpenKeyChain](https://www.openkeychain.org/) pour le second. L'installation de client en ligne tel que [Roundcube](https://roundcube.net/) est possible mais relativement lourde pour l'usage qui en est fait. Plus modestement, le module [PHP `php-imap `](https://www.php.net/manual/fr/book.imap.php) permet d'effectuer des tâches basiques de gestion et d'affichages des messages, suffisant pour être utilisé en cas de secours. ## Internet Chat Relay Dans le milieu des communications plus informelles et rapides, le protocole [IRC](https://fr.wikipedia.org/wiki/Internet_Relay_Chat) fait partie des plus légers et personnalisables. Cela détermina mon choix. Je suivis un nouveau [tutoriel](https://pimylifeup.com/raspberry-pi-irc-server/), ouvris quelques ports supplémentaires, et le tour était joué. J'appris alors que le chat de Twitch utilisait lui-aussi le protocole IRC. Dans la lignée des Nighbot ou autres Moobot, l'envie me prit de développer un robot pour mon propre serveur. Le module [`irc`](https://python-irc.readthedocs.io/en/latest/) pour Python fournit une interface relativement bas-niveau pour l'interaction avec le serveur IRC. Je l'incorporai donc dans un service Python dont le code est disponible sur GitHub ([ircbot](https://github.com/ychalier/ircbot)). # Services Google Après la migration de ces services classiques pour l'auto-hébergement, je m'attelai à une tache peut-être moins commune. Les services de Google forment un écosystème monopolistique dont il est très difficile de se défaire, malgré le siphonnage flagrant de données qu'ils amènent. Mon objectif devint alors de me détacher au possible de ces services, pour favoriser des solutions libres de droit voire personnelles. ## Agenda et Contacts Afin de gérer la compatibilité avec un maximum de clients, il m'était nécessaire d'implémenter un protocole générique pour l'échange d'événements : [CalDAV](https://fr.wikipedia.org/wiki/CalDAV). La tâche étant de taille, j'optai pour une solution existante, [Radicale](https://radicale.org/). Implémentée en Python, elle gère les calendriers, les tâches, et les listes de contacts. ## Keep Pour la gestion de mes notes, je choisis de développer ma propre solution : [Orgapy](https://github.com/ychalier/orgapy), sous la forme d'une application Django, facile donc à incorporer au site déjà existant. Le zèle me poussa à doter cette application de fonctionnalités plus avancées que pour la simple prise de notes, par exemple le balisage du texte en [Markdown](https://fr.wikipedia.org/wiki/Markdown). ## YouTube (et Twitch) Pour ne plus dépendre de mon compte Google pour suivre mes abonnements YouTube, je développai une autre application Django : [Notifpy](https://github.com/ychalier/notifpy). Originellement, ce logiciel permettait d'être notifié lorsqu'une chaîne YouTube publiait une vidéo dont le titre satisfaisait un ensemble d'expressions régulières, ce qui permettait de filtrer le contenu de chaînes trop prolifiques, comme peuvent l'être les chaînes de revisionnage. Je l'adaptai donc pour en faire une application Django, et élargissais du même temps son champs d'utilisation. Plus tard, j'ajoutai également la gestion des utilisateurs Twitch. L'application actuelle permet ainsi de consulter un flux d'abonnement comparable à celui d'un compte YouTube sans dépendre de la plateforme, et de même pour Twitch. # Bilan et poursuites En l'état actuel de ma migration, je n'ai eu que peu de pannes à gérer, et souvent dues à des maladresses de ma part. L'expérience est très enrichissante, car elle permet de découvrir Internet comme ses pionniers l'ont imaginée, et d'en utiliser pleinement les capacités. La personnalisation complète de chaque élément intervenant dans le processus est une grande source de satisfaction. L'inconvénient majeur reste le temps à investir pour que ce projet aboutisse. Bien entendu, les choses peuvent être grandement accélérées en utilisant des services complets déjà développés, mais l'essence du projet en serait perdue. Sur ce, ma route reste longue. Les composants actuels sont toujours améliorables, et d'autres viendront certainement s'y greffer. Par exemple : - un serveur [Icecast](https://icecast.org/), pour pouvoir diffuser des playlists musicales en continu ; quelques expériences m'ont montré cela possible mais nécessitant de plus de ressources, - un serveur [GitLab](https://about.gitlab.com/), mais nécessitant aussi plus de ressources, - un serveur média, analogue à [Plex](https://www.plex.tv/fr/). Malheureusement, une simple carte Raspberry Pi ne possède pas les capacités nécessaires à ces derniers services. Par exemple, le simple hébergement de photos est difficile à gérer (j'utilise d'ailleurs [Imgur](https://imgur.com/)). Un serveur NAS serait bien plus approprié pour ces besoins, mais représente un investissement bien plus conséquent. À voir, donc.