Instalar Strapi en Rocky Linux 9 con Nginx y PM2
Descripción rápida
Strapi es un CMS sin cabeza (headless) de código abierto construido en JavaScript. No incluye frontend por defecto; expone una API que permite crear sitios con frameworks como React o Next.js. Su panel de administración y la API son extensibles mediante plugins, y ofrece control detallado de permisos de usuarios.
Imagen introductoria: 
Alt: Diagrama de arquitectura con Strapi, base de datos y proxy inverso Nginx
Variantes de búsqueda útiles
- instalar Strapi en Rocky Linux
- Strapi con PostgreSQL y Nginx
- desplegar Strapi en producción
- Strapi PM2 Nginx SSL
Requisitos previos
- Un servidor con Rocky Linux 9, mínimo 2 GB RAM y 1 vCPU.
- Un usuario no root con privilegios sudo.
- Un nombre de dominio totalmente cualificado (FQDN), por ejemplo
strapi.example.com. - Sistema actualizado y paquetes básicos instalados.
Ejecuta actualización del sistema:
$ sudo dnf updateInstala utilidades necesarias:
$ sudo dnf install wget curl nano unzip yum-utils -yAlgunas pueden ya estar presentes.
Resumen de la metodología (mini-methodology)
- Abrir puertos y configurar FirewallD.
- Instalar y configurar PostgreSQL 15.
- Instalar Node.js LTS (v18) y crear el proyecto Strapi.
- Ejecutar Strapi en producción con PM2.
- Instalar Nginx como proxy inverso y obtener SSL con Certbot.
- Aplicar endurecimiento básico de seguridad y rutinas de backup.
1. Configurar el cortafuegos
Rocky Linux usa Firewalld. Comprueba el estado:
$ sudo firewall-cmd --state
runningLista los servicios permitidos en la zona pública (por defecto):
$ sudo firewall-cmd --permanent --list-servicesSalida esperada (ejemplo):
cockpit dhcpv6-client sshPermite HTTP y HTTPS:
$ sudo firewall-cmd --permanent --add-service=http
$ sudo firewall-cmd --permanent --add-service=https
$ sudo firewall-cmd --reloadVerifica de nuevo:
$ sudo firewall-cmd --permanent --list-servicesSalida esperada:
cockpit dhcpv6-client http https sshImportante: Evita exponer puertos de administración (p. ej. 1337) al público en producción. Usa Nginx para proxy y TLS.
2. Instalar y configurar PostgreSQL
Strapi funciona con PostgreSQL 11+. Usaremos PostgreSQL 15.
Añade la clave GPG del repositorio y el repositorio:
$ curl https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor | sudo tee /usr/share/keyrings/postgresql-key.gpg >/dev/null
$ sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-9-x86_64/pgdg-redhat-repo-latest.noarch.rpmDeshabilita el módulo integrado y instala PostgreSQL 15:
$ sudo dnf -qy module disable postgresql
$ sudo dnf install -y postgresql15-serverInicializa, habilita y arranca el servicio:
$ sudo /usr/pgsql-15/bin/postgresql-15-setup initdb
$ sudo systemctl enable postgresql-15
$ sudo systemctl start postgresql-15
$ sudo systemctl status postgresql-15Salida de ejemplo del estado del servicio (no modifiques):
? postgresql-15.service - PostgreSQL 15 database server
Loaded: loaded (/usr/lib/systemd/system/postgresql-15.service; enabled; vendor preset: disabled)
Active: active (running) since Wed 2023-02-01 13:21:27 UTC; 41min ago
Docs: https://www.postgresql.org/docs/15/static/
Process: 53088 ExecStartPre=/usr/pgsql-15/bin/postgresql-15-check-db-dir ${PGDATA} (code=exited, status=0/SUCCESS)
Main PID: 53093 (postmaster)Crea la base de datos y el usuario para Strapi:
$ sudo -i -u postgres psql
postgres=# CREATE DATABASE strapidb;
postgres-# CREATE USER strapiuser WITH PASSWORD 'Your_Password';
postgres-# ALTER DATABASE strapidb OWNER TO strapiuser;
postgres-# \qPrueba las credenciales:
$ psql --username strapiuser --password --host localhost strapidb
Password:
psql (15.1)
Type "help" for help.
strapidb=>Nota: Sustituye ‘Your_Password’ por una contraseña fuerte y almacénala de forma segura.
3. Instalar Node.js (versión LTS)
Rocky Linux incluye Node v16; instalaremos la LTS (v18 en el momento del tutorial).
Obtén el instalador de NodeSource e instala Node.js:
$ curl -fsSL https://rpm.nodesource.com/setup_18.x | sudo bash -
$ sudo dnf install nodejs -yVerifica la versión:
$ node -v
v18.13.04. Instalar Strapi
Crea el proyecto Strapi con npx:
$ npx create-strapi-app@latest howtoforge-project
Need to install the following packages:
[email protected]
Ok to proceed? (y) ySelecciona “Custom” y responde los parámetros para PostgreSQL:
? Choose your installation type Custom (manual settings)
? Choose your preferred language JavaScript
? Choose your default database client postgres
? Database name: strapidb
? Host: 127.0.0.1
? Port: 5432
? Username: strapiuser
? Password: Your_Password
? Enable SSL connection: NoPuedes optar por JavaScript o TypeScript según tus preferencias.
Una vez creado el proyecto, construye la UI de administración e inicia Strapi para pruebas locales:
$ cd howtoforge-project
$ NODE_ENV=production npm run build
$ node ~/howtoforge-project/node_modules/.bin/strapi startAbre temporalmente el puerto 1337 si necesitas acceder directamente (solo para pruebas locales):
$ sudo firewall-cmd --permanent --add-port=1337/tcp
$ sudo firewall-cmd --reloadAccede a http:// para ver la app. Cuando termines, detén el servidor con Ctrl+C y quita la regla del firewall:
$ sudo firewall-cmd --permanent --remove-port=1337/tcp
$ sudo firewall-cmd --reloadPantalla de ejemplo (Strapi arrancado en modo desarrollo):

