Saltar a contenido

3.6.-Servidor web con Nginx

3.6. Servidor web con Nginx

Idea principal

Nginx recibe peticiones HTTP, selecciona el sitio que debe atenderlas y puede servir archivos estáticos o reenviar las peticiones dinámicas a otro servicio. Una instalación básica debe dejar claro qué escucha, qué publica, dónde están los archivos y cómo se recarga la configuración.

En este punto se instala y configura un servidor web como componente de la arquitectura estudiada. La comprobación completa de funcionamiento, con un plan de pruebas y registro de incidencias, se reserva al apunte 3.8. Pruebas de funcionamiento del despliegue; aquí se prepara la configuración necesaria para poder probarla después.

La relación normativa exclusiva de este documento es:

Código Descripción
RA1 Implanta arquitecturas web analizando y aplicando criterios de funcionalidad.
CE c Se ha realizado la instalación y configuración básica de servidores web.

Qué deberías saber al terminar

Deberías poder:

  • instalar Nginx y gestionar su servicio;
  • localizar su configuración, el contenido y los registros;
  • publicar una web estática y preparar un proxy básico sin exponer más puertos de los necesarios.

Mapa del tema

Veremos el papel del servidor web, la instalación, sus archivos principales, un sitio estático y una configuración inicial de proxy.

1. Función de un servidor web

Un servidor web escucha solicitudes HTTP o HTTPS y devuelve respuestas. Puede entregar directamente recursos estáticos, como HTML, CSS, JavaScript e imágenes, que no necesitan ejecutar código en cada petición. También puede reenviar una petición dinámica a un servidor de aplicaciones, que sí debe ejecutar código para preparar la respuesta. Además, puede seleccionar el sitio según el nombre solicitado, gestionar el cifrado HTTPS mediante TLS o añadir cabeceras comunes. Cuando se dice que Nginx «termina TLS», significa que Nginx recibe y descifra la conexión HTTPS antes de reenviar la petición a otro servicio.

Servidor web

Es el software que atiende peticiones de recursos web y genera o entrega respuestas HTTP, directamente o mediante la cooperación con otros servicios.

Nginx utiliza un proceso principal que administra la configuración y procesos de trabajo que atienden las conexiones. Esta organización permite servir muchas conexiones con un consumo contenido, pero no elimina la necesidad de configurar correctamente permisos, límites, registros y actualizaciones.

flowchart LR
  C["Navegador"] -->|"HTTP :80"| N["Nginx"]
  N -->|"Archivo estático"| F["Raíz del sitio"]
  N -->|"Petición dinámica"| A["Servidor de aplicaciones"]
  N --> L["Registros de acceso y error"]
Flujo de una petición a través de Nginx
Nginx selecciona un bloque `server` y un bloque `location` para servir un archivo o reenviar la petición al backend. Los dos recorridos dejan evidencias en los registros.

1.1. Qué decide Nginx en cada petición

Cuando llega una petición, Nginx no busca automáticamente un archivo en todo el disco. Aplica su configuración en un orden que conviene saber interpretar:

  1. Comprueba la dirección y el puerto indicados por listen.
  2. Utiliza el nombre enviado en la cabecera Host para elegir el bloque server que mejor encaja con server_name.
  3. Dentro de ese bloque selecciona el location correspondiente a la ruta.
  4. Ejecuta la acción configurada: servir un recurso, redirigir, rechazar o reenviar la petición mediante proxy_pass.
  5. Escribe el resultado en los registros configurados.

Por ejemplo, una petición a http://catalogo.local/css/app.css puede ser atendida directamente desde /var/www/catalogo/css/app.css. Otra petición a /api/productos puede enviarse al backend. El navegador ve una única respuesta, pero el equipo de despliegue debe saber qué componente la ha generado.

Servidor web y servidor de aplicaciones no son sinónimos

Nginx puede servir HTML, CSS, JavaScript e imágenes, y también actuar como puerta de entrada para una aplicación. No ejecuta por sí mismo una aplicación Java, Python o PHP: para ello coopera con un servidor de aplicaciones, un runtime o un servicio como PHP-FPM.

2. Instalación y ciclo de vida

