J'essaie de configurer nginx en tant que proxy inverse, avec un grand nombre de serveurs principaux. Je voudrais démarrer les backends à la demande (à la première demande qui arrive), j'ai donc un processus de contrôle (contrôlé par des requêtes HTTP) qui démarre le backend en fonction de la demande qu'il reçoit.
Mon problème est de configurer nginx pour le faire. Voici ce que j'ai jusqu'à présent:
server {
listen 80;
server_name $DOMAINS;
location / {
# redirect to named location
#error_page 418 = @backend;
#return 418; # doesn't work - error_page doesn't work after redirect
try_files /nonexisting-file @backend;
}
location @backend {
proxy_pass http://$BACKEND-IP;
error_page 502 @handle_502; # Backend server down? Try to start it
}
location @handle_502 { # What to do when the backend server is not up
# Ping our control server to start the backend
proxy_pass http://127.0.0.1:82;
# Look at the status codes returned from control server
proxy_intercept_errors on;
# Fallback to error page if control server is down
error_page 502 /fatal_error.html;
# Fallback to error page if control server ran into an error
error_page 503 /fatal_error.html;
# Control server started backend successfully, retry the backend
# Let's use HTTP 451 to communicate a successful backend startup
error_page 451 @backend;
}
location = /fatal_error.html {
# Error page shown when control server is down too
root /home/nginx/www;
internal;
}
}
Cela ne fonctionne pas - nginx semble ignorer tous les codes d'état renvoyés par le serveur de contrôle. Aucune des error_page
directives de l' @handle_502
emplacement ne fonctionne et le code 451 est envoyé tel quel au client.
J'ai renoncé à essayer d'utiliser la redirection interne nginx pour cela, et j'ai essayé de modifier le serveur de contrôle pour émettre une redirection 307 vers le même emplacement (afin que le client réessaye la même demande, mais maintenant avec le serveur principal démarré). Cependant, maintenant nginx écrase bêtement le code d'état avec celui qu'il a obtenu lors de la tentative de demande de backend (502), malgré le fait que le serveur de contrôle envoie un en-tête "Location". Je l'ai finalement "fait fonctionner" en changeant la ligne error_page enerror_page 502 =307 @handle_502;
, forçant ainsi toutes les réponses du serveur de contrôle à être renvoyées au client avec un code 307. C'est très hacky et indésirable, car 1) il n'y a aucun contrôle sur ce que nginx devrait faire ensuite en fonction de la réponse du serveur de contrôle (idéalement, nous ne voulons réessayer le backend que si le serveur de contrôle signale le succès), et 2) pas tous HTTP les clients prennent en charge les redirections HTTP (par exemple, les utilisateurs curl et les applications utilisant libcurl doivent activer explicitement les redirections suivantes).
Quelle est la bonne façon de faire en sorte que nginx essaie de faire un proxy vers le serveur en amont A, puis B, puis A de nouveau (idéalement, uniquement lorsque B renvoie un code d'état spécifique)?
proxy_next_upstream
, le truc a fait l'affaire (enfin mon scénario n'était pas aussi complexe que le vôtre), je voulais juste que nginx essaie le serveur suivant si une erreur se produisait, j'ai donc dû ajouterproxy_next_upstream error timeout invalid_header non_idempotent;
(non_idempotent
, parce que je veux principalement transmettre desPOST
requêtes).Vous pouvez essayer quelque chose comme le suivant
la source
a.example.net
après avoir échoué une fois sur la même demande. Il enverra au client l'erreur rencontrée lors de la tentative de connexionb.example.net
, ce qui ne sera pas ce à quoi il s'attendait à moins que j'implémente également le proxy sur le serveur de contrôle.