Una guía para ejecutar un proxy inverso para HTTP(S), SSH y MySQL/MariaDB usando NGINX

Esta guía te guiará a través de la instalación y configuración de NGINX para permitir la ejecución de múltiples servidores físicos, máquinas virtuales o una combinación de ambos detrás de una única dirección IP pública. Puedes optar por ejecutar una serie de servidores web en máquinas virtuales y administrarlos localmente o puede que tengas que hacer uso de herramientas de acceso remoto, como SSH, a cada uno de los hosts. Por ejemplo, si el acceso local no está disponible fuera del horario laboral. Esta guía puede facilitar ambos escenarios.

Las configuraciones que se muestran aquí serían las más adecuadas para un laboratorio doméstico o una red de pequeña empresa que tenga limitaciones en las direcciones IP públicas disponibles. Habría pocas razones, si es que hay alguna, para ejecutar una configuración como ésta, cuando tienes varios servidores o máquinas virtuales alquiladas a un servicio de alojamiento, se te asignará una Dirección IP pública para cada servidor o host de todos modos.

Te mostraré cómo instalar NGINX y hacer configuraciones que permitan al servidor actuar como proxy inverso para HTTP(S), SSH, FTP y MySQL/MariaDB. Supongo que para el servidor anfitrión NGINX tienes: acceso local, una instalación fresca de Ubuntu 18.04 y que has optado por instalar el servidor SSH durante los pasos de instalación del servidor Ubuntu.

Esta configuración me funciona bien, pero entiende que no puedo garantizar que te funcione a ti. Por supuesto, si encuentras algo incorrecto, házmelo saber para que se pueda corregir. Por favor, asegúrate de que lees toda la guía antes de empezar, ya que hay una parte (flujos) en la que muestro dos formas de gestionarlo.

Cómo empezar

En esta guía, utilizaré los siguientes nombres de host y direcciones IP.

rproxy.example.com  192.168.1.1
web1.example.com    192.168.1.2
db1.exmple.com      192.168.1.3

Deberías tener una cuenta de usuario no root en el servidor para una instalación estándar de servidor Ubuntu 18.04 que hayas creado durante la instalación. Comienza iniciando sesión en el servidor donde vas a instalar NGINX con ese usuario. Como lo más probable es que se trate de un servidor local, es posible que tengas que iniciar sesión en el servidor directamente la primera vez para configurar el servidor SSH. Por supuesto, necesitarás un teclado y un monitor conectados al servidor para hacerlo.

Nota: Si, como yo, utilizas un software de virtualización como VMWare que incluye una interfaz de navegador, entonces deberías tener una consola dentro de ese sistema y podrás realizar este paso sin acceso «directo». Podrías intentar realizar toda esta configuración dentro de esa consola, sin embargo, he comprobado que algunas funciones como copiar y pegar no funcionaban en la consola basada en el navegador, aunque esto podría ser específico del navegador, por lo que puede merecer la pena probar a ver si puedes.

Preparar el servidor anfitrión

En tu consola (navegador o directamente conectada)

sudo nano /etc/ssh/sshd_config

Descomenta las líneas: Port cambia el número de puerto a algo como 23456, ListenAddress y cámbialo a 0.0.0.0. Para los que no estén familiarizados con nano, pulsa CTRL + X, escribe y y luego pulsa intro. Esto guardará y cerrará un archivo, si no se hicieron cambios en el archivo, CTRL + x cerrará el archivo sin pedir que se guarde. Volverás al símbolo del sistema.

No profundizaré en el resto de las configuraciones de este archivo porque esta es ya una guía considerablemente larga y hay muchas guías que te mostrarán qué configuraciones debes cambiar para una serie de cosas, como el uso de claves SSH y permitir el inicio de sesión SSH de root. También puedes encontrar esas guías aquí en el sitio web de HowtoForge.

Una vez realizados los cambios, tendrás que reiniciar el servidor ssh para que los cambios surtan efecto. Tu inicio de sesión actual no se verá afectado por este reinicio.

