Set-OPS-Public/roles/serveur_nginx/templates/expositions.conf.j2

90 lines
4.3 KiB
Text
Raw Normal View History

# Vhosts derives des applications (champ 'expose' de instance/plan/applications.yml,
# edge depuis instance/plan/domaines.yml) — gere par Set-OPS (role serveur_nginx).
# Ne pas editer a la main.
#
# Un FQDN expose produit un vhost si l'hote de l'application est resolvable :
# amont = http://<IP interne de l'hote de l'application>:<port>. Une exposition
# non resolvable (application sans hote actif, ou sans port) est listee mais
# NON publiee (binding declare, pas encore cablable).
{% if serveur_nginx_expositions | default([]) | selectattr('websocket', 'defined') | selectattr('websocket') | list | length > 0 %}
# Une exposition au moins est WebSocket-aware (ex. Collabora) : map d'upgrade.
map $http_upgrade $connection_upgrade { default upgrade; "" close; }
{% endif %}
{% for expo in serveur_nginx_expositions | default([]) %}
{% set ns = namespace(amont='') %}
{#- LE SCHEMA DE L'AMONT SUIT LE PORT DE L'AMONT (2026-09-15).
`http://` etait ecrit en dur. Un service qui termine DEJA le TLS — la forge, sur son
443 — recevait donc du clair sur un port qui attend une poignee de main, et rendait
`400 Bad Request`. Du TLS parfait a l'entree, une erreur de protocole a la sortie.
On ne devine pas : un amont declare sur un port de TLS se parle en TLS. La liste est
reglable (`serveur_nginx_ports_tls`) parce qu'un service peut servir du TLS ailleurs
que sur 443. -#}
{% if expo.hote in hostvars and hostvars[expo.hote].ansible_host is defined and expo.port %}
{% set _schema = 'https://' if (expo.port | int) in (serveur_nginx_ports_tls | default([443, 8443])) else 'http://' %}
{% set ns.amont = _schema ~ hostvars[expo.hote].ansible_host ~ ':' ~ expo.port %}
{% endif %}
{% if ns.amont %}
# {{ expo.fqdn }} -> application {{ expo.application }} sur {{ expo.hote }} ({{ ns.amont }})
{% if serveur_nginx_redirection_http | bool %}
server {
listen 80;
listen [::]:80;
server_name {{ expo.fqdn }};
return 301 https://$host$request_uri;
}
{% endif %}
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name {{ expo.fqdn }};
ssl_certificate {{ serveur_nginx_certificat }};
ssl_certificate_key {{ serveur_nginx_cle }};
location / {
proxy_pass {{ ns.amont }};
{% if ns.amont.startswith('https://') %}
# ON VERIFIE L'AMONT, PAS SEULEMENT LE VISITEUR. Un edge qui relaie en TLS sans
# verifier ne fait que DEPLACER la confiance : le visiteur croit l'edge, l'edge
# ne croit personne. L'AC interne est la meme des deux cotes.
proxy_ssl_verify on;
proxy_ssl_trusted_certificate {{ serveur_nginx_ca_interne }};
proxy_ssl_name {{ expo.fqdn }};
proxy_ssl_server_name on;
{% endif %}
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Tampons d'en-tetes de reponse. Le defaut de nginx (4 Ko) ne suffit PAS
# derriere une authentification OIDC : le cookie de session porte le jeton
# d'identite, decoupe en plusieurs `Set-Cookie`, et nginx repond alors 502
# « upstream sent too big header » — juste apres une authentification
# REUSSIE, ce qui rend le symptome trompeur. Constate le 2026-08-08 sur
# icinga.chezlepro.internal, ou oauth2-proxy journalisait `AuthSuccess`
# pendant que le navigateur recevait une erreur de passerelle.
#
# Pose pour TOUTES les expositions : c'est une propriete du proxy, pas du
# service, et le prochain service place derriere un IdP rencontrerait le
# meme mur.
proxy_buffer_size {{ serveur_nginx_proxy_buffer_size }};
proxy_buffers {{ serveur_nginx_proxy_buffers }};
proxy_busy_buffers_size {{ serveur_nginx_proxy_busy_buffers_size }};
{% if expo.websocket | default(false) %}
# Collabora & co : editeur en direct via WebSocket (upgrade + longue tenue).
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_read_timeout 3600s;
{% endif %}
}
}
{% else %}
# (non publie) {{ expo.fqdn }} -> application {{ expo.application }} : amont non resolvable (hote sans IP active ou sans port).
{% endif %}
{% endfor %}