Derrière un proxy
Faites pointer votre proxy vers le WEB_PORT publié et laissez-lui la terminaison HTTPS. Il faut
alors ajuster deux variables dans .env, puis redémarrer la pile : PUBLIC_URL, l’adresse publique
sous laquelle vous servez l’application, et COOKIE_SECURE=true, qui réserve le cookie de session à
HTTPS.
L’adresse en amont
Section intitulée « L’adresse en amont »L’amont dépend de l’endroit où tourne le proxy.
Le port publié se joint à 127.0.0.1:8080. Avec BIND_ADDRESS=127.0.0.1, c’est la seule
adresse où il écoute, et ce réglage ferme l’instance à tout ce qui n’est pas le proxy.
Un proxy en conteneur a sa propre boucle locale : 127.0.0.1 n’y mène à rien, chaque requête
reçoit une 502 et le journal du proxy affiche connect() failed (111: Connection refused).
Branchez plutôt le conteneur sur le réseau de la pile et joignez l’application par son nom :
docker network connect badlen_default my-proxy # avant de le démarrerL’amont devient alors
http://app:3001. Branchez le conteneur avant de le démarrer : nginx ne résout le nom d’un amont qu’une fois, au démarrage, et s’arrête sur host not found in upstream "app" s’il n’est pas encore sur le réseau. Dans ce cas, rien n’a besoin
d’être publié sur l’hôte.
Relever la taille du corps
Section intitulée « Relever la taille du corps »L’application accepte des requêtes jusqu’à 25 Mo : c’est la taille que peut atteindre l’export JSON
d’une instance bien remplie, qu’il faut pouvoir réimporter. nginx s’arrête par défaut à 1 Mo et
répond au-delà par sa propre page 413 Request Entity Too Large. La requête n’arrive jamais jusqu’à
Badlen, et le journal de l’application n’en garde donc aucune trace. Ajoutez
client_max_body_size 25m; dans le bloc location du proxy pour aligner les deux limites.
Servir HTTP/2
Section intitulée « Servir HTTP/2 »Le serveur de Badlen ne parle que HTTP/1.1, et en HTTP/1.1 un navigateur ne télécharge que six fichiers à la fois. Le premier écran en compte deux douzaines : ils arrivent donc par vagues, et chaque vague paie le délai du réseau. Un proxy qui sert HTTP/2 les envoie tous ensemble. Mesuré sur la Synthèse, depuis un téléphone en 4G lente : le premier affichage arrive à 3,6 s au lieu de 5,7 s, et l’écran est complet à 8,4 s au lieu de 13,5 s.
Pour nginx, ajoutez http2 on; dans le bloc server qui écoute sur le port 443
(listen 443 ssl http2; avant nginx 1.25.1). Caddy sert HTTP/2 par défaut. Un accès direct au port
publié reste en HTTP/1.1 : le gain ne vaut qu’à travers le proxy.
Dire à l’application combien de proxies sont devant
Section intitulée « Dire à l’application combien de proxies sont devant »Derrière un proxy, toutes les requêtes semblent venir du proxy, et deux fonctions lisent l’adresse d’origine d’une requête. Les limites de débit se comptent par adresse : la limite de dix tentatives par minute sur les routes qui vérifient un mot de passe s’applique alors au foyer entier, et une personne qui se trompe deux fois bloque tous les autres. Par ailleurs, Réglages → Sécurité affiche chaque session avec l’adresse depuis laquelle elle a été ouverte : tous les appareils de la maison y apparaissent avec la même.
TRUSTED_PROXY_HOPS=1 rend aux deux la bonne adresse. La valeur est de un pour un seul nginx ou
Caddy, plus un pour chaque proxy supplémentaire à vous placé derrière. Elle se lit comme un décompte
depuis la fin de l’en-tête X-Forwarded-For, car chaque proxy y ajoute l’adresse dont il a reçu la
requête : avec un seul proxy devant, la dernière adresse de cet en-tête est celle qu’il a écrite. Un
client qui fabrique son propre en-tête ne fait que repousser son invention vers la gauche ; c’est
pour cela que le décompte vient de vous, et non de l’en-tête.
Trop bas, c’est le proxy extérieur qui est compté. Trop haut, le décompte dépasserait vos proxies et
irait lire la partie de la chaîne écrite par le client. La valeur seule ne suffit donc pas. Avec un
seul proxy, rien de plus n’est nécessaire : l’application lit l’adresse qu’il a écrite. Avec deux ou
plus, nommez les proxies placés derrière le premier dans TRUSTED_PROXY_ADDRESSES, par adresse ou
par plage CIDR, séparées par des virgules (TRUSTED_PROXY_ADDRESSES=172.18.0.0/16) : chaque saut
entre l’adresse lue et l’application doit en faire partie. Être sur un réseau privé ne suffit pas,
puisqu’un client de la maison a lui aussi une adresse privée. Si le décompte va au-delà des proxies
nommés, ou au-delà de la longueur de l’en-tête, l’application revient à l’adresse de connexion et le
signale dans le journal, une fois par minute :
docker compose logs app | grep TRUSTED_PROXY_HOPSLa boucle de connexion
Section intitulée « La boucle de connexion »COOKIE_SECURE=true est le seul réglage qui puisse vous renvoyer sans fin à la page de connexion.
Le navigateur conserve un cookie ainsi marqué sur une origine HTTPS et le jette sur une origine en
clair, sauf localhost. Si vous joignez la même instance directement à http://<lan-ip>:8080 avec
ce réglage actif, vous êtes connecté puis aussitôt déconnecté : la connexion répond 201,
l’application s’ouvre, la première navigation vous ramène à la page de connexion, et rien n’indique
pourquoi. Passez par le proxy, ou réglez COOKIE_SECURE=false tant qu’aucun HTTPS n’est en place.
Dernier point, que le navigateur tranche seul : avec un certificat auquel il ne fait pas confiance, auto-signé compris, vous perdez l’application installable. Le navigateur refuse d’enregistrer le service worker et affiche une erreur SSL dans la console. L’interface et les données n’en souffrent pas.