systemctl restart ssh

Comprueba que puedes iniciar la sesión mediante SSH desde un terminal en otro ordenador de tu red local.

ssh [email protected] -p23456

Mantén este terminal abierto después de iniciar la sesión con éxito utilizando SSH y cierra la sesión de la consola/servidor. Ya no es necesario que lo utilices para el resto de esta guía.

A partir de este momento, ejecutarás comandos de nivel raíz desde tu terminal. El siguiente comando eliminará la necesidad de preceder los comandos posteriores con sudo.

sudo -s

Actualiza la base de datos de paquetes Apt y actualiza Ubuntu para asegurarte de que tienes instalados los paquetes más recientes.

apt update && apt -y upgrade

Si durante la actualización ves algo que informa de que se están instalando nuevos núcleos, debes reiniciar una vez que apt haya terminado de actualizar para asegurarte de que estás trabajando en un sistema totalmente actualizado.

Establecer el nombre de host del servidor proxy inverso.

hostnamectl set-hostname rproxy.example.com

Si estás ejecutando un servidor virtual, es posible que tengas un archivo llamado cloud.cfg que necesite ser modificado para conservar el nombre de host que se establece aquí. El siguiente comando mostrará un archivo con contenido o una página vacía. Si ves una página vacía, puedes simplemente pulsar CTRL + x y saltarte este paso, ya que no tienes que hacer nada.

nano /etc/cloud/cloud.cfg

Cambia la línea de preservar el nombre de host a verdadero y cierra/guarda el archivo.

If your system is currently local only you will need to show this server where your other servers/virtual hosts are.
nano /etc/hosts

El archivo de hosts tendrá este aspecto después de realizar los cambios, las direcciones IP y los hosts deben coincidir con tu propia infraestructura.

127.0.0.1 localhost
127.0.1.1  rproxy.example.com
192.168.1.2    web1.example.com
192.168.1.3    db1.example.com

# The following lines are desirable for IPv6 capable hosts
::1     ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

Instalación de NGINX

apt install -y nginx

Después de la instalación debes comprobar tu versión de NGINX, es primordial que tengas una versión 1.9 o superior para permitirte el proxy inverso para SSH y MySQL/MariaDB.

nginx -v

Como puedes ver, tengo instalada la versión 1.14 de NGINX, que es la que viene por defecto en Ubuntu 18.04 (10 de octubre de 2019)

nginx version: nginx/1.14.0 (Ubuntu)

Preparar NGINX para que funcione como Proxy Inverso

Con esta configuración, no vas a servir ningún sitio web directamente desde el servidor proxy inverso. Crearás una nueva estructura de directorios en /etc/nginx/. Esto preservará las configuraciones por defecto de NGINX en caso de que quieras revertir estos cambios más adelante o decidas que en realidad también quieres servir sitios web directamente desde este host. Es posible ejecutar la configuración por defecto junto con estas configuraciones de proxy inverso, pero si Apache2 va a estar en el mismo servidor, necesitará puertos alternativos para escuchar y todavía tendrás que hacer proxy inverso a los sitios web que sirve esta instancia de Apache2.

Construye la estructura de directorios del proxy inverso

cd /etc/nginx && mkdir rproxy && cd rproxy && mkdir http http/available http/enabled stream stream/available stream/enabled

Ahora que ya tienes la estructura, puedes proceder a crear los archivos de configuración. Yo utilizo nano, pero puedes utilizar el editor con el que te sientas cómodo. Nano creará/actualizará los archivos al guardarlos.

Before you proceed, open an empty document on your computer or get a pen and paper to note down the ports you configure.

Configurar los proxies inversos del servidor web (http)

Crea el/los archivo/s de configuración http para el/los sitio/s web ajustando en consecuencia

nano http/available/example.com.conf

Copia el bloque del servidor en la página abierta en el terminal con nano ajustando en consecuencia.

