Child pages
  • nginx
Skip to end of metadata
Go to start of metadata

Configuration

NB : contrairement à apache, en cas de dépassement

  • prévient par un "worker_connections are not enough" dans error.log
  • renvoie une réponse vide au client
  • aucune entrée dans le access log !!

proxy_pass

Préférer

proxy_pass http://xxx

sans / à la fin. Cela indique à nginx de conserver le même path. Cela fonctionne notamment dans un location avec regexp (~)

nested location

Il est possible d'avoir des location nested, mais le proxy_pass n'est pas hérité, il faut donc le répéter.

Il est possible d'utiliser if à la place, notamment pour faire des add_header. nginx vous dira si une directive est autorisé dans un if. C'est aussi indiqué dans la documentation.

compression

Par défaut seul le contenu text/html est compressé. Il est conseillé d'ajouter des gzip_types comme fait par défaut sur les apache sous debian.

Monitoring

Par défaut le monitoring nginx est très limité : module stub_status. Ce module est utilisé par /usr/local/bin/monitor-nginx .

Pour avoir les “live requests”, on peut ajouter du code lua qui le fait, cf monitor-live-requests.conf (à mettre dans /etc/nginx/conf.d/ par exemple)

Attention : cela nécessite un nginx >= 1.11 (donc debian 10 ou debian 9 avec backports)

Différences avec Apache

Limitation de la taille d'upload

Par défaut Apache limite très peu la taille d'upload, laissant le soin aux scripts de limiter.

Nginx en reverse proxy limite par défaut l'upload à 1M. Il faut l'augmenter (surtout pour des sites permettant l'upload de fichiers) :

/etc/nginx/conf.d/max_body_size.conf
client_max_body_size 150M;

Cache

Attention à proxy_cache_key :

  • contrairement à ce qu'indique la documentation, le cache ignore http vs https. D'où des pbs de mixed-content

  • si le même backend est utilisé pour plusieurs vhosts, ils vont se mélanger.

Solution à ces deux pbs, forcer une valeur proxy_cache_key plus solide :

proxy_cache_key $scheme://$host$request_uri;

Par défaut un force-reload ne fonctionne pas avec nginx (?). Solution :

proxy_cache_bypass $http_pragma;

Buffering

Par défaut nginx bufferise les requêtes et les réponses. Cela peut nécessiter de la place disque.


Pour voir ces fichiers temporaires , on peut utiliser :

find /proc/[0-9]*/fd -lname '*(deleted)' 2>/dev/null | perl -lne 'print -s, " $_ $l", readlink'  | sort -g

Buffering des réponses

Bufferiser les réponses est utile quand le client est lent : le backend donne la réponse entière et peut passer à autre chose (utile notamment pour des backend apache-prefork ou PHP-FPM gourmand en mémoire).

Si la réponse est trop grosse pour être bufferisée en mémoire la réponse est stockée dans un fichier temporaire. Son emplacement est défini à la compilation sur debian

% nginx -V 2>&1 | perl -lne 'print $& while /--(\S+)/g' | grep proxy-temp-path
--http-proxy-temp-path=/var/lib/nginx/proxy

Si la réponse est vraiment grosse, nginx ne bufferise que le début. Par défaut nginx bufferise les réponses jusqu'à 1G. Il est possible de réduire la taille via proxy_max_temp_file_size.

Il est aussi possible de désactiver le buffering complètement avec proxy_buffering off mais attention, cela désactive aussi la fonctionnalité proxy_cache

Gros fichiers et timeout backend

Le frontal nginx va bufferiser d'un coup proxy_max_temp_file_size puis demander le reste au fur et a mesure. Réf

Il faut que le timeout du backend soit supérieur au temps que met le client à télécharger ces premiers proxy_max_temp_file_size, sinon le backend va abandonner et on verra l'erreur upstream prematurely closed connection while reading upstream dans le error log de nginx.

Par exemple, si on veut autoriser un téléchargement en modem 56kbps et que proxy_max_temp_file_size est 30MB, il faut un Timeout / send_timeout backend de 2h.

Upload buffering

Si la requête est plus grosse que client_body_buffer_size la requête est stockée dans un fichier temporaire. Son emplacement est défini à la compilation sur debian

% nginx -V 2>&1 | perl -lne 'print $& while /--(\S+)/g' | grep client-body-temp-path
--http-client-body-temp-path=/var/lib/nginx/body

Si nginx est utilisé en reverse proxy sans load balancing, on peut désactiver cette fonctionnalité :

proxy_request_buffering off;
proxy_http_version 1.1;

Content-Type par défaut

Apache accepte de ne pas renvoyer de Content-Type. Nginx va forcer un Content-Type par défaut, souvent application/octet-stream ce qui va indiquer au navigateur de sauvegarder un fichier plutôt que d'afficher une page Web par exemple.

backends et IPv4/IPv6

  • apache : il semble qu'il préfère l'IPv6 du serveur backend (cf apr_sockaddr_info_get qui utilise getaddrinfo et donc RFC 3484 puis ap_proxy_connect_backend qui va prendre le premier qui fonctionne)

  • nginx : utilise IPv4 ou IPv6 en alternance (cf ngx_http_upstream_init_round_robin qui utilise ngx_inet_resolve_host)

Certaines applications (comme typo3) n'apprécient pas ce changement d'IP. Solution pour typo3 en backend apache+mod-php : configurer remote_ip… en espérant que le client ne mixe pas les requêtes IPv4 et IPv6 (cf Happy eyeballs) !!

TLS session tickets

Par défaut, nginx n'a pas de cache de TLS session tickets. Il faut l'activer avec ssl_session_cache.

Shibboleth-SP

Shibboleth-SP fournit un FastCGI authorizer. Nginx ne gère pas cela en standard.

Le module nginx-http-shibboleth fournit cette fonctionnalité. Mais ce module n'est pas packagé en standard dans les distributions Linux.

Voici une solution alternative, testée sur moodle. NB : cette solution est coûteuse si l'application ne gère pas sa propre session (par exemple une appli qui protège toutes les urls avec shib).

Explication

Fonctionnement classique avec Apache et module shib2Nginx renvoie les requêtes protégées par SAML vers Apache

(diagrammes de séquences réalisés avec plantuml et les fichiers apache-shib-simple.puml et nginx-shib-proxy.puml)

Configuration sur le nginx

set $shib_backend '172.0.0.42';

location /Shibboleth.sso {
    proxy_pass http://$shib_backend;
    proxy_set_header Host $http_host;
}

location ~ [^/]\.php(/|$) {
    set $uri_to_shib $uri;
    if ($remote_addr = $shib_backend) {
        set $uri_to_shib '';
    }
    if ($uri_to_shib = "/auth/shibboleth/index.php") {
        proxy_pass http://$shib_backend;
    }
    proxy_set_header Host $http_host; # preserve host when going to shib backend

    fastcgi_split_path_info  ^(.+\.php)(/.+)$;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_param PATH_INFO $fastcgi_path_info;
    include fastcgi_params;

    fastcgi_pass unix:/run/php/moodle-fpm.sock;
    fastcgi_index index.php;
}

Configuration sur le apache/mod_shib

Configurer normalement shibboleth, et relayer les requêtes vers le nginx :

    ProxyPass / https://le_nginx/
    ProxyPreserveHost On
    ShibUseHeaders On


  • No labels