Alt: Página principal de Strapi mostrando la interfaz inicial en modo desarrollo
5. Ejecutar Strapi en producción con PM2
PM2 permite ejecutar Node.js como servicio y crear integración con systemd.
Instala PM2 globalmente:
$ sudo npm install pm2@latest -gCrea el archivo de configuración PM2 (ecosystem.config.js). Abre el editor:
$ sudo nano ecosystem.config.jsPega el contenido (modifica la ruta y credenciales según tu usuario/proyecto):
module.exports = {
apps: [
{
name: 'strapi',
cwd: '/home/navjot/howtoforge-project',
script: 'npm',
args: 'start',
env: {
NODE_ENV: 'production',
DATABASE_HOST: 'localhost',
DATABASE_PORT: '5432',
DATABASE_NAME: 'strapidb',
DATABASE_USERNAME: 'strapiuser',
DATABASE_PASSWORD: 'Your_Password',
},
},
],
};Guarda y arranca con PM2:
$ pm2 start ecosystem.config.jsSalida de ejemplo de PM2 (resumen, no editar):
[PM2] App [strapi] launched (1 instances)Haz que PM2 se inicie con el sistema:
$ pm2 startupCopia y ejecuta el comando que te indique (puede variar por usuario), por ejemplo:
$ sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u navjot --hp /home/navjotGuarda la lista de procesos para restaurarla al reinicio:
$ pm2 save
[PM2] Successfully saved in /home/navjot/.pm2/dump.pm2Nota: Cambia ‘navjot’ por tu usuario. PM2 resucitará procesos tras reinicios si se ha ejecutado el comando startup y pm2 save.
6. Instalar Nginx como proxy inverso
Instala el repositorio oficial de Nginx y la versión estable:
$ sudo nano /etc/yum.repos.d/nginx.repoPega:
[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true
[nginx-mainline]
name=nginx mainline repo
baseurl=http://nginx.org/packages/mainline/centos/$releasever/$basearch/
gpgcheck=1
enabled=0
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=trueInstala y arranca Nginx:
$ sudo dnf install -y nginx
$ sudo systemctl enable nginx --now
$ sudo systemctl status nginxVerifica la versión:
$ nginx -v
nginx version: nginx/1.22.17. Obtener SSL con Certbot (Let’s Encrypt)
Para Certbot usaremos snapd. Instala EPEL, snapd y Certbot:
$ sudo dnf install -y epel-release
$ sudo dnf install -y snapd
$ sudo systemctl enable snapd --now
$ sudo snap install core && sudo snap refresh core
$ sudo ln -s /var/lib/snapd/snap /snap
$ echo 'export PATH=$PATH:/var/lib/snapd/snap/bin' | sudo tee -a /etc/profile.d/snapd.sh
$ sudo snap install --classic certbot
$ sudo ln -s /snap/bin/certbot /usr/bin/certbot
$ certbot --versionGenera el certificado para tu dominio (sustituye correo y dominio):
$ sudo certbot certonly --nginx --agree-tos --no-eff-email --staple-ocsp --preferred-challenges http -m [email protected] -d strapi.example.comLos certificados quedarán en /etc/letsencrypt/live/strapi.example.com.
Genera Diffie–Hellman para mayor seguridad:
$ sudo openssl dhparam -dsaparam -out /etc/ssl/certs/dhparam.pem 4096Prueba la renovación automática con una ejecución de prueba:
$ sudo certbot renew --dry-run8. Configurar Nginx como proxy TLS hacia Strapi
Ajusta nginx.conf para evitar errores de nombres largos:
$ sudo nano /etc/nginx/nginx.confAñade antes de include /etc/nginx/conf.d/*.conf;:
server_names_hash_bucket_size 64;Crea el bloque de servidor para Strapi:
$ sudo nano /etc/nginx/conf.d/strapi.confPega (sustituye strapi.example.com por tu dominio):
server {
# Redirect any http requests to https
listen 80;
listen [::]:80;
server_name strapi.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name strapi.example.com;
access_log /var/log/nginx/strapi.access.log;
error_log /var/log/nginx/strapi.error.log;
# TLS configuration
ssl_certificate /etc/letsencrypt/live/strapi.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/strapi.example.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/strapi.example.com/chain.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384';
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:50m;
ssl_session_timeout 1d;
# OCSP Stapling ---
# fetch OCSP records from URL in ssl_certificate and cache them
ssl_stapling on;
ssl_stapling_verify on;
ssl_dhparam /etc/ssl/certs/dhparam.pem;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1:1337;
}
}Verifica la sintaxis y reinicia Nginx:
$ sudo nginx -t
$ sudo systemctl restart nginxAhora accede a https://strapi.example.com.
Pantalla de ejemplo en producción:

Alt: Página de Strapi en modo producción con la interfaz pública accesible por HTTPS
Accede a la administración en https://strapi.example.com/admin para crear el usuario administrador:

Alt: Formulario para crear el usuario administrador de Strapi
Tras crear la cuenta verás el panel de control:

Alt: Panel de administración de Strapi mostrando contenido y secciones principales
9. Actualizar Strapi
Para actualizar realiza los siguientes pasos básicos:
- Detén la app con PM2:
$ cd ~
$ pm2 stop ecosystem.config.js- Edita package.json en el directorio del proyecto y actualiza las versiones de los paquetes de Strapi a la última estable.
$ cd howtoforge-project
$ nano package.jsonEjemplo (actualiza los números a la versión más reciente):
"dependencies": {
"@strapi/strapi": "4.5.5",
"@strapi/plugin-users-permissions": "4.5.5",
"@strapi/plugin-i18n": "4.5.5",
"pg": "8.6.0"
},- Instala, reconstruye y reinicia:
$ npm install
$ NODE_ENV=production npm run build
$ cd ~
$ pm2 start ecosystem.config.jsNota: Revisa las notas de migración oficiales antes de actualizar versiones mayores. Haz backup de la base de datos y del directorio
./config.
Verificación y pruebas de aceptación
Criterios de aceptación:
- El dominio
https://strapi.example.comdevuelve el sitio usando TLS válido. - El panel
/adminpermite iniciar sesión con el administrador creado. - PM2 muestra el proceso
strapicomo online tras reinicio del servidor. - Renovación de certificado mediante
certbot renew --dry-runfunciona sin errores.
Pruebas rápidas:
curl -I https://strapi.example.com
pm2 status
sudo certbot renew --dry-run
psql --username=strapiuser --host=localhost strapidb -c "SELECT 1;"Seguridad y endurecimiento
- No expongas el puerto 1337 públicamente; siempre usa proxy TLS.
- Usa contraseñas fuertes y, si es posible, autenticación basada en certificados para conexiones administrativas.
- Habilita un firewall a nivel de red y reglas de fail2ban para intentos de acceso SSH.
- Restringe el acceso a PostgreSQL mediante pg_hba.conf y redes permitidas.
- Mantén sistema y dependencias actualizadas; evalúa usar escáneres de vulnerabilidades.
Copias de seguridad y recuperación
- Base de datos: configura dumps regulares con pg_dump y retén en almacenamiento externo.
- Archivos: haz tar/rsync del directorio de proyecto y carpeta
./publicsi la usas. - PM2: usa
pm2 savey automatiza dumps antes de actualizaciones.
Proceso de recuperación rápido:
- Restaurar dump en PostgreSQL.
- Restaurar directorio del proyecto.
npm installyNODE_ENV=production npm run build.pm2 resurrectopm2 start ecosystem.config.js.
Cuándo falla y soluciones rápidas (counterexamples)
- Error: 502 Bad Gateway tras configurar Nginx: revisa que PM2 tenga la app corriendo en 127.0.0.1:1337 y que
proxy_passapunte a la dirección correcta. - Error de conexión a la DB: verifica credenciales en environment variables y que PostgreSQL acepte conexiones locales.
- Certbot no puede validar el dominio: comprueba DNS y que el puerto 80 esté accesible mientras Certbot valida.
Checklist por rol
Administrador de sistema:
- Crear usuario no root con sudo
- Abrir puertos HTTP/HTTPS en FirewallD
- Instalar y asegurar PostgreSQL Desarrollador backend:
- Generar proyecto Strapi con DB configurada
- Verificar endpoints y roles en panel admin DevOps:
- Configurar PM2 y systemd startup
- Configurar Nginx con TLS y OCSP stapling
- Implementar backups y monitorización
Mapa de decisiones rápido
- Necesitas hosting gestionado y no quieres mantener infra: considera Strapi Cloud o proveedores PaaS.
- Quieres control total y costes previsibles: seguir este despliegue con PM2 + Nginx.
Conclusión
Has instalado Strapi en Rocky Linux 9 con PostgreSQL 15, Node.js v18, PM2 y Nginx con TLS. A partir de aquí puedes:
- Crear colecciones y tipos de contenido en el panel de administración.
- Integrar un frontend consumiendo la API REST o GraphQL.
- Añadir plugins y configurar roles y permisos según tus necesidades.
Resumen final:
- Mantén backups y pruebas de restauración.
- Revisa notas de seguridad y actualizaciones de Strapi antes de actualizar.
- Automatiza renovación de certificados y arranque de PM2.
Si tienes preguntas concretas sobre un paso o error, indica el comando que estás ejecutando y la salida para poder ayudarte.
Materiales similares
Podman en Debian 11: instalación y uso
Apt-pinning en Debian: guía práctica
OptiScaler: inyectar FSR 4 en casi cualquier juego
Dansguardian + Squid NTLM en Debian Etch
Arreglar error de instalación Android en SD