# Note down ports 80 and 443

server {
    server_name example.com www.example.com;
    listen 80;
    set $upstream 192.168.1.2;
    location / {
         proxy_pass_header Authorization;
         proxy_pass http://$upstream;
         proxy_set_header Host $host;
         proxy_set_header X-Real-IP $remote_addr;
         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
         proxy_http_version 1.1;
         proxy_set_header Connection "";
         proxy_buffering off;
         client_max_body_size 0;
         proxy_read_timeout 10000s;
         proxy_redirect off;
     }
}

Configurar los proxies inversos SSH, MySQL/MariaDB (stream)

Antes de continuar, decide qué quieres utilizar, por host o por servicio. Por host, crearás una configuración para cada host que puede ser útil para cambiar rápidamente la configuración de un solo host. Por servicio, tendrás los puertos de servicio de todos los servidores en un archivo para cada uno, SSH, MySQL/MariaDB y FTP.

Utilizar las configuraciones por servicio

Añade las configuraciones de SSH.

nano stream/available/ssh.conf
# Note down the listen ports

upstream web1-ssh {
  server 192.168.1.2:22;
}

server {
  listen 22002;
  proxy_pass web1-ssh;
}

upstream db1-ssh {
  server 192.168.1.3:22;
}

server {
  listen 22003;
  proxy_pass db1-ssh;
}

# Add as many upstream and server block pairs as you will need for your remote accessed SSH servers.

Añade las configuraciones de MySQL/MariaDB.

nano stream/available/db.conf
# Note down the listen ports

upsteam db1-mysql {
  server 192.168.1.3:3306;
}

server {
  listen 33063;
  proxy_pass db1-mysql;
}

# Add as many upstream/server block pairs as you will need for your remote accessed MySQL/MariaDB servers to this file.

Ahora crea las configuraciones del proxy inverso FTP.

nano stream/available/ftp.conf
upstream web1-ftp {
  server 192.168.1.3:21
}

server {
  listen 21002;
  proxy_pass web1-ftp;
}

# Add as many upstream/server block pairs as you will need for your remote accessed FTP servers.

Utilizando archivos de configuración por host

nano /etc/nginx/rproxy/stream/available/web1.example.com.conf
# Note down the listen ports

upstream web1-ssh {
  server 192.168.1.3:22;
}

server {
  listen 22002;
  proxy_pass web-ssh;
}

Crear el archivo de host para db1.ejemplo.com

nano /etc/nginx/rproxy/stream/available/db1.example.com.conf
# Note down the listen ports

upsteam db1-mysql {
  server 192.168.1.3:3306;
}

server {
  listen 33063;
  proxy_pass db1-mysql;
}

upstream db1-ssh {
  server 192.168.1.3:22;
}

server {
  listen 22003;
  proxy_pass db1-ssh;
}

Como puedes ver, es algo poco ortodoxo. Estás utilizando los puertos públicos de una forma no estándar, eligiendo los puertos que necesitas y apuntándolos a NGINX. Esto sería normal, salvo que ahora estás utilizando un puerto diferente para cada servicio de cada servidor al que quieres acceder de forma remota. Esto significa que, utilizando SSH como ejemplo, un número de puerto diferente para cada host habilitado para SSH 22 222 2222 22222, por ejemplo, apuntaría al puerto 22 en cuatro servidores o máquinas virtuales diferentes.

Este no es el caso de NGINX para el proxy inverso de los sitios web, siempre que NGINX tenga una configuración de servidor definida para un sitio web, funcionará correctamente con sólo los puertos 80 y 443 reenviados a él.

Llegados a este punto, probablemente te habrás dado cuenta de que podrías utilizar simplemente los pasos de HTTP y saltarte los pasos de flujo, y en su lugar reenviar varios puertos para los múltiples servicios al servidor/dirección IP correspondiente. Efectivamente, esto puede hacerse. Sin embargo, añadiría otra capa de complejidad y se volvería difícil de mantener a medida que aumentara el número de servidores, ya que podrías tener que cambiar los puertos por defecto de cada servidor para ssh, mysql y ftp. Esta configuración ya es compleja, pero aún así podría hacerse si se quiere.

