Tengo un servidor nginx 1.6.2 que se ejecuta como back-end detrás de un equilibrador de carga que finaliza SSL. Toda la comunicación con los servidores de fondo se realiza a través de HTTP.
Diagrama de lo que está sucediendo:
/--http---> frontend:80 --\
client --+ +--http---> backend:8000
\--https--> frontend:443 --/
LOAD BALANCER BACKENDS
Para fines de prueba, solo tengo un back-end en este momento. El equilibrador de carga ejecuta HAProxy 1.5, sobre el que tengo cierto control.
Tengo una try_files
directiva bastante típica en mi server
bloque en la configuración de back-end nginx:
server {
server_name frontend;
...
try_files $uri $uri/ =404;
...
}
Ahora, por defecto, cuando accedo a un directorio sin una barra inclinada final, por ejemplo https://frontend/somedir
, nginx quiere enviar una redirección HTTP 301 a una URL absoluta como http://frontend:8000/somedir/
.
Puedo hacer que nginx omita el número de puerto 8000 usando port_in_redirect off
.
Sin embargo, parece que no puedo corregir el http://
esquema al comienzo de la redirección que genera nginx. ¡Lo mejor que puedo hacer con nginx es redirigir de https://frontend/somedir
a http://frontend/somedir/
, eliminando efectivamente SSL!
El equilibrador de carga está enviando un X-Forwarded-Proto
encabezado, pero no veo ninguna forma de que nginx lo consulte al diseñar su redirección; de hecho, hay una respuesta de 2012 que dice que nginx no puede hacer esto, y la solución es reemplazar el equilibrador de carga con nginx. En mi humilde opinión, esto es algo demasiado trivial para garantizar un cambio de pila tan drástico.
¿Ha cambiado algo desde 2012 aquí? Realmente no quiero reescribir estos redireccionamientos en el nivel HAProxy: los redireccionamientos HTTPS a HTTP reales intencionales desde la aplicación web podrían "re-HTTPSed" si siempre reescribo el esquema para que el Location:
encabezado de respuesta sea el mismo que el esquema la solicitud fue hecha con.
EDITAR:
Aquí hay una configuración minimizada que muestra que nginx produce Location:
URL absolutas . Tenga en cuenta que no hay reescrituras.
user nobody nobody;
worker_processes auto;
worker_rlimit_nofile 4096;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
multi_accept on;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
# TODO: Tune fastcgi_buffers/other buffers
# Configure keepalive connections
keepalive_timeout 15;
keepalive_requests 1000;
# Hide server version.
server_tokens off;
# Do not allow any directory indexes anywhere.
# This is the default, but it is here for extra paranoia.
autoindex off;
# gzip text content.
gzip on;
gzip_vary on;
gzip_disable "msie6";
gzip_comp_level 2;
gzip_min_length 1024;
gzip_types text/css
text/plain
text/xml
application/json
application/javascript;
server {
listen 8000 default_server;
root /usr/share/nginx/html;
index index.html index.htm;
server_name localhost;
location / {
try_files $uri $uri/ =404;
}
}
}
Y si usa curl para ver los encabezados, tenga en cuenta que he creado un directorio testdir
en /usr/share/nginx/html
:
[myuser@dev nginx]$ curl -i http://localhost:8000/testdir
HTTP/1.1 301 Moved Permanently
Server: nginx
Date: Thu, 26 Mar 2015 14:35:49 GMT
Content-Type: text/html
Content-Length: 178
Location: http://localhost:8000/testdir/
Connection: keep-alive
<html>
<head><title>301 Moved Permanently</title></head>
<body bgcolor="white">
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx</center>
</body>
</html>
Location:
encabezado ya que nginx no tiene idea de cuál era el protocolo original.
nginx wants to send an HTTP 301 redirect to an absolute URL
- nginx no hace eso a menos que tenga una regla de reescritura explícita para hacerlo - muestre su configuración completa.