Estoy tratando de configurar nginx como proxy inverso, con una gran cantidad de servidores de fondo. Me gustaría iniciar los backends a pedido (en la primera solicitud que llega), por lo que tengo un proceso de control (controlado por solicitudes HTTP) que inicia el backend dependiendo de la solicitud que reciba.
Mi problema es configurar nginx para hacerlo. Esto es lo que tengo hasta ahora:
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;
}
}
Esto no funciona: nginx parece ignorar los códigos de estado devueltos por el servidor de control. Ninguna de las error_page
directivas de la @handle_502
ubicación funciona, y el código 451 se envía tal cual al cliente.
Dejé de intentar usar la redirección interna de nginx para esto, e intenté modificar el servidor de control para emitir una redirección 307 a la misma ubicación (para que el cliente vuelva a intentar la misma solicitud, pero ahora con el servidor de fondo iniciado). Sin embargo, ahora nginx está sobrescribiendo estúpidamente el código de estado con el que obtuvo del intento de solicitud de fondo (502), a pesar de que el servidor de control está enviando un encabezado de "Ubicación". Finalmente lo conseguí "trabajando" cambiando la línea error_page aerror_page 502 =307 @handle_502;
, lo que obliga a que todas las respuestas del servidor de control se envíen de vuelta al cliente con un código 307. Esto es muy hacky e indeseable, porque 1) no hay control sobre lo que nginx debe hacer a continuación dependiendo de la respuesta del servidor de control (idealmente solo queremos volver a intentar el backend solo si el servidor de control informa de éxito), y 2) no todo HTTP los clientes admiten redireccionamientos HTTP (por ejemplo, los usuarios curl y las aplicaciones que usan libcurl deben habilitar los siguientes redireccionamientos explícitamente).
¿Cuál es la forma correcta de hacer que nginx intente proxy al servidor ascendente A, luego B, luego A nuevamente (idealmente, solo cuando B devuelve un código de estado específico)?
proxy_next_upstream
hice el truco (bueno, mi escenario no era tan complejo como el tuyo), solo quería que nginx probara el siguiente servidor si ocurriera un error, por lo que tuve que agregarproxy_next_upstream error timeout invalid_header non_idempotent;
(non_idempotent
porque quiero enviar principalmentePOST
solicitudes).