Configuración de Nginx

Autor: Joel Barrios Dueñas
Correo electrónico: darkshram en gmail punto com
Sitio de Red: https://www.alcancelibre.org/

Licencia de este documento: Creative Commons Reconocimiento-NoComercial-CompartirIgual 2.1

© 1999-2022 Joel Barrios Dueñas. Usted es libre de copiar, distribuir y comunicar públicamente la obra y hacer obras derivadas bajo las condiciones siguientes: a) Debe reconocer y citar al autor original. b) No puede utilizar esta obra para fines comerciales (incluyendo su publicación, a través de cualquier medio, por entidades con fines de lucro). c) Si altera o transforma esta obra o genera una obra derivada, sólo puede distribuir la obra generada bajo una licencia idéntica a ésta. Al reutilizar o distribuir la obra, tiene que dejar bien claro los términos de la licencia de esta obra. Alguna de estas condiciones puede no aplicarse si se obtiene el permiso del titular de los derechos de autor. Los derechos derivados de usos legítimos u otras limitaciones no se ven afectados por lo anterior. Licencia completa en castellano. La información contenida en este documento y los derivados de éste se proporcionan tal cual son y los autores no asumirán responsabilidad alguna si el usuario o lector hace mal uso de éstos.

Temario.

  1. Instalación de Nginx en AlmaLinux/CentOS.
  2. Configuración de EPEL y Remi.
  3. Configuración de directorios virtuales.
  4. Instalación y configuración de php-fpm.
  5. Uso de múltiples versiones de PHP en el mismo servidor web.
  6. Anfitriones virtuales.
  7. Configuración de HTTPS.

Introducción.

Acerca de Nginx.

Nginx es un servidor Web y Proxy muy ligero, rápido y versátil enfocado en el alto rendimiento que permite servir miles e incluso millones de peticiones a través de los protocolos HTTP y HTTPS. Fue creado por Igor Sysoev en el año 2009, originalmente para resolver la necesidad de millones de peticiones solicitadas en el motor de búsqueda Ruso conocido como Rambler, mismas que eran un problema utilizando Apache. En el año 2021 Nginx se convirtió en el servidor Web más popular del mundo, acabando con los 25 años de reinado de Apache. Sin realizar ajustes a la configuración predeterminada, Nginx es capaz de soportar hasta 10 mil conexiones simultáneas.

Preparativos.

Instalación de herramientas y configuración de políticas de SELinux.

Acceda al sistema como root.

Habilite el almacén PowerTools ejecutando lo siguiente:

dnf -y install dnf-plugins-core && dnf config-manager --set-enabled powertools

Instale y habilite el muro cortafuegos:

dnf -y install firewalld && systemctl enable --now firewalld

Encontrará conveniente esté instalado bash-completion a fin de facilitar el uso de la consola y lynx como navegador Web para la consola a fin de poder realizar pruebas y diagnósticos.

dnf -y install bash-completion lynx

SElinux estará activo en modo forzado. Ejecute lo siguiente para habilitar la políticas necesarias para realizar los procedimientos descritos en este documento:

setsebool -P httpd_unified=1 httpd_can_network_connect=1 httpd_enable_homedirs=1 nis_enabled=1

Actualice el sistema y reinicie. Es importante trabajar con los parches correctivos y de seguridad.

dnf -y update && reboot

Instalación de paquetes.

Instalación de Nginx.

Nginx viene incluido en los almacenes de software de AlmaLinux 8, CentOS 8 y Red Hat Enterprise Linux 8. Sólo es necesario instalar del siguiente modo:

dnf -y install nginx

Ejecute lo siguiente para iniciar el servicio nginx:

systemctl enable --now nginx

Ejecute lo siguiente para abrir los puertos 80 y 443 en el muro cortafuegos:

firewall-cmd --add-service=http --permanent  
firewall-cmd --add-service=https --permanent
firewall-cmd --reload

Acceda con cualquier navegador hacia http://direccion.ip.servidor/ o bien desde la consola hacia http://localhost/ para validar que Nginx está arriba y funcionando.

Acceda con lynx hacia http://localhost/:

lynx http://localhost/

Deberá poder ver la página predeterminada de Nginx.

Instalación de PHP.

De modo predeterminado los sistemas operativos mencionados arriba sólo incluyen PHP 7.2. Dicha versión es obsoleta para la mayoría de las aplicaciones Web modernas. Es por este motivo que será importante habilitar el almacén de EPEL e instalar el almacén de Remi a fin de poder utilizar versiones de PHP más recientes.

Instale EPEL, yum-utils, vim-enhanced, nano y lynx ejecutando lo siguiente:

dnf -y install epel-release yum-utils vim-enhanced nano httpd-tools

Instale Remi ejecutando lo siguiente:

dnf -y install https://rpms.remirepo.net/enterprise/remi-release-8.rpm

Una vez instalado Remi, puede utilizar PHP en las siguientes opciones:

