NGINX, además de utilizarse como servidor Web estático o dinámico, dispone de otras características desarrolladas como la mayoría de servidores Web. Ofrece la funcionalidad de realizar Proxy inverso o también llamado servidor de paso. Además, esta función permite poder configurar un escenario de balanceo de carga para distribuir el tráfico para la disponibilidad, escalabilidad y rendimiento.
Un servidor de Proxy inverso es el que recibe las peticiones generalmente de clientes Web, este servidor recupera y sirve los recursos de uno o más servidores. En este artículo te enseñamos cómo realizar Proxy inverso con NGINX utilizando un único servidor Web Apache con FastCGI para la interconexión y así poder atender más peticiones simultáneas.
¿Qué es y cómo funciona el Proxy inverso?
Un servidor de paso o Proxy no genera contenido ni aloja datos, en su lugar el contenido se obtiene de los servidores Backend, que normalmente tienen conexión directa con redes internas. Por ejemplo, en un escenario Web, cuando un servidor Proxy recibe tráfico de un cliente realiza la petición a uno de estos servidores Backend para gestionarla, generar el contenido, proporcionarle una respuesta y entonces el servidor Proxy reenvía la respuesta al cliente.
Hay múltiples razones para la implementación de esta función, entre ellas, seguridad, alta disponibilidad, balanceo de carga y centralización de autorización. Normalmente en estas implementaciones en las que la arquitectura y el diseño de la infraestructura de los servidores Backend suelen estar aislados/protegidos del exterior (DMZ); la única conexión debería ser con el servidor Proxy (qué recibe y proporciona la respuesta al cliente).
Instalación y configuración de servidor Web (Apache)
Primero, actualiza los repositorios y paquetes:
# apt update && apt upgrade -y
Después, instala apache y PHP:
# apt install apache2 php-fpm php-curl php-dompdf php-mbstring php-imagick php-zip php-gd -y
Normalmente se utiliza el módulo fcgi del propio repositorio de Ubuntu, pero se encuentra desactualizado:
# apt show libapache2-mod-fcgid
Por lo tanto, puedes utilizar FastCGI con una versión más actualizada que se encuentra disponible en el repositorio GitHub de FastCGI-Archives. Para ello, primero ejecuta el siguiente comando para instalar unos paquetes necesarios:
# apt install unzip build-essential apache2-dev gcc make m4 autoconf automake libtool -y
Luego descarga el código comprimido:
# cd /tmp/ && wget https://github.com/FastCGI-Archives/fcgi2/archive/refs/heads/master.zip
Descomprímelo y accede al directorio:
# unzip master.zip && cd fcgi2-master/
Configúralo:
# ./autogen.sh && ./configure
E instálalo:
# make && make install
Posteriormente, descarga también el módulo de rpaf para las cabeceras:
# cd /tmp/ && wget https://github.com/gnif/mod_rpaf/archive/stable.zip
Luego, descomprímelo, accede al directorio descomprimido e instálalo también:
# unzip stable.zip && cd mod_rpaf-stable && make && make install
Para cargarlo, crea el fichero:
# vi /etc/apache2/mods-available/rpaf.load
Con el siguiente contenido:
LoadModule rpaf_module /usr/lib/apache2/modules/mod_rpaf.so
También crea otro fichero de nuevo para la configuración:
# vi /etc/apache2/mods-available/rpaf.conf
Con el este contenido (IMPORTANTE: Modificar la dirección IP)
<IfModule mod_rpaf.c>
RPAF_Enable On
RPAF_Header X-Real-Ip
RPAF_ProxyIPs DIRECCION_IP
RPAF_SetHostName On
RPAF_SetHTTPS On
RPAF_SetPort On
</IfModule>
Ahora actívalos y también los siguientes módulos:
# a2enconf php7.4-fpm && a2enmod rpaf actions proxy_fcgi setenvif cache cache_disk expires headers
Después, modifica el puerto por defecto de Apache del 80 al 8080:
# vi /etc/apache2/ports.conf
Y también desactiva site por defecto:
# a2dissite 000-default
Luego copia el fichero site por defecto (modifica la salida del ejemplo):
# cp /etc/apache2/sites-available/000-default.conf /etc/apache2/sites-available/ejemplo.es.conf
Edita fichero site copiado con un editor de texto:
# vi /etc/apache2/sites-available/ejemplo.es.conf
Para modificar el puerto modifica "<VirtualHost *:80>" a "<VirtualHost *:8080>" y cambia el valor de ServerName por el FQDN en cuestión:
<VirtualHost *:8080>
ServerName ejemplo.es
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html/
CacheQuickHandler off
CacheLock on
CacheLockPath /tmp/
CacheIgnoreHeaders Set-Cookie
<Location />
CacheEnable disk
CacheHeader on
CacheDefaultExpire 800
CacheMaxExpire 64000
CacheIgnoreNoLastMod On
ExpiresActive on
ExpiresDefault A300
</Location>
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
Guarda los cambios realizados, sal del editor y luego activa el site:
# a2ensite ejemplo.es.conf
Comprueba que la configuración es correcta del servicio Apache:
# apachectl -t
Y en caso positivo, recarga la configuración realizando un reinicio del servicio Apache:
# systemctl restart apache2
Luego puedes comprobar que este escuchando por el puerto modificado:
# ss -tlpn sport :8080
Y también crear un fichero de información de PHP para realizar una prueba para comprobar el FastCGI:
# echo "<?php phpinfo(); ?>" | tee /var/www/html/info.php
Instalación y configuración de Proxy Inverso con NGINX
Primero instala NGINX y Certbot para adquirir un certificado SSL con Let's Encrypt:
# apt install nginx python3-certbot-nginx
Posteriormente, crea el directorio para la cache de NGINX:
# mkdir -p /var/lib/nginx/cache && chown www-data /var/lib/nginx/cache && chmod 700 /var/lib/nginx/cache
Elimina el site por defecto:
# rm /etc/nginx/sites-enabled/default
Crea el fichero para el site que utilizarás (modifica el ejemplo):
# vi /etc/nginx/sites-available/ejemplo.es
Con el siguiente contenido (modifica el server_name de ejemplo):
proxy_cache_path /var/lib/nginx/cache levels=1:2 keys_zone=nginx_cache:8m max_size=50m;
proxy_cache_key "$scheme$request_method$host$request_uri$is_args$args";
proxy_cache_valid 200 302 10m;
proxy_cache_valid 404 1m;
server {
listen 80;
server_name ejemplo.es;
location / {
proxy_pass http://[::1]:8080;
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_set_header X-Forwarded-Proto $scheme;
proxy_cache nginx_cache;
proxy_cache_bypass $http_upgrade;
proxy_buffering on;
proxy_buffer_size 32k;
proxy_buffers 16 16k;
proxy_busy_buffers_size 32k;
proxy_max_temp_file_size 0;
proxy_temp_file_write_size 32k;
gzip on;
gzip_min_length 1000;
gzip_comp_level 5;
gzip_proxied any;
gzip_vary on;
gzip_types
text/css
text/javascript
text/xml
text/plain
text/x-component
application/javascript
application/json
application/xml
application/rss+xml
font/truetype
font/opentype
application/vnd.ms-fontobject
image/svg+xml;
add_header X-Proxy-Cache $upstream_cache_status;
add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains; preload';
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header X-Cache-Status $upstream_cache_status;
add_header X-Powered-By 'Clouding';
}
location ~ /\.ht {
deny all;
}
}
Crea un enlace simbólico del sitio disponible en el directorio de sitios activos:
# ln -s /etc/nginx/sites-available/ejemplo.es /etc/nginx/sites-enabled/ejemplo.es
Finalmente, reinicia el servicio NGINX:
# systemctl restart nginx.service
Aunque posteriormente, también puedes utilizar Certbot que anteriormente has instalado para adquirir el certificado y configurar automáticamente nginx:
# certbot --nginx --redirect -d ejemplo.es
Adicionalmente, si tienes problemas de contenido mixto puedes modificar la configuración de Apache. Para ello edita el fichero de configuración:
# vi /etc/apache2/apache2.conf
Y añade al final:
<IfModule mod_setenvif.c>
SetEnvIf X-Forwarded-Proto "^https$" HTTPS
</IfModule>
Prueba de rendimiento
Como puedes comprobar con la siguiente prueba, un servidor Plesk con la misma configuración contra un servidor configurado con estas características ofrece un mejor tiempo de respuestas.
Servidor Plesk con Proxy NGINX (cache habilitada) con PHP 7.4 servido por FastCGI con Apache:
Running 30s test @ https://plesk.ejemplo.es/info.php
12 threads and 50 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 87.18ms 93.88ms 1.49s 95.08%
Req/Sec 51.35 32.85 646.00 96.83%
17578 requests in 30.07s, 1.70GB read
Socket errors: connect 0, read 0, write 0, timeout 33
Requests/sec: 584.66
Transfer/sec: 57.87MB
Servidor configurado mediante este artículo:
Running 30s test @ https://proxy.ejemplo.es/info.php
12 threads and 50 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 59.98ms 27.89ms 1.17s 96.40%
Req/Sec 66.73 12.59 150.00 60.93%
24035 requests in 30.10s, 1.70GB read
Requests/sec: 798.56
Transfer/sec: 57.78MB
Prueba realizada con la siguiente configuración PHP en ambos servidores:
max.children 26
pm.start_servers 0
pm.min_spare_server 2
pm.max_spare_servers 8
¿Lo has probado? ¡Déjanos tus comentarios! 🙂