Nginx Reverse Proxy - Múltiples servicios en el mismo servidor

Helguera
Escrito por Helguera el
Link

Introducción

A lo largo de mis años como desarrollador de software he creado varias aplicaciones web en mi tiempo libre que puedes consultar aquí. Pero claro, para poder desplegarlas y que todo el mundo pueda hacer uso de ellas es necesario tener un servidor.

La pregunta es, ¿cómo configuro un servidor Ubuntu para que sirva diferentes aplicaciones ya sean Node.js, PHP, paginas estáticas, Jekyll… con sus respectivos dominios y certificados SSL? No spoilers, pero eso es lo que te voy a enseñar a hacer en este post usando como ejemplo mi propio servidor.

El Servidor

Hablando desde mi experiencia personal, siempre recomiendo DigitalOcean. Llevo utilizando sus servicios desde hacer varios años y nunca he tenido ningún problema. El servidor mas barato que se puede obtener ronda los 5$ al mes, lo cual esta muy bien para proyectos pequeños.

De todas maneras, lo ideal es que compares los diferentes proveedores que existen y elijas el que mas te convenza. Cada uno tiene sus pros y sus contras. Todo es cuestion de que analices lo que necesitas exactamente y cual de ellos te lo ofrece.

Si finalmente te decides por DigitalOcean, me seria de mucha ayuda si te registras a través de la siguiente imagen. Estarias contribuyendo al mantenimiento de esta pagina y obtendrás 100$ de crédito en la página.

DigitalOcean Referral Badge

Desplegando las Apps

Una vez que tenemos el servidor, es el momento de desplegar las aplicaciones. A continuación puedes encontrar tecnologías que uso en mi propio servidor y que son bastante comunes.

Vamos a utilizar la carpeta /var/www como directorio donde colocar los archivos de cada app.

En mi caso:

  • hlgrdev.com -> html y css puro
  • javierhelguera.com -> Blog en Jekyll (esta misma pagina que estas leyendo)
  • pao.hlgrdev.com -> App en Node.js
  • phrase2playlist.hlgrdev.com -> App en Node.js

quality screen

Node.js

Para manejar diversas apps en Node.js la mejor herramienta es PM2. Lo instalamos:

npm install pm2 -g

Accedemos a la carpeta donde esta el archivo principal de la aplicación. En mi caso:

cd /var/www/phrase2playlist.hlgrdev.com

Y ejecutamos el siguiente comando, que va a arrancar la app en segundo plano:

pm2 start app.js

Para ver la lista de Node apps que tenemos en ejecución podemos ejecutar:

pm2 list

quality screen

Se pueden ver datos como la versión, el pid, el status o el tiempo de uptime.

Otros comandos útiles de pm2 son:

$ pm2 stop     <app_name|namespace|id|'all'|json_conf>
$ pm2 restart  <app_name|namespace|id|'all'|json_conf>
$ pm2 delete   <app_name|namespace|id|'all'|json_conf>

En las apps en Node el puerto donde se despliega se especifica dentro de la propia app. Recuerda bien ese numero, lo necesitaremos mas adelante.

Jekyll

Para desplegar un blog en Jekyll para producción hay que usar el siguiente comando, que añadirá el proceso al segundo plano:

JEKYLL_ENV=production bundle exec jekyll serve > /dev/null 2>&1 &

Si quieres sabes mas sobre Jekyll consulta este post donde trato el tema en detalle.

HTML Puro

Facil, no hay nada que hacer. Coloca los ficheros (incluyendo el index.html) en una carpeta y pasa al siguiente apartado.

Wordpress

Bueno, no quiero ser pesimista, pero prepárate para tener dolores de cabeza configurando una app en PHP, en este caso Wordpress, junto con NGINX actuando de reverse proxy. No voy a entrar mucho en detalle, ya que no lo utilizo, pero si lo he configurado en el pasado y se que se puede. Te dejo unos enlaces que te pueden ser de utilidad.

Normalmente Wordpress se utiliza con apache, lo que se conoce como LAMP. Al utilizar NGINX se conoce como LEMP (Linux, Nginx, MySQL y PHP).

Otros

Si quieres utilizar alguna que no aparece aquí, no hay ningun problema, simplemente tienes que ejecutar la app como si lo hicieras en tu maquina local y asignarle un puerto.

Nginx- Reverse Proxy

Por el momento las apps serán accesible desde la IP del servidor junto con sus respectivos puertos. En verdad es así de fácil, no tiene mucho misterio. Pero por supuesto no queremos que nuestros usuarios accedan a las apps mediante una url del estilo http://192.168.1.1:32400.

Aquí es donde Nginx entra en juego:

Nginx es un software de código abierto para la prestación de servicios web, proxy inverso, almacenamiento en caché, balanceo de carga, transmisión de medios y mucho más. Comenzó como un servidor web diseñado para obtener el máximo rendimiento y estabilidad.