En una distribución Debian o Ubuntu, la instalación básica puede realizarse con el gestor de paquetes. Los nombres de los paquetes y las rutas pueden cambiar en otras distribuciones, por lo que conviene comprobar la documentación local.

sudo apt update
sudo apt install nginx
sudo systemctl enable --now nginx
sudo systemctl status nginx
nginx -v

enable hace que el servicio se prepare para iniciarse con el sistema y --now lo inicia en ese momento. Durante una práctica se puede utilizar start, stop, restart y reload según la operación necesaria:

sudo systemctl start nginx
sudo systemctl reload nginx
sudo systemctl restart nginx
sudo systemctl stop nginx

reload vuelve a leer la configuración sin detener normalmente las conexiones existentes. Antes de usarlo, valida siempre la sintaxis.

Si la instalación falla o el servicio no arranca, no conviene empezar modificando archivos al azar. Comprueba primero si el puerto está ocupado y consulta el motivo registrado por el servicio:

sudo ss -ltnp | grep -E ':(80|443)[[:space:]]'
sudo journalctl -u nginx --no-pager -n 50

En un equipo de prácticas puede haber otro servidor web escuchando en el puerto 80. Dos procesos no pueden reservar simultáneamente la misma combinación de dirección y puerto; hay que detener el servicio que no se vaya a utilizar o configurar conscientemente otro puerto.

3. Archivos y directorios principales

La distribución puede organizar los sitios de forma distinta, pero estas rutas son habituales en Debian y Ubuntu:

Ruta Finalidad
/etc/nginx/nginx.conf Configuración global y bloques incluidos
/etc/nginx/conf.d/ Fragmentos de configuración disponibles
/etc/nginx/sites-available/ Sitios definidos, todavía no necesariamente activos
/etc/nginx/sites-enabled/ Enlaces a los sitios activos
/var/www/html/ Contenido estático inicial
/var/log/nginx/access.log Peticiones atendidas
/var/log/nginx/error.log Errores y avisos del servidor

La configuración se organiza por contextos. El contexto principal contiene opciones globales; events regula conexiones; http contiene la configuración HTTP; server representa un sitio virtual y location define el tratamiento de una ruta. Un archivo incluido no es una configuración independiente: sus directivas pasan a formar parte del contexto desde el que se incluye.

events {
    worker_connections 1024;
}