Utilizar un proxy inverso para estos servicios de la forma que te he mostrado disminuye la complejidad significativamente al proporcionar un único lugar para realizar estos cambios de configuración y no necesitarías hacer cambios en los puertos en toda tu infraestructura.

Como ventaja añadida a esta configuración, los demás servidores de tu infraestructura sólo tienen que escuchar en las interfaces locales y en los puertos por defecto, si eso es lo que prefieres. Si estás gestionando localmente, puedes utilizar las direcciones IP locales y los puertos de servicio por defecto para acceder a los servicios requeridos, por lo que no necesitarás consultar tus notas para recordar los puertos correctos, sólo necesitas conocer la dirección IP y las credenciales de acceso.

Reunirlo todo

Para empezar a utilizar las configuraciones del proxy inverso NGINX tendrás que hacer algunas modificaciones en el archivo de configuración principal. Comenta la línea de inclusión actual en el bloque http (si no estás sirviendo sitios web directamente desde NGINX también).

cd /etc/nginx && nano nginx.conf

Fíjate en las partes resaltadas más abajo para determinar qué hay que cambiar.

user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

events {
        worker_connections 768;
        # multi_accept on;
}

http {

        ##
        # Basic Settings
        ##

        sendfile on;
        tcp_nopush on;
        tcp_nodelay on;
        keepalive_timeout 65;
        types_hash_max_size 2048;
        # server_tokens off;

        # server_names_hash_bucket_size 64;
        # server_name_in_redirect off;

        include /etc/nginx/mime.types;
        default_type application/octet-stream;

        ##
        # SSL Settings
        ##

        ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
        ssl_prefer_server_ciphers on;

        ##
        # Logging Settings
        ##

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

        ##
        # Gzip Settings
        ##

        gzip on;

        gzip on;

        # gzip_vary on;
        # gzip_proxied any;
        # gzip_comp_level 6;
        # gzip_buffers 16 8k;
        # gzip_http_version 1.1;
        # gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascri$

        ##
        # Virtual Host Configs
        ##

        include /etc/nginx/conf.d/*.conf;
#       include /etc/nginx/sites-enabled/*;

        # Reverse proxy http configuration files.
        include /etc/nginx/rproxy/http/enabled/*.conf;
}

stream {

    # Reverse proxy stream configuration files.
    include /etc/nginx/rproxy/streams/enabled/*.conf;
}


#mail {
#       # See sample authentication script at:
#       # http://wiki.nginx.org/ImapAuthenticateWithApachePhpScript
# 
#       # auth_http localhost/auth.php;
#       # pop3_capabilities "TOP" "USER";
#       # imap_capabilities "IMAP4rev1" "UIDPLUS";
# 
#       server {
#               listen     localhost:110;
#               protocol   pop3;
#               proxy      on;
#       }
# 
#       server {
#               listen     localhost:143;
#               protocol   imap;
#               proxy      on;
#       }
#}
    

Activa las configuraciones del proxy inverso.

Primero, activa todas las configuraciones http

ln -s /etc/nginx/rproxy/http/available/*.conf /etc/nginx/rproxy/http/enabled

Habilita todas las configuraciones de flujo

ln -s /etc/nginx/rproxy/stream/available/*.conf /etc/nginx/rproxy/stream/enabled

Realiza una prueba para comprobar que la configuración de NGINX como proxy inverso es correcta.

nginx -T

En la salida, deberías ver un mensaje de éxito junto con todas las configuraciones personalizadas que hayas realizado previamente.

Reinicia NGINX para poner en marcha las configuraciones del proxy inverso.

systemctl restart nginx

Comprueba que NGINX está escuchando en todos los puertos configurados. verifica con tus notas que todos los puertos aparecen en los resultados.

netstat -tulpn | grep nginx

El resultado debería ser algo parecido a esto

tcp        0      0 0.0.0.0:22           0.0.0.0:*               LISTEN      4964/nginx: master  
tcp        0      0 0.0.0.0:22002           0.0.0.0:*               LISTEN      4964/nginx: master  
tcp        0      0 0.0.0.0:22003           0.0.0.0:*               LISTEN      4964/nginx: master
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      4964/nginx: master  
tcp        0      0 0.0.0.0:33062           0.0.0.0:*               LISTEN      4964/nginx: master  
tcp        0      0 0.0.0.0:33063           0.0.0.0:*               LISTEN      4964/nginx: master  
tcp        0      0 0.0.0.0:443             0.0.0.0:*               LISTEN      4964/nginx: master  
    

Abrir el servidor al tráfico

Ahora que NGINX está escuchando y está listo para actuar como proxy inverso para todas las conexiones que queremos permitir que entre el tráfico, desactiva temporalmente UFW mientras realizas los siguientes pasos. Esto facilitará la resolución de problemas si las cosas no funcionan correctamente.

ufw disable

Reenvío de puertos

Lamentablemente, no puedo orientarte en este punto. Tendrás que consultar el manual de tu router o buscarlo en Internet para saber cómo hacerlo. En resumen, sin embargo, querrás reenviar cada uno de los puertos en los que NGINX está escuchando a la máquina anfitriona de NGINX. En mi router específico, puedo configurar «aplicaciones» personalizadas.

Esto me permite asignar cualquier número de puertos o rangos de puertos no asignados a la aplicación personalizada, que luego se asignará a una dirección IP de la LAN o a un dispositivo conectado específico identificado por su nombre de host. En cualquier caso, esto significa que puedo cambiar todos los puertos asignados a esa aplicación personalizada a cualquier host de mi red sin tener que borrar todos los puertos y reasignarlos. Es una opción excelente y te recomiendo encarecidamente que elijas un router que la soporte.

Esta pequeña pero increíblemente útil función en el cortafuegos de mi router me llevó a instalar un segundo proxy inverso que refleja las configuraciones de mi proxy inverso activo. Lo tengo apagado y soy capaz de arrancar y tener los puertos cambiados a él en menos de 3 minutos de descubrimiento. Imagino que hay empresas de alojamiento profesionales que tendrían dificultades para cumplir ese tiempo de recuperación de desastres y todo esto surgió por el deseo de ejecutar varios servidores en una red doméstica.

Letsencrypt SSL gratuito para el servidor proxy inverso

Instala Certbot y el plugin Certbot NGINX. Este paso se realiza aquí porque no puedes crear un certificado hasta que tengas un DNS funcional para todos los (sub.)nombres de dominio que figuran en un certificado y puedas realizar una conexión al dominio a través de HTTP. Al completar esto después de haber reenviado los puertos al proxy inverso, también actúa como una prueba adicional a tus configuraciones. Si el cert falla porque no se puede alcanzar el dominio, verás un aviso de error significativo en la salida.

Para asegurarte de que obtienes la última versión de certbot, añade el repositorio de certbot antes de instalarlo. Los repositorios de Ubuntu suelen ir una versión o más por detrás de una versión de software y realmente quieres las últimas versiones estables de todo tu software si puedes conseguirlas.

add-apt-repository ppa:certbot/certbot
apt install -y certbot python-certbot-plugin

Con certbot y el plugin nginx de certbot instalados, ahora puedes crear los certificados para NGINX.

Este comando debe repetirse para todos los dominios y subdominios para los que quieras proporcionar SSL. Si es la primera vez que ejecutas certbot, deberás aceptar los términos y condiciones.

certbot --nginx -d example.com -d www.example.com

Ten en cuenta que si tienes una configuración de servidor en funcionamiento con SSL en el servidor principal, deberás asegurarte de que las opciones seleccionadas aquí coinciden con las del servidor principal, concretamente, si rediriges a https en el servidor principal, deberás hacerlo también aquí.

Para mayor claridad, ejemplo.com existe en otro servidor, y he seleccionado redirigir http a https dentro de ISPConfig, así que por esa razón, selecciono hacer eso aquí. El archivo de configuración se actualiza y ahora veo que Certbot ha añadido algunas configuraciones propias.

Comprobando que las cosas funcionan.

Ahora que el tráfico puede fluir hacia tu proxy inverso, debes comprobar que todo funciona como es debido. Comprueba que los sitios web funcionan correctamente, realiza conexiones y tareas SSH, FTP y MySQL/MariaDB. Una vez que estés satisfecho de que todo funciona como debería, habilita el UFW y añade reglas para permitir cada uno de los puertos.

Asegurar el servidor Proxy Inverso

ufw enable

Querrás permitir, 80 y 443 desde cualquier lugar. y probablemente restringir SSH, FTP y MySQL/MariaDB a una dirección IP o nombre de host. Puedes comentar las reglas para identificar rápidamente a qué servicio/servidor has asignado el puerto.

ufw allow 80
ufw allow 443
ufw allow from 1.2.3.4 to any port 22002 comment 'web1 SSH'
ufw allow from somehost.domain.com to any port 33061 comment 'db1 MySQL/MariaDB'

ufw reload
ufw status numbered

Actualizar Apache2

Cuando se ejecuta detrás de un proxy inverso, los archivos de registro de Apache2 registrarán la Dirección IP del servidor del proxy inverso en lugar de la Dirección IP del visitante del sitio web. Para restablecer el registro normal de la Dirección IP en Apache2 hay un módulo disponible para corregir este comportamiento.

Completa los siguientes pasos en cada servidor web con una instancia de Apache2 instalada.

sudo apt install -y libapache2-mod-rpaf

Para asegurarte de que Apache2 va a registrar ahora las direcciones IP correctas haz una pequeña modificación en el archivo rpaf.conf. Ubuntu 18.04 ya ha creado el archivo por nosotros, sólo tenemos que editarlo cambiando la Dirección IP resaltada por la del host del proxy inverso NGINX.

nano /etc/apache2/mods-available/rpaf.conf
<ifmodule rpaf_module="">
    RPAFenable On

    # When enabled, take the incoming X-Host header and
    # update the virtualhost settings accordingly:
    RPAFsethostname On

    # Define which IP's are your frontend proxies that sends
    # the correct X-Forwarded-For headers:
    RPAFproxy_ips 127.0.0.1 ::1

    # Change the header name to parse from the default
    # X-Forwarded-For to something of your choice:
#   RPAFheader X-Real-IP
</ifmodule>

Notas finales

NGINX y Apache2 en el mismo host

No puede haber dos servicios que escuchen en el mismo puerto dentro de un servidor o máquina virtual. Si NGINX está instalado en el mismo servidor o máquina virtual que un servidor web Apache2, tendrás que cambiar el puerto en el que escucha Apache2. NGINX necesita los puertos 80 y 443 para realizar sus funciones HTTP(S), ya que son los puertos por defecto para HTTP y HTTPS.

Vuelve a consultar la sección http de esta guía y añade configuraciones de proxy inverso para los sitios web servidos por esta instancia de Apache2 de la misma manera que la de otros servidores de la red.

Cambiar el puerto de escucha de Apache2

Si tienes instalado un sistema de gestión de servidores como ISPConfig, este sistema gestiona los archivos vhost de Apache2, por lo que debes investigar cómo cambiar los puertos en los que escucha Apache2. Busca en los foros de ISPConfig y luego haz los ajustes necesarios. Si no, debes buscar en los foros de Ubuntu o en el sitio web de Apache2 cómo realizar estos cambios.

Note: Apache2 ports do not need to be altered when it is the only web server installed on server or virtual machine.

También te podría gustar...