¿Cómo utilizar nginx como proxy inverso con múltiples IP y SSL?

¿Cómo utilizar nginx como proxy inverso con múltiples IP y SSL?

Me gustaría configurar el proxy inverso nginx con múltiples dominios y una IP para que cada uno de ellos use diferentes certificados SSL. Ejecuto Ubuntu como sistema operativo que está instalado en una máquina virtual KVM/Qemu.

Según tengo entendido, nginx debería poder servir un dominio (y los subdominios que le pertenecen) a través de una IP. Pero no consigo que se ejecute...

Esa es mi configuración de nginx:

/etc/nginx/sites-enabled/mi_primer_dominio

server {
  listen x.x.x.84:80;                                   # this is a public ip
  server_name firstdomain.com;

  access_log /var/log/nginx/access.log proxy;     # I made my own logformat
  error_log  /var/log/nginx/error.log;

  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header Client-IP $remote_addr;
  proxy_set_header X-Host $host;
  proxy_set_header Host $host;
  proxy_set_header X-Forwarded-For $remote_addr;

  location / {
    rewrite ^/(.*) https://firstdomain/$1;  # redirect to https
  }
}

server {
  listen x.x.x.84:443 ssl;                            # this is a public ip
  server_name firstdomain.com;

  ssl_certificate      /etc/nginx/ssl/combined.firstdomain.com.crt;
  ssl_certificate_key  /etc/nginx/ssl/wildcard.firstdomain.com.key;

  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header Client-IP $remote_addr;
  proxy_set_header X-Host $host;
  proxy_set_header Host $host;
  proxy_set_header X-Forwarded-For $remote_addr;

  access_log /var/log/nginx/access.log proxy;
  error_log  /var/log/nginx/error.log;

  location / {
    proxy_pass http://x.x.x.85;                       # this is a public ip, too 
    proxy_redirect off;
  }
}

Creo que esta configuración es muy sencilla. Cada solicitud en el puerto 80 debe redirigirse al puerto 443. La configuración para un segundo dominio es muy similar.

/etc/nginx/sitios habilitados/otro dominio

server {
  listen x.x.x.87:80;                                   # this is a public ip
  server_name anotherdomain.org;

  access_log /var/log/nginx/access.log proxy;     # I made my own logformat
  error_log  /var/log/nginx/error.log;

  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header Client-IP $remote_addr;
  proxy_set_header X-Host $host;
  proxy_set_header Host $host;
  proxy_set_header X-Forwarded-For $remote_addr;

  location / { 
    rewrite ^/(.*) https://anotherdomain.org/$1;  # redirect to https
  }   
}

server {
  listen x.x.x.87:443 ssl;                            # this is a public ip
  server_name anotherdomain.org;

  ssl_certificate      /etc/nginx/ssl/combined.anotherdomain.org.crt;
  ssl_certificate_key  /etc/nginx/ssl/wildcard.anotherdomain.org.key;

  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header Client-IP $remote_addr;
  proxy_set_header X-Host $host;
  proxy_set_header Host $host;
  proxy_set_header X-Forwarded-For $remote_addr;

  access_log /var/log/nginx/access.log proxy;
  error_log  /var/log/nginx/error.log;

  location / {
    proxy_pass http://x.x.x.89;                       # this is a public ip, too
    proxy_redirect off;
  }
}

Mi fragmento de netstat -tulpen:

Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       User       Inode       PID/Program name
...
tcp        0      0 x.x.x.84:80           0.0.0.0:*               LISTEN      0          8724        1187/nginx      
tcp        0      0 x.x.x.87:80           0.0.0.0:*               LISTEN      0          8723        1187/nginx      
tcp        0      0 x.x.x.84:443          0.0.0.0:*               LISTEN      0          8726        1187/nginx      
tcp        0      0 x.x.x.87:443          0.0.0.0:*               LISTEN      0          8725        1187/nginx      
...

De hecho, pensé que debería ser suficiente para alojar varios dominios con SSL en el mismo servidor. Pero nginx entrega el mismo certificado en cada solicitud. El resultado es un error de SSL.

Y hay otro comportamiento inesperado. Durante la depuración intenté obtener los sitios web con telnet como cliente. Esta petición:

user@host:~$ telnet x.x.x.84 80
Trying x.x.x.84...
Connected to x.x.x.84.
Escape character is '^]'.
GET / HTTP/1.1
Host: firstdomain.com

pertenece a esta respuesta:

HTTP/1.1 302 Moved Temporarily
...
Location: https://firstdomain.com/

Mmh, está bien... pero esta solicitud [mismo dominio (ver encabezado 'Host:'), pero la IP no es ahora]:

user@host:~$ telnet x.x.x.87 80
Trying x.x.x.87...
Connected to x.x.x.87.
Escape character is '^]'.
GET / HTTP/1.1
Host: firstdomain.com

... da como resultado la entrega del sitio web que estoy solicitando. Obtuve el sitio web a través del proxy aunque envié la solicitud a la IP incorrecta y sin SSL. ¡Eso es exactamente lo que quería evitar!

¡Gracias por tus ideas!

Respuesta1

Su primera configuración debería verse así.

server {
  listen x.x.x.84:80;
  server_name firstdomain.com;

  access_log /var/log/nginx/access.log proxy;
  error_log  /var/log/nginx/error.log;

  return https://$server_name$request_uri;
}

server {
  listen x.x.x.84:443 ssl;
  server_name firstdomain.com;
  root ????;

  ssl_certificate      /etc/nginx/ssl/combined.firstdomain.com.crt;
  ssl_certificate_key  /etc/nginx/ssl/wildcard.firstdomain.com.key;

  access_log /var/log/nginx/access.log proxy;
  error_log  /var/log/nginx/error.log;

  location / {
    # Do not proxy everything to the backend, deliver static files
    # right away!
    try_files $uri @proxy;
  }

  location @proxy {
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header Client-IP $remote_addr;
    proxy_set_header X-Host $host;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $remote_addr;
    proxy_redirect off;
    # The backend MUST be SSL enabled as well!
    proxy_pass https://x.x.x.85;
  }
}

Su segunda configuración debería verse así.

server {
  listen x.x.x.87:80;
  server_name anotherdomain.org;

  access_log /var/log/nginx/access.log proxy;
  error_log  /var/log/nginx/error.log;

  return https://$server_name$request_uri;
}

server {
  listen x.x.x.87:443 ssl;
  server_name anotherdomain.org;
  root ????;

  ssl_certificate      /etc/nginx/ssl/combined.anotherdomain.org.crt;
  ssl_certificate_key  /etc/nginx/ssl/wildcard.anotherdomain.org.key;

  access_log /var/log/nginx/access.log proxy;
  error_log  /var/log/nginx/error.log;

  location / {
    # Do not proxy everything to the backend, deliver static files
    # right away!
    try_files $uri @proxy;
  }

  location @proxy {
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header Client-IP $remote_addr;
    proxy_set_header X-Host $host;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $remote_addr;
    proxy_redirect off;
    # The backend MUST be SSL enabled as well!
    proxy_pass https://x.x.x.85;
  }
}

Avíseme si esto ayuda para que podamos redefinir aún más la configuración.

información relacionada