http {
    include /etc/nginx/mime.types;
    include /etc/nginx/conf.d/*.conf;

    server {
        listen 80;

        location / {
            # El tratamiento concreto se define aquí.
        }
    }
}

En Debian y Ubuntu es habitual separar los sitios en sites-available/ y activar cada uno mediante un enlace en sites-enabled/. La imagen oficial de Nginx para Docker suele cargar directamente archivos de conf.d/. No hay que suponer una estructura por el nombre de la herramienta: hay que revisar los include reales de /etc/nginx/nginx.conf.

Para ver la configuración efectiva, incluidos los archivos que se han cargado, utiliza:

sudo nginx -T

nginx -T ayuda a descubrir un sitio duplicado, un include que no se está leyendo o el bloque que actúa como configuración predeterminada. La orden nginx -t valida; nginx -T valida y además muestra la configuración resultante, por lo que su salida puede contener rutas o nombres internos que no conviene publicar sin revisar.

El bloque server define un sitio virtual, es decir, la configuración de un sitio web concreto dentro de Nginx. Dentro de él, listen indica el puerto y server_name los nombres que debe reconocer. Un bloque location decide cómo se trata cada ruta: servir un archivo, devolver una redirección o usar proxy_pass para enviarla a otro servicio.

4. Publicar una web estática

Una configuración mínima para un sitio de catálogo puede ser:

server {
    listen 80;
    listen [::]:80;
    server_name catalogo.local;

    root /var/www/catalogo;
    index index.html;

    location / {
        try_files $uri $uri/ =404;
    }
}

El directorio debe existir y el proceso de Nginx necesita permisos de lectura:

sudo install -d -o root -g www-data -m 0755 /var/www/catalogo
sudo cp index.html /var/www/catalogo/
sudo nginx -t
sudo systemctl reload nginx

La directiva try_files evita que una ruta inexistente se convierta en un archivo inesperado. En una aplicación que utilice rutas gestionadas por el servidor de aplicaciones, la configuración deberá ser diferente y se decidirá qué prefijos son estáticos y cuáles se reenvían.

Para probar un nombre local sin desplegar DNS, añade temporalmente una entrada en el equipo cliente, por ejemplo:

127.0.0.1 catalogo.local

Después, comprueba desde el cliente que el nombre, el código y el contenido son los esperados:

curl --include --max-time 10 http://catalogo.local/
curl --include --max-time 10 http://catalogo.local/css/app.css

También puedes comprobar el Host sin modificar /etc/hosts:

curl --include --header 'Host: catalogo.local' http://127.0.0.1/

Estas pruebas distinguen un problema de resolución del nombre de un problema de configuración o de permisos. Si existen varios bloques que escuchan en el mismo puerto y ningún server_name coincide, Nginx utilizará el bloque predeterminado para esa dirección y puerto; por eso una página de bienvenida no demuestra que el sitio virtual solicitado esté bien seleccionado.

5. Preparar la cooperación con una aplicación

Nginx puede actuar como proxy inverso cuando la aplicación escucha en otro puerto. Un proxy inverso recibe la petición del cliente y la reenvía al servicio que puede atenderla; para el cliente, Nginx sigue siendo el punto de entrada. Llamaremos backend al servicio que está detrás de Nginx y ejecuta la lógica de la aplicación. El backend no tiene que publicarse en la interfaz externa si ambos servicios comparten una red interna:

server {
    listen 80;
    server_name app.local;

    location / {
        proxy_pass http://app: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;
    }
}

app debe ser un nombre resoluble desde el entorno de Nginx, por ejemplo el nombre de un servicio en una red de Compose. Esta configuración es una preparación básica: los tiempos de espera, las cabeceras de seguridad, la terminación TLS, la autenticación y el balanceo requieren un diseño posterior.

Las cabeceras reenviadas conservan información que se perdería al pasar por el proxy:

Directiva Información que conserva Uso habitual en el backend
Host $host Nombre solicitado por el cliente Generar enlaces y seleccionar el sitio
X-Real-IP $remote_addr Dirección observada por Nginx Registro o diagnóstico
X-Forwarded-For $proxy_add_x_forwarded_for Cadena de proxies Trazabilidad de la petición
X-Forwarded-Proto $scheme http o https original Generar redirecciones y enlaces correctos

El valor de proxy_pass también importa. proxy_pass http://app:8080; conserva la ruta que llega a Nginx, mientras que añadir una ruta puede sustituir parte de la URI según la posición y el contenido del location. En una primera configuración es preferible usar una regla sencilla y probar explícitamente una ruta conocida antes de combinar prefijos.

localhost cambia de significado en un contenedor

Si Nginx está dentro de un contenedor, localhost apunta a ese mismo contenedor, no al backend ni al equipo anfitrión. En una red de Compose se utiliza el nombre del servicio, como app:8080; en una instalación nativa puede ser 127.0.0.1:8080 si el backend escucha realmente en el mismo host.

5.1. Ejemplo de integración con una red de contenedores

Una topología mínima puede publicar solo Nginx y mantener el backend en la red interna:

services:
  web:
    image: nginx:1.27-alpine
    ports:
      - "127.0.0.1:8080:80"
    volumes:
      - ./default.conf:/etc/nginx/conf.d/default.conf:ro
    depends_on:
      - app

  app:
    image: tomcat:9.0
    expose:
      - "8080"

El bloque server del ejemplo anterior se guardaría como default.conf en el mismo directorio que este archivo Compose. El montaje :ro hace que Nginx lo lea sin poder modificarlo desde el contenedor.

El nombre app se resuelve en la red de Compose y expose documenta el puerto interno sin publicarlo en el host. Tomcat se utiliza aquí como backend de ejemplo; en una práctica real se sustituye por la imagen y el artefacto de la aplicación elegidos. El siguiente apunte estudia la preparación de Tomcat y la práctica de integración muestra el recorrido completo.

5.2. Configurar de forma segura y verificable

Antes de recargar, comprueba la sintaxis y guarda una copia de la configuración que se ha utilizado:

sudo nginx -t
sudo systemctl reload nginx
sudo journalctl -u nginx --since "10 minutes ago"
sudo tail -f /var/log/nginx/access.log /var/log/nginx/error.log

El comando nginx -t comprueba que la configuración es válida y que los archivos necesarios se pueden abrir. No demuestra por sí solo que la aplicación responda correctamente; ese objetivo corresponde al plan de pruebas de 3.8. Pruebas de funcionamiento del despliegue.

Una comprobación mínima debe separar tres preguntas:

Pregunta Evidencia orientativa
¿El proceso está administrado y escucha? systemctl status nginx y ss -ltnp
¿La configuración cargada es la esperada? nginx -t y nginx -T
¿La respuesta llega al cliente? curl, navegador y registros de acceso

Así se evita afirmar que la instalación funciona solo porque el servicio aparece como active (running). Las pruebas funcionales completas, incluyendo el backend, el rendimiento y la recuperación, se desarrollan en el punto 3.8. Pruebas de funcionamiento del despliegue.

6. Buenas prácticas

  • Validar antes de recargar: ejecuta nginx -t y conserva la configuración anterior para poder recuperarla.
  • Separar sitios: utiliza un bloque server y un archivo identificable por aplicación, en lugar de acumular cambios sin documentar en el archivo global.
  • Publicar lo necesario: deja los backends en la red interna cuando Nginx sea el único punto de entrada.
  • Proteger el contenido: aplica permisos de lectura mínimos y no coloques secretos dentro de la raíz pública.
  • Observar los registros: revisa acceso y error después de cada cambio relevante.
  • Separar instalación y configuración: conserva el archivo del sitio y documenta qué include lo carga, en lugar de dejar cambios sin identificar en nginx.conf.
  • Probar el nombre real: utiliza el mismo Host y el mismo protocolo que empleará el cliente; localhost puede ocultar errores de DNS, de firewall o de selección del sitio.
  • Mantener los montajes de contenedores en solo lectura: configura Nginx desde archivos versionados y no dependas de cambios manuales que desaparecerán al recrear el contenedor.
  • No confundir validación con funcionamiento: combina sintaxis, puerto, respuesta HTTP y registros para cerrar la comprobación.

7. Errores frecuentes

Error frecuente Por qué ocurre Cómo evitarlo
Editar solo nginx.conf sin revisar los include Se desconoce cómo se cargan los sitios Comprueba la configuración efectiva con nginx -T
Recargar una configuración con errores Se omite la validación previa Ejecuta nginx -t antes de reload
Dar permisos de escritura a toda la raíz web Se confunde acceso de lectura con publicación Usa propietario y grupo adecuados y permisos mínimos
Apuntar el proxy a localhost por costumbre Dentro de un contenedor localhost es el propio Nginx Usa el nombre o dirección del backend en su red
Publicar directamente el backend Se expone un punto de entrada que no necesita el cliente Publica Nginx y restringe la red interna
Crear el archivo del sitio pero no cargarlo Se desconoce la diferencia entre disponible y habilitado, o el include real Comprueba el enlace o el directorio incluido y ejecuta nginx -T
Probar solo con 127.0.0.1 Se ignoran Host, DNS y la selección del bloque server Prueba el nombre configurado o envía la cabecera Host
Cambiar proxy_pass sin comprobar la ruta La URI puede conservarse o sustituirse según el bloque Prueba una ruta concreta y documenta la forma de la directiva
Confundir reload con una prueba funcional La configuración puede ser válida aunque el backend esté caído Solicita la URL y revisa los logs después de recargar

8. Resumen

En este tema has aprendido que:

  • Nginx puede servir estáticos y actuar como punto de entrada para una aplicación dinámica;
  • la instalación incluye servicio, configuración, contenido y registros;
  • los bloques server y location determinan qué sitio y qué recurso atiende;
  • la configuración efectiva depende de los contextos y de los archivos incluidos, no solo del archivo que se haya editado;
  • un proxy inverso puede ocultar el backend y mantenerlo en una red interna, pero necesita nombres resolubles, rutas y cabeceras coherentes;
  • validar, recargar y registrar los cambios forma parte de una instalación básica responsable.

Idea clave

Un servidor web está preparado cuando se sabe qué escucha, qué publica, dónde se configura, quién puede leer sus archivos y cómo se recupera la configuración anterior.

9. Para seguir practicando

Bibliografía y fuentes

Presentación

Presentación sobre el servidor web con Nginx