Un tunnel low cost
Besoin de tunnel
La dernière mode chez les développeurs, c’est d’exposer publiquement son environnement local, généralement une application web en cours d’écriture. De mon côté, il m’a été demandé de travailler sur un système de paiement dont la configuration nécessitait que ma machine de développement soit accessible au service de paiement.
Il m’a été proposé d’utiliser les tunnels Cloudflare, ou bien d’installer ngrok. Mais ces deux solutions, ainsi que leurs multiples alternatives, me semblaient «/overkill/» pour mon simple besoin. J’ai donc préféré m’amuser à implémenter une solution plus modeste et sur mesure, que je vais présenter ci-après.
Solution maison
Je contrôle déjà un serveur web qui est accessible publiquement sur internet. C’est le serveur web qui héberge le
blog sur lequel vous êtes certainement en train de lire cet article. Mon objectif va être d’utiliser ce serveur comme
proxy web sur un nom de domaine dédié, qui transmettra toutes les requêtes vers mon serveur de développement, qui lui
tournera sur mon portable dans des containers configurés avec docker-compose
.
Configuration DNS
La première étape consiste donc à faire pointer le nom de domaine sous lequel on veut rendre accessible notre environnement de développement vers ce serveur.
Par convention je vais utiliser les noms suivants:
-
my-web-server.net
: le nom de domaine de mon serveur web public; -
dev1.devs.my-web-server.net
: le nom de domaine sous lequel l’environnement de développement sera accessible.
L’enregistrement DNS à créer ressemblera à quelque chose comme: *.devs.my-web-server.net CNAME
my-web-server.net
Configuration Caddy
Mon serveur web utilise Caddy. Ici je vais utiliser deux fonctionnalités de cet outil particulièrement pratiques:
- en déclarant un nom de domaine ouvert sur le port
443
, Caddy récupère automatiquement le certificat Letsencrypt! - Un reverse proxy se configure en une seule ligne.
La section de ma configuration Caddy dédiée au tunnel ressemble à ceci:
dev1.devs.my-web-server.net:80, dev1.devs.my-web-server.net:443 { log { output file /var/log/caddy/dev1-devs.log } reverse_proxy { to 127.0.0.1:8888 } }
Configuration Docker avec le certificat
Lorsque mon application web sera accessible depuis l’extérieur, Caddy va utiliser le certificat généré par Letsencrypt pour sécuriser la connexion. Mais lorsque j’accède à cette même application en local depuis mon portable, c’est au serveur web qui tourne dans Docker de s’en occuper. Pour cela ce serveur a aussi besoin des fichiers du certificat.
Ces fichiers (la clé publique et la clé privée) se trouvent dans le sous répertoire
dev1.devs.my-web-server.net
du répertoire
/var/lib/caddy/.local/share/caddy/certificates/acme-v02.api.letsencrypt.org-directory/
Il faut les copier
en local, puis les insérer dans le container qui fera tourner le serveur web.
Dans le Dockerfile
du serveur web on trouvera donc quelque chose qui ressemble à:
COPY certs/dev1.devs.my-web-server.net.crt /usr/local/apache2/conf/dev1.devs.my-web-server.net.crt COPY certs/dev1.devs.my-web-server.net.key /usr/local/apache2/conf/dev1.devs.my-web-server.net.key
Dans mon cas particulier l’application en local est servie par un serveur apache. La configuration de ce serveur ressemble à ceci:
<VirtualHost _default_:443> DocumentRoot "/var/www/my-app/" ServerName dev1.devs.my-web-server.net SSLEngine on <Directory "/var/www/my-app/"> AllowOverride All Require all granted </Directory> SSLCertificateFile "/usr/local/apache2/conf/dev1.devs.my-web-server.net.crt" SSLCertificateKeyFile "/usr/local/apache2/conf/dev1.devs.my-web-server.net.key" Protocols h2 http/1.1 </VirtualHost>
Modification du fichier /etc/hosts
Pour pouvoir travailler localement, sans passer par le proxy, il faut associer l’adresse IP du container apache au
nom de domaine dev1.devs.my-web-server.net
. On récupère cette adresse avec la commande suivante:
docker inspect \ --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' \ $(docker compose ps -q apache)
Connexion ssh
La dernière étape consiste à créer le tunnel, avec SSH, entre notre machine locale et le serveur web:
ssh -R 8888:127.0.0.1:8351 my-web-server.net
Ici on a:
-
8351
le port ouvert de notre serveur web dans votre docker-compose; -
8888
le port qui est dans la configuration reverse proxy de Caddy.
Et voilà!
Aller plus loin
Il ne semble pas trop difficile de bricoler une solution qui automatise un peu toutes ces étapes. D’ailleurs c’est
pour cela que j’ai déclaré le domaine *.devs.my-web-server.net
dans ma configuration dns, au lieu de
dev1.my-web-server.net
. Ainsi je peux ajouter plus facilement d’autres domaines sans modifier mon serveur
DNS. Je n’aurais ensuite que les modifications de la configuration Caddy et de docker à programmer. Pour le moment, avec
un seul environnement à rendre accessible, je n‘ai pas besoin d’automatiser plus.
Post Scriptum
Après avoir écrit cet article, je découvre un projet qui met en œuvre exactement le même procédé que moi, avec un début d’automatisation.