Estou tentando configurar o nginx como um proxy reverso, com um grande número de servidores back-end. Eu gostaria de iniciar os back-end sob demanda (na primeira solicitação que entra), para ter um processo de controle (controlado por solicitações HTTP) que inicia o back-end, dependendo da solicitação que recebe.
Meu problema é configurar o nginx para fazer isso. Aqui está o que eu tenho até agora:
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;
}
}
Isso não funciona - o nginx parece ignorar qualquer código de status retornado do servidor de controle. Nenhuma das error_page
diretivas no @handle_502
local funciona e o código 451 é enviado como está para o cliente.
Desisti de tentar usar o redirecionamento nginx interno para isso e tentei modificar o servidor de controle para emitir um redirecionamento 307 para o mesmo local (para que o cliente tentasse novamente a mesma solicitação, mas agora com o servidor back-end iniciado). No entanto, agora o nginx está substituindo estupidamente o código de status pelo código obtido na tentativa de solicitação de back-end (502), apesar de o servidor de controle estar enviando um cabeçalho "Local". Finalmente consegui "mudar" a linha error_page paraerror_page 502 =307 @handle_502;
, forçando assim todas as respostas do servidor de controle a serem enviadas de volta ao cliente com um código 307. Isso é muito hacky e indesejável, porque 1) não há controle sobre o que o nginx deve fazer a seguir, dependendo da resposta do servidor de controle (idealmente, queremos apenas tentar novamente o back-end somente se o servidor de controle relatar êxito) e 2) nem todo o HTTP os clientes suportam redirecionamentos HTTP (por exemplo, usuários curl e aplicativos que usam libcurl precisam ativar explicitamente os seguintes redirecionamentos).
Qual é a maneira correta de fazer com que o nginx tente proxy para o servidor upstream A, depois B e A novamente (idealmente, apenas quando B retornar um código de status específico)?
proxy_next_upstream
, o truque (bem, meu cenário não era tão complexo quanto o seu), eu só queria que o nginx tentasse o próximo servidor se ocorresse um erro; portanto, tive que adicionarproxy_next_upstream error timeout invalid_header non_idempotent;
(non_idempotent
porque eu quero encaminhar principalmentePOST
solicitações).