Algunas aplicaciones podrían presentar problemas con PHP 8.x, como ocurre con Wordpress (todas las versiones hasta el momento de redactar este documento en mayo de 2022). La recomendación es utilizar PHP 7.4. Ejecute lo siguiente para configurar que el sistema utiliza PHP 7.4:

dnf -y module reset php
dnf -y module install php:remi-7.4
dnf -y update

Ejecute lo siguiente para instalar los componentes principales de PHP:

dnf -y install php-bcmath php-cli php-dba php-enchant php-fpm php-gd php-gmp php-imap php-intl php-json php-ldap php-litespeed php-mbstring php-mysqlnd php-opcache php-pdo php-pdo-dblib php-process php-pspell php-snmp php-soap php-sodium php-tidy php-xml php-xmlrpc

A diferencia de Apache, Nginx requiere utilizar el servicio php-fpm para permitir a las aplicaciones utilizar PHP. Ejecute lo siguiente para activar el servicio:

systemctl enable --now php-fpm

Archivos de configuración y directorios.

La estructura de configuraciones para AlmaLinux, CentOS y Red Hat Enterprise Linux es muy distinta a la de Debian y Ubuntu. El directorio para los archivos de configuración de Nginx está en /etc/nginx y éste además incluye dos directorios relevantes:

El archivo /etc/nginx/nginx.conf tiene la siguiente estructura:

    ...
    # Configuración princpal de Nginx como usuario, módulos, zócalo;
    # archivo PID y otras opciones usadas por el daemon;
    # Todas terminan en punto y coma; 
    ...

