Configuración de Nginx para Web Sockets Seguros (wss)

Hace un tiempo atras empecé a interiorizarme en el manejo de Web Sockets, para lo cual realizé un chat de pruebas, para lo cual necesité configurar Nginx para que se ocupe de realizar la redirección de puertos y la utilización de certificados SSL.

Bueno, el primer paso será obtener los certificados SSL, para lo cual usé Let’s Encript, luego se necesita crear el archivo de configuración correspondiente en: /etc/nginx/sites-available.

En este caso el archivo que cree se denomina chat-ws.greenborn.com.ar, con el siguiente contenido:

server {
    listen PUERTO_ESCUCHA;
    ssl on;
    server_name DOMINIO;

    ssl_certificate PATH_CERTIFICADO/fullchain.pem; # managed by Certbot
    ssl_certificate_key PATH_CERTIFICADO/privkey.pem; # managed by Certbot
    include PATH_LETS_ENCRIPT/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam PATH_LETS_ENCRIPT/ssl-dhparams.pem; # managed by Certbot

    location / {
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_pass         "http://127.0.0.1:PUERTO_INTERNO";
    }
}

Claramente en el mismo se debe reemplazar:

  • PUERTO_ESCUCHA: Especificando el puerto que se usará publicamente para la conexion con el Web Socket
  • DOMINIO: El dominio asignado a la APP
  • PATH_CERTIFICADO: Ubicación del certificado SSL
  • PATH_LETS_ENCRIPT: Ubicación de la instalación de Lets Encript
  • PUERTO_INTERNO: Es el puerto que la APP estará escuchando

Luego será necesario crear el enlace simbólico del archivo de configuración, por ej con:

ln -s /etc/nginx/sites-available/archivo_config /etc/nginx/sites-enabled/archivo_config

Y reiniciar el servicio de Nginx

sudo service nginx restart

Con eso ya sería todo.

Una forma de comprobar el funcionamiento podría ser usar una extensión del navegador como simple-websocket-client, disponible tanto para Firefox como para Chrome: https://addons.mozilla.org/en-US/firefox/addon/simple-websocket-client/ o https://chrome.google.com/webstore/detail/simple-websocket-client/pfdhoblngboilpfeibdedpjgfnlcodoo

Archivo de configuración básico Nginx

Luego de meditarlo por un tiempo, decidí finalmente reemplazar Apache por Nginx.

Se podría decir que finalmente he sido convencido por su promesa de tener un mejor rendimiento que Apache.

Cuestión que parece ser verdad.

Aunque eso no significa que pueda volver a Apache si el mismo mejora en dicho apartado, es el servidor web con el cual empecé a trabajar y aún le tengo cierto cariño.

Además con la actualización a PHP 8 y su módulo PHP-FPM, la verdad que estoy muy satisfecho con su rendimiento.

El archivo de configuración

Aquí agrego una muestra de un archivo de configuración básico que uso para el sitio, claramente Ud. deberá modificar los parámetros para que se adecué a sus necesidades

server {
        root /RUTA/DIRECTORIO/SITIO/WEB;
        index index.php index.html;
        server_name DOMINIO.DE.SU.SITIO.COM.AR;

        location / {
                try_files $uri $uri/ @rewrite_url;
        }

        location @rewrite_url {
                rewrite ^/(.*)$ /index.php?viewpage=$1 last;
        }

        location ~ \.php$ {
            include snippets/fastcgi-php.conf;
            fastcgi_pass unix:/var/run/php/php8.0-fpm.sock;
        }

        location ~* .(woff|eot|ttf|svg|mp4|webm|jpg|jpeg|png|gif|ico|css|js)$ 
        {
             expires 365d;
        }

        listen 443 ssl http2; # managed by Certbot
        ssl_certificate /RUTA/CERTI/fullchain.pem; # managed by Certbot
        ssl_certificate_key /RUTA/CERTI/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 = DOMINIO.DE.SU.SITIO.COM.AR) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


    server_name DOMINIO.DE.SU.SITIO.COM.AR;
    listen 80;
    return 404; # managed by Certbot
}

DOMINIO.DE.SU.SITIO.COM.AR: Deberá ser reemplazado por el dominio del sitio (se puede especificar sub-dominio)

/RUTA/DIRECTORIO/SITIO/WEB: Deberá ser reemplazado por la ruta en la cual se halle su sitio web.

Este archivo de configuración está recomendado para cualquier sitio basado en PHP, como bien podría ser una web desarrollada con WordPress.

Precondiciones

En este caso se asume que:

  • Ud. tiene acceso SSH para poder configurar el servidor.
  • El sistema operativo es Debian o alguno de sus derivados.
  • Usa certificado SSL gratuito de Let’s Encrypt: https://letsencrypt.org/
  • Tiene correctamente configurado su firewall tieniendo abierto los puertos 80 y 443.

Comentarios sobre secciones del archivo

Para que se realice la reescritura de URL (que en Apache se realizaba habilitando el mod_rewrite y configurando la reescritura en el .conf del sitio o en el .htaccess) se usa la sección:

location / {
    try_files $uri $uri/ @rewrite_url;
}

location @rewrite_url {
    rewrite ^/(.*)$ /index.php?viewpage=$1 last;
}

Se especifica el uso de PHP-FPM con las líneas:

location ~ \.php$ {
     include snippets/fastcgi-php.conf;
     fastcgi_pass unix:/var/run/php/php8.0-fpm.sock;
}

Dependiendo de sus sistema operativo, puede que varíe la ruta especificada en el parámetro: fastcgi_pass.

La configuración referente al cacheo de archivos se especifica en:

location ~* .(woff|eot|ttf|svg|mp4|webm|jpg|jpeg|png|gif|ico|css|js)$ 
{
      expires 365d;
}

Configuración de certificado SSL y uso de HTTP2

La configuración del certificado SSL, en este caso, se realiza de forma automática utilizando el certbot de Let’s Encrypt; puede ver como instalarlo en: https://www.linode.com/docs/guides/enabling-https-using-certbot-with-nginx-on-debian/

En el archivo de configuración indicado, todo el contenido grisado y en itálica (a partir de la linea listen 443 ssl http2; # managed by Certbot inclusive) debería no ser incluido en el archivo, ya que deberá ser generado por el certbot.

A esta altura, se asume que ya habilitó el sitio agregando el correspondiente enlace simbólico.

Por ej usuando un comando similar al siguiente:

# ln -s /etc/nginx/sites-available/mi.sitio.com.ar /etc/nginx/sites-enabled/mi.sitio.com.ar

Y que agregó el correspondiente registro de tipo A en la configuración de registros DNS de su dominio.

Por lo que el siguiente paso será reiniciar Nginx para que se apliquen los cambios, con:

# service nginx restart

Si, todo va bien, no debería indicarse ningún mensaje en consola.

Y luego ejecutar el certbot con:

# certbot

Allí mismo se indicarán una o varias opciones de acuerdo a los dominios y subdominios de los sitios alojados en el servidor, dicha lista se arma de acuerdo a los archivos de configuración de Nginx.

Se elige la opción correspondiente al dominio o subdominio a configurar, y si todo va bien, el certbot genera el certificado SSL y actualiza el archivo de configuración del vhost.

Si no se quiere usar HTTP2 ya estaría todo casi listo, pero por defecto dicho protocolo no está habilitado, por lo que deberá volver a abrir el archivo de configuración, buscar la línea listen 443 ssl; # managed by Certbot y reemplazarla por: listen 443 ssl http2; # managed by Certbot

Ya para finalizar será necesario volver a reiniciar el servicio nginx.