Lo que necesita antes de configurar Nginx
Esta guía utiliza Ubuntu 24.04 LTS, Nginx, PHP-FPM, MariaDB y dos dominios de ejemplo: site1.com y site2.com. Reemplace estos nombres por sus dominios reales. El diseño funciona para sitios estáticos, WordPress, Laravel, aplicaciones PHP, sitios de documentación y API pequeñas.
Requisitos mínimos de producción
- CPU: 4 vCPU para varios sitios web ligeros; use núcleos físicos dedicados para tráfico sostenido o aplicaciones que consuman mucha CPU.
- Memoria: 8 GB de RAM como mínimo. Asigne más si varios sitios usan PHP, MariaDB, Redis o servicios de búsqueda.
- Almacenamiento: 100 GB de SSD NVMe como mínimo, con las copias de seguridad almacenadas por separado.
- Sistema operativo: Ubuntu 24.04 LTS con acceso root o sudo.
- Red: Una dirección IPv4 pública estática y DNS configurado correctamente.
- Acceso: Un cliente SSH y una copia local de cada sitio web.
Un VPS es suficiente para unos pocos sitios con poco tráfico, pero un servidor dedicado o bare-metal es preferible para tráfico sostenido, bases de datos grandes, aislamiento estricto o rendimiento predecible de disco y CPU. Un solo servidor también crea un único dominio de fallo, así que mantenga copias de seguridad fuera del servidor y tenga un plan de recuperación.
Planificación de capacidad de producción
Use la siguiente tabla como punto de partida para el dimensionamiento de producción; la capacidad real depende del almacenamiento en caché, el código de la aplicación, las consultas de la base de datos, los tamaños de imagen y los patrones de tráfico.
| Escala: sitios activos y carga máxima agregada | vCPU | RAM | Disco | Ancho de banda mensual |
|---|---|---|---|---|
| 5 sitios, hasta 20 solicitudes dinámicas/seg | 4 vCPU | 8 GB | 160 GB SSD NVMe | 5 TB |
| 20 sitios, hasta 100 solicitudes dinámicas/seg | 8 vCPU | 32 GB | 480 GB SSD NVMe | 15 TB |
| 50 sitios, hasta 300 solicitudes dinámicas/seg | 16 núcleos dedicados | 64 GB | 960 GB SSD NVMe con RAID1 | 30 TB |
Para tráfico sostenido, bases de datos o clientes que requieran aislamiento, elija bare metal con núcleos dedicados y almacenamiento NVMe empresarial en lugar de sobreasignar un VPS pequeño.
Paso 1: Actualice Ubuntu y cree un usuario administrativo
Conéctese mediante SSH, actualice los paquetes y cree una cuenta que no sea root. Reemplace deploy por su nombre de usuario preferido.
ssh root@SERVER_IP
apt update && apt -y full-upgrade
apt install -y sudo
adduser deploy
usermod -aG sudo deploy
Copie su clave SSH a la nueva cuenta antes de desactivar el inicio de sesión root:
ssh-copy-id deploy@SERVER_IP
ssh deploy@SERVER_IP
sudo hostnamectl set-hostname web01.example.net
Después de confirmar que el inicio de sesión basado en claves funciona, edite la configuración de SSH:
sudo nano /etc/ssh/sshd_configEstablezca PermitRootLogin no y, si todos los administradores usan claves, establezca PasswordAuthentication no. Valide y recargue:
sudo sshd -t && sudo systemctl reload ssh
Paso 2: Instale Nginx, PHP-FPM, MariaDB y herramientas de firewall
Instale la pila web y las extensiones PHP comunes. Elimine las extensiones que sus aplicaciones no necesiten.
sudo apt install -y nginx mariadb-server php-fpm php-mysql php-curl php-gd php-mbstring php-xml php-zip php-intl unzip curl ufw fail2ban
sudo systemctl enable --now nginx mariadb php8.3-fpm fail2ban
sudo mariadb-secure-installationCompruebe el socket PHP-FPM instalado porque la versión puede diferir en otra versión de Ubuntu:
ls /run/php/php*-fpm.sock
systemctl status nginx --no-pager
Permita solo los servicios públicos necesarios. SSH debe restringirse a un rango de IP de confianza cuando sea posible.
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw --force enable
sudo ufw status verbosePaso 3: Cree directorios y permisos separados
Asigne a cada sitio web su propia raíz de documentos. Mantener los sitios separados simplifica la implementación, los permisos, los registros y la migración futura.
sudo mkdir -p /var/www/site1.com/public
sudo mkdir -p /var/www/site2.com/public
sudo chown -R deploy:www-data /var/www/site1.com /var/www/site2.com
sudo find /var/www/site1.com /var/www/site2.com -type d -exec chmod 755 {} \;
sudo find /var/www/site1.com /var/www/site2.com -type f -exec chmod 644 {} \;
Cree archivos de prueba:
printf '%s\n' '<h1>site1.com funciona</h1>' | sudo tee /var/www/site1.com/public/index.html
printf '%s\n' '<h1>site2.com funciona</h1>' | sudo tee /var/www/site2.com/public/index.html
Para WordPress u otra aplicación PHP, cargue los archivos en el directorio public correspondiente y asegúrese de que solo los directorios que requieran cargas sean escribibles por el proceso web.
Paso 4: Configure los bloques de servidor de Nginx
Nginx selecciona un bloque de servidor según el nombre de host solicitado. Cree un archivo de configuración por sitio.
sudo nano /etc/nginx/sites-available/site1.comUse esta configuración para un sitio estático o PHP:
server {
listen 80;
listen [::]:80;
server_name site1.com www.site1.com;
root /var/www/site1.com/public;
index index.php index.html;
access_log /var/log/nginx/site1.access.log;
error_log /var/log/nginx/site1.error.log;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}
location ~ /\.ht {
deny all;
}
}
Cree el segundo bloque cambiando el dominio y la ruta:
sudo cp /etc/nginx/sites-available/site1.com /etc/nginx/sites-available/site2.com
sudo sed -i 's/site1\.com/site2.com/g; s#/var/www/site1.com#/var/www/site2.com#g; s#site1#site2#g' /etc/nginx/sites-available/site2.com
sudo ln -s /etc/nginx/sites-available/site1.com /etc/nginx/sites-enabled/site1.com
sudo ln -s /etc/nginx/sites-available/site2.com /etc/nginx/sites-enabled/site2.com
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t
sudo systemctl reload nginx
La regla try_files es adecuada para muchas aplicaciones con controlador frontal. Un sitio puramente estático puede usar try_files $uri $uri/ =404; en su lugar, lo que evita enviar rutas desconocidas a PHP.
Paso 5: Dirija los registros DNS al servidor dedicado
En su proveedor de DNS, cree estos registros:
- Un registro
Aparasite1.comque apunte a la dirección IPv4 del servidor. - Un registro
Aparawww.site1.comque apunte a la misma dirección, o un CNAME asite1.com. - Registros equivalentes para
site2.comywww.site2.com. - Un registro
AAAAsolo si IPv6 está configurado y probado en el servidor.
Verifique DNS antes de solicitar certificados:
sudo apt install -y dnsutils
dig +short site1.com A
dig +short site2.com A
curl -I http://site1.com
Los cambios de DNS pueden retrasarse debido a valores TTL almacenados en caché. La respuesta de dig debe contener la dirección del servidor antes de continuar.
Paso 6: Active HTTPS con Let's Encrypt
Instale Certbot y solicite un certificado que cubra tanto el dominio raíz como el nombre de host www para cada sitio.
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d site1.com -d www.site1.com
sudo certbot --nginx -d site2.com -d www.site2.com
Elija la opción de redirección cuando Certbot pregunte si HTTP debe redirigir a HTTPS. Pruebe la renovación sin cambiar los certificados activos:
sudo certbot renew --dry-run
sudo nginx -t
curl -I https://site1.com
curl -I https://site2.com
Mantenga abiertos los puertos 80 y 443 porque la renovación de certificados HTTP-01 necesita el puerto 80, a menos que use validación DNS.
Paso 7: Agregue aislamiento de PHP-FPM y usuarios de base de datos
Para varias aplicaciones PHP independientes, los pools de PHP-FPM separados reducen el acceso entre sitios y facilitan la aplicación de límites de recursos. Cree un pool para site1:
sudo nano /etc/php/8.3/fpm/pool.d/site1.conf[site1]
user = site1
group = site1
listen = /run/php/site1.sock
listen.owner = www-data
listen.group = www-data
pm = dynamic
pm.max_children = 12
pm.start_servers = 2
pm.min_spare_servers = 2
pm.max_spare_servers = 4
php_admin_value[open_basedir] = /var/www/site1.com:/tmp
Cree el usuario del sistema y repita el pool con valores específicos de site2:
sudo useradd --system --home /var/www/site1.com --shell /usr/sbin/nologin site1
sudo chown -R site1:site1 /var/www/site1.com
sudo systemctl restart php8.3-fpm
sudo systemctl status php8.3-fpm --no-pager
Cambie la línea PHP de Nginx de site1 a fastcgi_pass unix:/run/php/site1.sock;. No establezca pm.max_children demasiado alto: un punto de partida práctico es de 2 a 4 trabajadores por GB de RAM disponible para PHP; después ajústelo tras medir el uso de memoria de los trabajadores.
Cree credenciales MariaDB separadas en lugar de usar root:
sudo mariadbCREATE DATABASE site1db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'site1user'@'localhost' IDENTIFIED BY 'CHANGE_THIS_LONG_PASSWORD';
GRANT ALL PRIVILEGES ON site1db.* TO 'site1user'@'localhost';
FLUSH PRIVILEGES;
EXIT;
Paso 8: Pruebe cada sitio web y supervise los registros
Compruebe la sintaxis de configuración, el estado HTTP, el enrutamiento de host virtual, la ejecución de PHP y la renovación de certificados:
sudo nginx -t
curl -I https://site1.com
curl -I https://site2.com
curl -s https://site1.com | head
sudo tail -f /var/log/nginx/site1.access.log /var/log/nginx/site1.error.log
Pruebe el enrutamiento de nombre de host directamente contra la dirección del servidor si DNS no está listo:
curl --resolve site1.com:80:SERVER_IP http://site1.com
curl --resolve site2.com:80:SERVER_IP http://site2.com
Supervise la presión de recursos con:
free -h
uptime
df -h
sudo systemctl --failed
sudo journalctl -u nginx -u php8.3-fpm --since '1 hour ago'
Configure la rotación de registros, recopile métricas de CPU, RAM, latencia de disco, uso de disco, códigos de estado HTTP y vencimiento de certificados, y mantenga al menos una copia de seguridad fuera del servidor. Se puede crear un volcado de base de datos con:
sudo mysqldump --single-transaction site1db | gzip | sudo tee /var/backups/site1db-$(date +%F).sql.gz > /dev/nullSolución de problemas comunes
Todos los dominios muestran el mismo sitio web
Compruebe que cada server_name sea correcto, que el sitio esté habilitado y que el bloque predeterminado se haya eliminado. Ejecute sudo nginx -T y busque nombres de host duplicados.
Nginx devuelve 403 Forbidden
Confirme que la raíz de documentos existe, que los directorios tienen permiso de ejecución y que el usuario de Nginx puede recorrer la ruta:
namei -l /var/www/site1.com/public
sudo tail -n 50 /var/log/nginx/site1.error.logPHP devuelve 502 Bad Gateway
El socket de PHP-FPM puede ser incorrecto o el servicio puede estar detenido. Ejecute:
ls -l /run/php/
sudo systemctl status php8.3-fpm
sudo journalctl -u php8.3-fpm -n 50 --no-pagerCertbot no puede validar un dominio
Compruebe que DNS se resuelva a este servidor, que el puerto 80 sea accesible y que Nginx cargue el bloque de servidor correcto. Un proxy o CDN también debe reenviar correctamente las solicitudes de validación HTTP.
Un sitio consume todos los recursos
Inspeccione los registros de acceso y los trabajadores de PHP-FPM, active la caché de la aplicación, limite los tamaños de carga y reduzca los límites del pool de ese sitio. Para vecinos ruidosos o requisitos de cumplimiento, traslade la aplicación a un VPS o servidor dedicado independiente.
Recomendaciones operativas
- Use archivos de implementación controlados por versiones y pruebe los cambios de Nginx con
nginx -tantes de cada recarga. - Mantenga actualizadas las aplicaciones, los plugins, los paquetes de Ubuntu y PHP.
- Use usuarios Unix, bases de datos, registros y directorios de implementación separados para cada sitio.
- Active las copias de seguridad automatizadas y realice periódicamente una prueba de restauración completa.
- Use una CDN o almacenamiento de objetos para recursos estáticos grandes y vídeo en lugar de consumir todo el ancho de banda del servidor.
- Para correo, use un servicio o servidor independiente centrado en correo cuando la capacidad de entrega y la reputación sean críticas para el negocio.