http {
    ...
    # Configuración general de Nginx;  
    # Todas terminan en punto y coma; 
    ...
    include /etc/nginx/conf.d/*.conf;

    server {
        ...
        # Configuración del anfitrión virtual predeterminado;
        # Todas terminan en punto y coma;
        ...
        include /etc/nginx/default.d/*.conf
    }
}

Es decir, si se requiere añadir alguna opción que aplique a la configuración general o crear un nuevo anfitrión virtual, sólo es necesario crear un archivo con extensión *.conf dentro de /etc/nginx/conf.d.

Para añadir configuraciones para el anfitrión virtual predeterminado, sólo es necesario crear un archivo con extensión *.conf dentro de /etc/nginx/default.d.

Procedimientos.

Ajustes de seguridad recomendados.

Nginx viene configurado de modo predeterminado con opciones básicas que cumplen con lo necesario para uso general. En la actualidad hay muchas amenazas en Internet que se ejecutan principalmente en los navegadores y que pueden ser mitigadas fácilmente desde el servidor Web.

Encabezados recomendados.

Para añadir un encabezado sólo es necesario utilizar la opción add_header con los valores deseados y el parámetro always para asegurar que los encabezados sean establecidos en todas las respuestas.

Una de las amenazas más comunes es el abuso de los marcos internos (etiquetas HTML <frame> e <iframe>), debido a que éstos permiten mostrar en cualquier servidor ilegítimo el contenido de otro sitio Web legítimo. Utilizando X-Frame-Options con el valor SAMEORIGINse puede impedir que otro sitio Web use el contenido de un sitio legítimo en otro servidor.

Utilizando X-XSS-Protection con los valores 1; mode=block se puede forzar a que los navegadores activen la protección contra a ejecución cruzada de programas (Cross Site Scripting o XSS).

Puede complementar la opción anterior con Content-Security-Policy para generar una lista blanca de contenidos remotos a ser utilizados en un sitio web. Si añade la opción Content-Security-Policy con el valor default-src 'self', sólo se permitirá cargar contenidos del mismo sitio y bloquea la carga de contenidos remotos. Si necesita cargar contenidos remotos, puede añadir los URL de origen de los contenidos remotos utilizados, como por ejemplo https://code.jquery.com o https://cdnjs.cloudflare.com o https://analytics.google.com. Debe poner entre comillas desde default-src hasta casi el final de la línea, antes del punto y coma. Considere que si la plantilla o el sitio Web incluye componentes remotos que sean omitidos de la lista, Content-Security-Policy impedirá acceder al sitio.

Utilizando X-Content-Type-Options con el valor nosniffse puede impedir que el servidor Web permita examinar las vulnerabilidades de contenidos mime.

El encabezado Strict-Transport-Security se utiliza para definir que sitio Web se debe acceder a través del protocolo HTTPS en lugar de HTTP. Este encabezado sólo se debe utilizar en sitios que ya han sido configurados para funcionar por HTTPS.

Ejecute lo siguiente para generar el siguiente archivo /etc/nginx/default.d/headers.conf:

vim /etc/nginx/default.d/headers.conf

Añada el siguiente contenido:

add_header X-Frame-Options "SAMEORIGIN" always;
add_header Content-Security-Policy: "default-src 'self' https://code.jquery.com https://cdnjs.cloudflare.com https://analytics.google.com";
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;

Guarde los cambios y reinicie Nginx ejecutando lo siguiente:

systemctl restart nginx

Errores más comunes por los que puede fallarlo anterior y los siguientes procedimientos:

a. Omitió poner un punto y coma al final de una línea. b. Escribió incorrectamente alguna opción, valor o parámetro. c. Omitió una línea.

Configuraciones adicionales recomendadas.

Es común que los registros de cualquier servidor Web crezcan considerablemente y se dificulte el diagnóstico de problemas. Puede crear un archivo para ser incluido automáticamente en el anfitrión virtual que establezca algunas acciones con algunos tipos de contenidos.

Ejecute lo siguiente para crear el archivo /etc/nginx/default.d/common-configs.conf:

vim /etc/nginx/default.d/common-configs.conf

Añada el siguiente contenido:

    # Denegar el acceso a cualquier archivo .ht* o .git*, aunque no los use
    # Nginx.
    location ~/\.(ht|git) {
        deny all;
    }
    # Establecer el tipo mime predeterminado para el directorio /.well-known
    location '/.well-known' {
        default_type "text/plain";
    }
    # Indicar a los servidores cache que este tipo de contenidos expiran a los 14 días
    location ~* \.(js|css|png|jpg|jpeg|gif|swf|xml|txt)$ {
        expires 14d;
    }
    # Si olvidamos poner un archivo favicon.ico, indicar a Nginx que omita registrar
    # la actividad relacionada con este archivo y además indicar a los servidores
    # cache que este archivo expira al año.
    location = /favicon.ico {
        log_not_found off;
        access_log off;
        expires 1y;
    }
    # Si olvidamos poner un archivo robots.txt, indicar a Nginx que omita registrar
    # la actividad relacionada con este archivo.
    location = /robots.txt {
        log_not_found off;
        access_log off;
    }

Guarde los cambios y reinicie Nginx ejecutando lo siguiente:

systemctl restart nginx

Todo lo anterior aplicará exclusivamente para el anfitrión virtual predeterminado. Si se quiere re-utilizar esta misma configuración en otros anfitriones virtuales, es posible hacerlo a través de una inclusión de este archivo en la configuración correspondiente.

Compresión Gzip.

Habilitar la compresión gzip contribuye a optimizar el uso del ancho banda disponible a realizar una compresión al vuelo de ciertos contenidos.

Genere el archivo /etc/nginx/default.d/gzip.conf:

vim /etc/nginx/default.d/gzip.conf

Añada el siguiente contenido:

# Activar el soporte de compresión gzip
gzip on;
# Activar para archivos que tengan o no compresión gzip
gzip_vary on; 
# Comprimir sólo archivos de al menos 1024 bytes. Con archivos
# menores hay pocos pocos beneficios y elevaría innecesariamente
# el uso del CPU y memoria.
gzip_min_length 1024; 
# Activar compresión para conexiones a través de proxy
gzip_proxied expired no-cache no-store private auth; 
# Tipos específicos de archivos a comprimir
gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml; 
# Desactivar para MS Internet Explorer
gzip_disable "MSIE [1-6]\.";

Al igual que las configuraciones adicionales recomendadas, todo lo anterior aplicará exclusivamente para el anfitrión virtual predeterminado. Si se quiere re-utilizar esta misma configuración en otros anfitriones virtuales, es posible hacerlo a través de una inclusión de este archivo en la configuración correspondiente.

Directorios virtuales.

Sí se tiene una carpeta hipotética en la ruta /var/www/aplicaciones/prueba, ésta se puede compartir de dos maneras:

location = /prueba {
    # Ruta absoluta de la carpeta en el sistema de archivos:
    alias /var/www/aplicaciones/prueba;
}

location /prueba {
    # /prueba es relativo a esta carpeta en sistema de archivos:
    root /var/www/aplicaciones;
}

La configuración de directorios virtuales tiene la siguiente estructura:

location = /directorio {
    alias /var/www/carpeta;
}

O bien:

location /directorio {
    # Se asume existe /var/www/directorio
    root /var/www;
}

El parámetro location requiere como argumento el nombre del URI a mostrar desde el navegador y opcionalmente permite utilizar los siguientes prefijos:

El parámetro alias se utiliza para definir una carpeta cuyo nombre es diferente al directorio definido en location. Ejemplo:

location /images {
    alias /var/www/estaticos/imagenes;
}

El parámetro root debe corresponder a la carpeta inmediata superior a la carpeta a utilizar. Se prefiere sobre alias cuando el nombre del directorio del URI coincide con el nombre de la carpeta en sistema de archivos. Ejemplo:

location /datos {
    root /var/www/estaticos;
}

Se recomienda utilizar root cuando el nombre de la carpeta definida en location coincide con la carpeta en el sistema de archivos.

Ejecute lo siguiente para generar una carpeta en el sistema de archivos denominada /var/www/estaticos/datos:

mkdir -p /var/www/estaticos/datos

Ejecute lo siguiente para crear el archivo /etc/nginx/default.d/estaticos.conf:

vim /etc/nginx/default.d/estaticos.conf

Añada el siguiente contenido:

location /datos {
    root /var/www/estaticos;
}

Guarde los cambios, salga del editor de texto y ejecute lo siguiente para aplicar los cambios en Nginx:

systemctl reload nginx

Acceda con lynx hacia http://localhost/datos/:

lynx http://localhost/datos/

El servidor le indicará que la carpeta existe, pero que está prohibido el acceso.

Para mostrar el contenido de un carpeta, es necesario definir el archivo índice y colocar un archivo index.html o bien configurar la carpeta para mostrar contenido.

Ejecute lo siguiente para volver a editar el archivo /etc/nginx/default.d/estaticos.conf:

vim /etc/nginx/default.d/estaticos.conf

Modifique el contenido del siguiente modo:

location /datos {
    root /var/www/estaticos;
    autoindex on;
}

Guarde los cambios, salga del editor de texto y ejecute lo siguiente para aplicar los cambios en Nginx:

systemctl reload nginx

Acceda nuevamente con lynx hacia http://localhost/datos/:

lynx http://localhost/datos/

El servidor deberá permitir ver el contenido de la carpeta.

Ejecute lo siguiente para crear el archivo /var/www/estaticos/datos/index.html:

vim /var/www/estaticos/datos/index.html

Añada el siguiente contenido:

<!DOCTYPE html>
<html>
  <head>
    <title>Hola mundo.</title>
  </head>
  <body>
    <h1>Hola mundo</h1>
    <p>Hola mundo</p>
  </body>
</html>

Ejecute lo siguiente para volver a editar el archivo /etc/nginx/default.d/estaticos.conf:

vim /etc/nginx/default.d/estaticos.conf

Quite autoindex on; y añada index index.html index.htm; en su lugar:

location /datos {
    root /var/www/estaticos;
    index index.html index.htm;
}

Guarde los cambios, salga del editor de texto y ejecute lo siguiente para aplicar los cambios en Nginx:

systemctl reload nginx

Acceda nuevamente con lynx hacia http://localhost/datos/:

lynx http://localhost/datos/

El servidor deberá mostrar el documento HTML que se configuró como índice del directorio.

Directorios virtuales con autenticación.

Ejecute lo siguiente para crear una carpeta denominada /var/www/estaticos/privado:

mkdir -p /var/www/estaticos/privado

Ejecute lo siguiente para crear un archivo de contraseñas con el usuario tudominio:

htpasswd -c /var/www/estaticos/.htpasswd tudominio

Ejecute lo siguiente para hacer propiedad de Nginx el archivo de contraseñas:

chown nginx:nginx /var/www/estaticos/.htpasswd

Ejecute lo siguiente para hacer que sólo Nginx pueda acceder al archivo de contraseñas:

chmod 640 /var/www/estaticos/.htpasswd

Edite nuevamente el archivo /etc/nginx/default.d/estaticos.conf:

vim /etc/nginx/default.d/estaticos.conf

Añada el siguiente contenido:

location /privado {
    root /var/www/estaticos;
    auth_basic "Acceso restringido";
    auth_basic_user_file /var/www/estaticos/.htpasswd;
    autoindex on;
}

Guarde los cambios, salga del editor de texto y ejecute lo siguiente para aplicar los cambios en Nginx:

systemctl reload nginx

Acceda con lynx hacia http://localhost/privado/:

lynx http://localhost/privado/

Navegador deberá solicitar un usuario (tudominio) y contraseña para acceder al directorio.

Soporte para PHP.

Nginx requiere utilizar php-fpm para permitir la ejecución de programas escritor en PHP. De modo predeterminado php-fpm crea un zócalo como /run/php-fpm/www.sock con permisos de acceso exclusivamente a Apache y Nginx.

Ejecute lo siguiente para crear una estructura de carpetas para una aplicación PHP hipotética:

mkdir -p /var/www/aplicaciones/aplicacion1/{cache,config,tmp}

Los contenidos de la carpeta donde se instale la aplicación PHP que requieran acceso de escritura o estén restringidos deben pertenecer al usuario y grupo apache. Ejecute lo siguiente para establecer los directorios que deben pertenecer al usuario y grupo apache:

chown apache:apache /var/www/aplicaciones/aplicacion1/{cache,config,tmp}

Ejecute lo siguiente para crear el archivo /var/www/aplicaciones/aplicacion1/index.php:

vim /var/www/aplicaciones/aplicacion1/index.php

Añada el siguiente contenido:

<!DOCTYPE html>
<html>
  <head>
    <title>Aplicaci&oacute;n 1</title>
  </head>
  <body>
    <h1>
<?php
    echo 'Aplicaci&oacute;n 1';
?>
    </h1>
    <p>
<?php
    echo 'Esta es la aplicaci&oacute;n 1';
?>
    </p>

    <hr>

<?php
  phpinfo(INFO_GENERAL);
?>
  </body>
</html>

Ejecute lo siguiente para crear el archivo /etc/nginx/default.d/aplicaciones.conf:

vim /etc/nginx/default.d/aplicaciones.conf

Añada el siguiente contenido para la primera aplicación, donde client_max_body_size deberá tener el mismo valor de post_max_size y upload_max_filesize (128M) a fin de permitir gestionar archivos de hasta 128 MiB:

location /aplicacion1 {
    root /var/www/aplicaciones;
    index index.html index.htm index.php;
    client_max_body_size 128M;
    # Si requiere reescribir el URI para activar el soporte de
    # 'URLs bonitos' en aplicaciones como Wordpress, descomente
    # la siguiente línea.
    # try_files $uri $uri/ /aplicacion1/index.php?$query_string;
    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PHP_VALUE "upload_max_filesize=128M \n post_max_size=128M \n date.timezone=America/Mexico_City";
        fastcgi_pass  unix:/run/php-fpm/www.sock;
        }
}

Nginx carece de soporte para archivos .htaccess. Si requiere añadir variables de PHP, puede hacerlo del mismo modo que se muestra en el ejemplo anterior en una lista separada por espacios y nuevas líneas en secuencia de escape.

Guarde los cambios, salga del editor de texto y ejecute lo siguiente para aplicar los cambios en Nginx:

systemctl reload nginx

Acceda con lynx hacia http://localhost/aplicacion1/:

lynx http://localhost/aplicacion1/

Deberá mostrarse el contenido generado con PHP y validar al mismo tiempo la versión y variables de PHP. Posteriormente considere eliminar la función phpinfo() del código a fin de evitar incidentes de seguridad. Esta información jamás debe estar a la vista del público en general.

Múltiples versiones de PHP al mismo tiempo.

Ejecute lo siguiente para instalar PHP 5.6 en paralelo con PHP 7.4.

dnf -y install php56-php-fpm php56-php-bcmath php56-php-cli php56-php-dba php56-php-mbstring php56-php-xml php56-php-cli php56-php-mysqlnd

Puede instalar otros paquete de PHP 5.6 si así lo requiere. Éstos tendrán el mismo patrón de nombres que los paquetes de PHP 7.4, pero con el prefijo "php56-" como se muestra arriba.

De modo predeterminado el archivo de la instancia predeterminada de php-fpm para PHP 5.6 sólo permite a Apache utilizar dicha instancia.

Edite el archivo /etc/opt/remi/php56/php-fpm.d/www.conf:

vim /etc/opt/remi/php56/php-fpm.d/www.conf

Localice la línea correspondiente a listen.acl_users = apache y añada a nginx a la lista:

listen.acl_users = apache,nginx

Ejecute lo siguiente para iniciar el servicio php56-php-fpm:

systemctl enable --now php56-php-fpm

De modo predeterminado php56-php-fpm crea un zócalo como /var/opt/remi/php56/run/php-fpm/www.sock con permisos de acceso exclusivamente a Apache y Nginx.

Ejecute lo siguiente para crear una estructura carpetas para una segunda aplicación PHP hipotética:

mkdir -p /var/www/aplicaciones/aplicacion2/{config,cache,tmp}

Igualmente, los contenidos de la carpeta donde se instale la aplicación PHP que requieran acceso de escritura o estén restringidos deben pertenecer al usuario y grupo apache. Ejecute lo siguiente para establecer los directorios que deben pertenecer al usuario y grupo apache:

chown apache:apache /var/www/aplicaciones/aplicacion2/{config,cache,tmp}

Ejecute lo siguiente para crear el archivo /var/www/aplicaciones/aplicacion2/index.php:

vim /var/www/aplicaciones/aplicacion2/index.php

Añada el siguiente contenido:

<!DOCTYPE html>
<html>
  <head>
    <title>Aplicaci&oacute;n 2</title>
  </head>
  <body>
    <h1>
<?php
    echo 'Aplicaci&oacute;n 2';
?>
    </h1>
    <p>
<?php
    echo 'Esta es la aplicaci&oacute;n 2';
?>
    </p>

    <hr>

<?php
  phpinfo(INFO_GENERAL);
?>
  </body>
</html>

Ejecute lo siguiente para editar de nuevo el archivo /etc/nginx/default.d/aplicaciones.conf:

vim /etc/nginx/default.d/aplicaciones.conf

Añada el siguiente contenido para la primera aplicación, donde client_max_body_size deberá tener el mismo valor de las variables de PHP post_max_size y upload_max_filesize (64M) a fin de permitir gestionar archivos de hasta 64 MiB:

location /aplicacion2 {
    root /var/www/aplicaciones;
    index index.html index.htm index.php;
    client_max_body_size 64m;
    # Si requiere reescribir el URI para activar el soporte de
    # 'URLs bonitos' en aplicaciones como Wordpress, descomente
    # la siguiente línea.
    # try_files $uri $uri/ /aplicacion2/index.php?$query_string;
    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PHP_VALUE "upload_max_filesize=64M \n post_max_size=64M \n date.timezone=America/Mexico_City";
        fastcgi_pass  unix:/var/opt/remi/php56/run/php-fpm/www.sock;                        
        }
}

Guarde los cambios, salga del editor de texto y ejecute lo siguiente para aplicar los cambios en Nginx:

systemctl reload nginx

Acceda con lynx hacia http://localhost/aplicacion2/:

lynx http://localhost/aplicacion2/

Deberá mostrarse el contenido generado con PHP y validar al mismo tiempo la versión y variables de PHP. Igualmente que con el ejemplo anterior, posteriormente considere eliminar la función phpinfo() del código a fin de evitar incidentes de seguridad.

Anfitriones virtuales.

Nginx permite gestionar múltiples anfitriones virtuales de manera similar a cómo lo hace Apache. Si los anfitriones virtuales serán administrado exclusivamente por root, la configuración de PHP será igual a la que se ha mostrado hasta ahora. Si se requiere que los anfitriones virtuales sean administrados por usuarios regulares, se requiere configurar una instancia de php-fpm ejecutada por el usuario correspondiente. Se requerirá lo siguiente para realizar el procedimiento de anfitriones virtuales:

  1. Nombre de anfitrión debe ser un FQDN.
  2. Debe estar resuelto en un servidor DNS o al menos en el archivo /etc/hosts del sistema donde se va a configurar.
  3. Crear un usuario regular.
  4. Cambiar el permiso de la carpeta de inicio del usuario a fin de permitir a Nginx acceder a ésta.
  5. Crear una estructura de directorios que serán utilizados por Nginx y php-fpm.

Defina el nombre de anfitrión. Éste deberá estar asociado a la dirección IP del servidor que hospeda Nginx.

Edite el archivo /etc/hosts:

vim /etc/hosts

Encontrará el siguiente contenido:

127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6

Añada debajo de lo anterior la dirección IP del servidor, seguido de la lista separada por tabuladores con los nombres que en adelante estarán asociados a la dirección IP:

127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.1.2    www.tudominio.net    tudominio.net

Guarde los cambios y salga del editor de texto.

Valide que lo anterior funciona ejecutando lo siguiente:

ping -c3 www.tudominio.net

Lo anterior deberá devolver una salida similar a la siguiente:

PING www.tudominio.net (192.168.1.2) 56(84) bytes of data.
64 bytes from www.tudominio.net (192.168.1.2): icmp_seq=1 ttl=64 time=0.042 ms
64 bytes from www.tudominio.net (192.168.1.2): icmp_seq=2 ttl=64 time=0.060 ms
64 bytes from www.tudominio.net (192.168.1.2): icmp_seq=3 ttl=64 time=0.061 ms

--- mirror0.alcancelibre.org ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 57ms
rtt min/avg/max/mdev = 0.042/0.054/0.061/0.010 ms

NOTA: Si es posible, solicite además resolver el nombre de anfitrión en un servidor DNS. Si lo anterior es imposible por limitaciones de infraestructura y quiere poder visualizar los ejemplos descritos en este documento desde su sistema, edite en Windows el archivo C:\Windows\System32\drivers\etc\hosts y añada un registros igual al que añadió en el servidor.

Ejecute lo siguiente para crear un usuario regular que será designado como administrador de un anfitrión virtual:

useradd -c "Administrador de Fulano" tudominio

Ejecute lo siguiente para asignar contraseña al nuevo usuario:

passwd tudominio

Ejecute lo siguiente para cambiar el permiso de acceso de la carpeta de inicio del usuario a fin de permitir que Nginx pueda acceder a ésta:

chmod 755 /home/tudominio

Se requerirá que este usuario tenga la siguiente estructura de carpetas:

/home/tudominio
    public_html
    logs
    tmp

Ejecute lo siguiente para generar esta estructura de carpetas:

mkdir -p /home/tudominio/{public_html,logs,tmp}

Ejecute lo siguiente para cambiar los atributos de pertenencia de estas nuevas carpetas para correspondan a los del usuario:

chown tudominio:tudominio /home/tudominio/{public_html,logs,tmp}

Ejecute lo siguiente para cambiar los contextos de SElinux a los que corresponden:

restorecon -Rv /home/tudominio

Ejecute lo siguiente para crear el archivo /home/tudominio/public_html/index.php:

vim /home/tudominio/public_html/index.php

Añada el siguiente contenido:

<!DOCTYPE html>
<html>
  <head>
    <title>Sitio Web de Fulano</title>
  </head>
  <body>
    <h1>
<?php
    echo 'Fulano';
?>
    </h1>
    <p>
<?php
    echo 'Esta es el sitio Web de Fulano';
?>
    </p>
  </body>
</html>

Ejecute lo siguiente para ver la configuración limpia predeterminada de php-fpm:

cat /etc/php-fpm.d/www.conf |grep -v ^$ |grep -v ^\;

Lo anterior mostrará un contenido similar al siguiente:

[www]
user = apache
group = apache
listen = /run/php-fpm/www.sock
listen.acl_users = apache,nginx
listen.allowed_clients = 127.0.0.1
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35
slowlog = /var/log/php-fpm/www-slow.log
php_admin_value[error_log] = /var/log/php-fpm/www-error.log
php_admin_flag[log_errors] = on
php_value[session.save_handler] = files
php_value[session.save_path]    = /var/lib/php/session
php_value[soap.wsdl_cache_dir]  = /var/lib/php/wsdlcache

Algunos de los valores mostrados arriba sólo pueden ser utilizados si php-fpm es ejecutado con el usuario y grupo apache. Si copia esta configuración, el usuario regular no dispondrá de los privilegios necesarios para utilizar el zócalo de php-fpm y registros. Los usuarios regulares sólo pueden acceder a las instancias de php-fpm utilizando un puerto en el anfitrión local.

Ejecute lo siguiente para generar una configuración de php-fpm que se ejecutará en paralelo con la predeterminada:

vim /etc/php-fpm.d/tudominio.conf

Añada el siguiente contenido simplificado que será el más adecuado para permitir sea ejecutado por el usuario regular:

[tudominio]
user = tudominio
group = tudominio
listen = 127.0.0.1:8001
pm = dynamic
pm.max_children = 9999
pm.start_servers = 1
pm.min_spare_servers = 1
pm.max_spare_servers = 5
php_admin_value[upload_tmp_dir] = /home/tudominio/tmp
php_admin_value[session.save_path] = /home/tudominio/tmp
php_value[date.timezone] = America/Mexico_City

La configuración establece al usuario y grupo tudominios como los utilizados para ejecutar esta instancia en particular de php-fpm utilizando el puerto 8001 en el anfitrión local. Define además una carpeta donde el usuario tiene privilegios para ser utilizado como carpeta temporal para subir archivos y para almacenar datos temporales de la sesión.

Como puede observar, también puede añadir aquí mismo variables de PHP con los valores que necesite. Es mucho mas eficiente hacerlo aquí que en la configuración de Nginx. Sin embargo, puede configurar indistintamente las variables de PHP en uno u otro servicio.

De modo predeterminado SELinux sólo permite trabajar al servicio php-fpm en el puerto 9000. Ejecute lo siguiente para autorizar en SELinux que php-fpm pueda utilizar el puerto 8001:

semanage port -a -t http_port_t -p tcp 8001

Ejecute lo siguiente para reiniciar el servicio php-fpm:

systemctl restart php-fpm

En adelante podrá utilizar esta nueva instancia del servicio php-fpm en 127.0.0.1:8001 en cualquier configuración donde se requieran privilegios para el usuario específico en la misma configuración.

Ejecute lo siguiente para crear el archivo donde se configurarán los nuevos anfitriones virtuales del servidor:

vim /etc/nginx/conf.d/virtualhosts.conf

Añada el siguiente contenido:

server {
    listen 192.168.1.2;
    server_name www.tudominio.net tudominio.net;
    access_log /var/log/nginx/tudominio-access_log main;
    error_log /var/log/nginx/tudominio-error_log notice;
    root /home/tudominio/public_html;
    client_max_body_size 64M;
    # Puede reutilizar los archivos dentro de /etc/nginx/default.d
    # para ahorrar trabajo.
    include /etc/nginx/default.d/headers.conf;
    include /etc/nginx/default.d/common-configs.conf;
    include /etc/nginx/default.d/gzip.conf;
    location / {
        index index.html index.htm index.php;
        # Si requiere reescribir el URI para activar el soporte de
        # 'URLs bonitos' en aplicaciones como Wordpress, descomente
        # la siguiente línea.
        # try_files $uri $uri/ /index.php?$query_string;
        location ~ \.php$ {
            try_files $uri =404;
            fastcgi_intercept_errors on;
            include fastcgi_params;
            fastcgi_param SERVER_NAME $host;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            fastcgi_pass 127.0.0.1:8001;
            fastcgi_param PHP_VALUE "upload_max_filesize=64M \n post_max_size=64M";
            fastcgi_index index.php;
        }
    }
}

Igualmente que con ejemplos anteriores, el valor de client_max_body_size debe ser el mismo de las variables de PHP memory_limit y upload_max_filesize (64M) a fin de permitir gestionar archivos de hasta 64 MiB.

Guarde los cambios, salga del editor de texto y ejecute lo siguiente para aplicar los cambios en Nginx:

systemctl reload nginx

Desde el mismo servidor acceda con lynx hacia http://www.tudominio.net/:

lynx http://www.tudominio.net/

Deberá mostrarse el nuevo anfitrión virtual y contenido generado con PHP. Si desea visualizar este anfitrión virtual desde otro sistema, es necesario exista un registro en la zona de DNS correspondiente resolviendo el nombre del anfitrión virtual apuntando a la dirección IP del servidor.

Puede generar cuanto sitios virtuales como considere necesarios. Cada uno se sugiere esté asignado a un usuario en particular y utilizando su propia instancia de php-fpm.

Soporte para HTTPS.

Certificados auto-firmados.

Ejecute lo siguiente para genera un certificado auto-firmado provisional con firma de 4096 bits:

openssl req -newkey rsa:4096 -x509 -sha256 -days 365 -nodes -out /etc/pki/tls/certs/servidor.crt -keyout /etc/pki/tls/private/servidor.key

Lo anterior le solicitará ingresar los datos estándar de un certificado, como son el código del país, estado, ciudad, empresa, unidad o departamento, nombre de anfitrión para el certificado (www.tudominio.net si sigue el ejemplo de este documento) y una cuenta de correo electrónico.

Ejecute lo siguiente para crear el archivo donde se configurarán los nuevos anfitriones virtuales del servidor:

vim /etc/nginx/conf.d/virtualhosts.conf

En la configuración del anfitrión virtual debe añadir el siguiente esquema:

server {
    listen 443 http2 ssl;
    ssl_certificate /ruta/del/archivo/del/certificado.crt;
    ssl_certificate_key /ruta/del/archivo/de/firma.key;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers off;
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    ...
}

Siendo así, la configuración sería similar a la siguiente:

# Redireccionar todo tráfico de puerto 80 para este anfitrión virtual
# hacia https.
server {
    if ($host = www.tudominio.net) {
        return 301 https://$host$request_uri;
    }
    if ($host = tudominio.net) {
        return 301 https://$host$request_uri;
    }
    listen 80;
    server_name www.tudominio.net tudominio.net;
    return 404;
}
# Se convierte a https el antiguo sitio en http.
server {
    listen 443 http2 ssl;
    ssl_certificate /etc/pki/tls/certs/servidor.crt;
    ssl_certificate_key /etc/pki/tls/private/servidor.key;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers off;
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    server_name www.tudominio.net tudominio.net;
    access_log /var/log/nginx/tudominio-access_log main;
    error_log /var/log/nginx/tudominio-error_log notice;
    root /home/tudominio/public_html;
    client_max_body_size 64M;
    # Puede reutilizar los archivos dentro de /etc/nginx/default.d
    # para ahorrar trabajo.
    include /etc/nginx/default.d/headers.conf;
    include /etc/nginx/default.d/common-configs.conf;
    include /etc/nginx/default.d/gzip.conf;
    location / {
        index index.html index.html index.php;
        # Si requiere reescribir el URI para activar el soporte de
        # 'URLs bonitos' en aplicaciones como Wordpress, descomente
        # la siguiente línea.
        # try_files $uri $uri/ /index.php?$query_string;
        location ~ \.php$ {
            try_files $uri =404;
            fastcgi_intercept_errors on;
            include fastcgi_params;
            fastcgi_param SERVER_NAME $host;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            fastcgi_pass 127.0.0.1:8001;
            fastcgi_param PHP_VALUE "upload_max_filesize=64M \n post_max_size=64M";
            fastcgi_index index.php;
        }
    }
}

Guarde los cambios, salga del editor de texto y ejecute lo siguiente para aplicar los cambios en Nginx:

systemctl reload nginx

Desde el mismo servidor acceda con lynx hacia https://www.tudominio.net/:

lynx https://www.tudominio.net/

Deberá mostrarse el anfitrión virtual a través de HTTPS mostrando una advertencia de certificado auto-firmado.

Certificados de Let's Encrypt.

Instale certbot y su complemento para Nginx:

dnf -y install certbot python3-certbot-nginx

Si dispone de una dirección IP pública fija y un registro de DNS para el dominio a utilizar, puede ejecutar lo siguiente para generar un certificado válido de Let's Encrypt:

certbot --nginx --agree-tos -d www.tudominio.net -d tudominio.net

Lo anterior le solicitará proporcionar una cuenta de correo electrónico válida y realizará automáticamente todos los cambios pertinentes requeridos en la configuración del anfitrión virtual en el archivo donde esté configurado (/etc/nginx/conf.d/virtualhosts.conf). Es requisito que los dominios a registrar estén resueltos en un DNS y que estén definidos como valor de server_name en el anfitrión virtual.

Asumiendo que lo anterior tuvo éxito, ejecute lo siguiente para habilitar el servicio que se encargará de renovar automáticamente el certificado cuando sea necesario:

systemctl enable --now certbot-renew.timer