Instalación

Ejecuta los siguientes comandos:

apt update
apt install nginx

Configuración

Accedemos ahora al directorio donde se encuentran los fichero de configuración de NGINX:

cd /etc/nginx/sites-available

En este directorio tendremos que crear un fichero de texto por cada app que queramos desplegar. No hace falta que tengan ninguna extensión en concreto:

quality screen

Copiamos el siguiente contenido dentro de cada fichero. Ten en cuenta que tienes que cambiar server_name por el dominio que quieras utilizar y ajustar proxy_pass con su respectivo puerto. Este bloque hace referencia a javierhelguera.com que se está ejecutando en el puerto 4000.

server {

    server_name javierhelguera.com;

    location / {
        proxy_pass http://0.0.0.0:4000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }

}

Una vez tengamos todos los archivos creados tenemos que activarlos. Todos los ficheros que se encuentren en el directorio /etc/nginx/sites-available son, como su nombre dice, ficheros de configuración disponibles. Para activarlos solo tenemos que copiar los que necesitemos al directorio /etc/nginx/sites-enable. Para ser más correctos, vamos a crear un enlace simbólico en vez de duplicar los ficheros. Para ello:

ln -s /etc/nginx/sites-available/javierhelguera.com /etc/nginx/sites-enabled/javierhelguera.com

Una vez tengamos todos los enlaces creados, con el comando ln -l podremos ver el fichero original al que apuntan:

quality screen

Finalmente, para comprobar que no hemos cometido ningún error de sintaxis, ejecutamos el siguiente comando:

nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Si todo está correcto, ya podemos arrancar el servicio nginx (en caso de que no lo estuviese ya):

sudo systemctl start nginx          -> Para arrancarlo
sudo systemctl stop nginx           -> Para pararlo
sudo systemctl restart nginx        -> Para refrescar en caso de que hagamos un cambio de config

Let's Encrypt y Certbot

Vamos a encriptar ahora las conexiones que se hacen entre el cliente y el servidor. Este es un paso muy importante, no solo si nuestro sitio trabaja con información confidencial como tarjetas de crédito, pero también para posicionar nuestra página. Google penaliza gravemente los sitios que no cuentan con un certificado para encriptar las conexiones. Por suerte, es bastante fácil de conseguir con Certbot y Let's Encrypt:

Lo primero de todo es instalar Certbot:

apt-get update
apt-get install software-properties-common
add-apt-repository ppa:certbot/certbot
apt-get update
apt-get install python3-certbot-nginx

Lo ejecutamos:

certbot --nginx

El programa nos llevara de la mano, sólo tendremos que seleccionar los ajustes que queremos. Lo primero es seleccionar el dominio (o subdominio) en el que queremos activar HTTPS. En mi caso voy a utilizar test.hlgrdev.com. Por lo tanto selecciono la opción 4.

Lo siguiente que nos pregunta es si queremos redirigir conexiones HTTP a HTTPS. Seleccionamos la opción 2:

Y listo, eso es todo lo que hay que hacer. Podemos ver que el archivo que creamos en /etc/nginx/sites-available ha cambiado ligeramente:

server {

    server_name test.hlgrdev.com;

    location / {
        proxy_pass http://0.0.0.0:5555;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/test.hlgrdev.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/test.hlgrdev.com/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
    if ($host = test.hlgrdev.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot

    server_name test.hlgrdev.com;
    listen 80;
    return 404; # managed by Certbot
}

Las lineas que están marcadas con # managed by Certbot nunca deberemos editarlas manualmente ya que podríamos romper la configuración de Certbot.

Configuración de DNS

Por último lo que nos queda de hacer es configurar que nuestro dominio, por ejemplo, test.hlgrdev.com apunte a la IP de nuestro servidor.

Esto depende un poco de con que empresa tengas contrados los servicios. Yo tengo comprado el dominio en Namecheap y el servidor en DigitalOcean.

  • En Namecheap configuro los DNS para que apunten a los de DigitalOcean:

  • En DigitalOcean añado 3 records NS que enlacen hlgrdev.com con los servidores de DNS de DigitalOcean:

    Finalmente añado un record del tipo A para apuntar el dominio (o subdominio) a la IP de mi servidor:

Si accedo ahora a test.hlgrdev.com puedo comprobar que el dominio apunta correctamente a la dirección IP que he configurado y, gracias a Nginx, también al puerto correcto. Por supuesto, la página será segura y las conexiones encriptadas.


Conclusión

Y esto es todo. Ya tendremos en nuestro servidor multiples servicios de diferentes tecnologías, cada uno con su certificado SSL y su dominio propio. Espero que te haya sido de utilidad.

Javier Helguera.

Comentarios