Strapi es un CMS headless de código abierto escrito en Node.js: gestionas el contenido desde un panel de administración y lo sirves a cualquier frontend (web, app móvil) a través de una API REST o GraphQL. En este tutorial instalarás Strapi 5 en Ubuntu 24.04 con Node.js 22 y PostgreSQL, lo ejecutarás en modo producción como servicio systemd y lo publicarás detrás de Nginx con un certificado HTTPS de Let's Encrypt.
Requisitos previos
Para seguir esta guía necesitas:
- Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath, con al menos 2 GB de RAM. La compilación del panel de administración consume bastante memoria; con 1 GB necesitarás swap.
- Un usuario no root con privilegios
sudo. - Un dominio con un registro DNS A que apunte a la IP del servidor. En esta guía se usa
tu_dominio. - UFW permitiendo SSH, si tienes el cortafuegos activado.
Paso 1: Instalar Node.js 22
Strapi 5 necesita una versión LTS activa de Node.js. Los repositorios de Ubuntu 24.04 traen Node.js 18, que ya no está soportado, así que instala Node.js 22 desde el repositorio oficial de NodeSource.
Descarga la clave del repositorio en /etc/apt/keyrings:
sudo apt update
sudo apt install ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
Añade el repositorio de Node.js 22 e instala el paquete:
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_22.x nodistro main" | sudo tee /etc/apt/sources.list.d/nodesource.list
sudo apt update
sudo apt install nodejs
Comprueba las versiones:
node -v
npm -v
v22.x.x
10.x.x
Paso 2: Instalar PostgreSQL y crear la base de datos
Strapi funciona con SQLite por defecto, pero para producción conviene PostgreSQL. Instálalo desde los repositorios de Ubuntu (versión 16):
sudo apt install postgresql
Crea un usuario de base de datos llamado strapi. El comando te pedirá la contraseña dos veces; elige una contraseña segura y guárdala, la usarás en el paso siguiente:
sudo -u postgres createuser --pwprompt strapi
Crea la base de datos con strapi como propietario:
sudo -u postgres createdb -O strapi strapi
Comprueba que puedes conectarte con ese usuario por TCP, que es como lo hará Strapi:
psql -h 127.0.0.1 -U strapi -d strapi -c 'SELECT current_user;'
current_user
--------------
strapi
(1 row)
Paso 3: Crear el proyecto de Strapi
Crea un usuario de sistema sin privilegios para la aplicación y cambia a él:
sudo useradd -m -s /bin/bash strapi
sudo -iu strapi
Genera el proyecto con create-strapi. Las opciones indican que no quieres usar Strapi Cloud, que la base de datos es PostgreSQL y que no arranque el servidor al terminar. Sustituye tu_contraseña_db por la contraseña del paso 2:
npx create-strapi@latest cms --skip-cloud --use-npm --no-run \
--dbclient=postgres --dbhost=127.0.0.1 --dbport=5432 \
--dbname=strapi --dbusername=strapi --dbpassword=tu_contraseña_db
El asistente hará algunas preguntas que no cubren las opciones, como si quieres datos de ejemplo, TypeScript o inicializar un repositorio Git. Para esta guía, responde No a los datos de ejemplo; lo demás a tu gusto. Al terminar tendrás el proyecto en /home/strapi/cms, con las dependencias instaladas y un archivo .env con claves aleatorias (APP_KEYS, ADMIN_JWT_SECRET, JWT_SECRET, etc.) y los datos de conexión a la base de datos.
Comprueba el .env:
cd ~/cms
grep -E '^(HOST|PORT|DATABASE_CLIENT|DATABASE_NAME)=' .env
HOST=0.0.0.0
PORT=1337
DATABASE_CLIENT=postgres
DATABASE_NAME=strapi
Importanteel
.envcontiene los secretos de la instancia. No lo subas a ningún repositorio y haz copia de él, porque sinAPP_KEYSy los demás secretos no podrás descifrar sesiones ni tokens existentes.
Paso 4: Configurar Strapi para producción detrás de un proxy
Strapi solo tiene que escuchar en local, porque Nginx recibirá las peticiones públicas. Cambia HOST en el .env y añade la URL pública:
nano ~/cms/.env
HOST=127.0.0.1
PORT=1337
PUBLIC_URL=https://tu_dominio
Ahora indica a Strapi su URL pública y que confíe en las cabeceras del proxy. Edita el archivo de configuración del servidor (config/server.ts si elegiste TypeScript, config/server.js si elegiste JavaScript):
nano ~/cms/config/server.ts
export default ({ env }) => ({
host: env('HOST', '0.0.0.0'),
port: env.int('PORT', 1337),
url: env('PUBLIC_URL', 'http://localhost:1337'),
proxy: { koa: true },
app: {
keys: env.array('APP_KEYS'),
},
});
En la versión JavaScript el contenido es el mismo, con module.exports = en lugar de export default.
Compila el panel de administración en modo producción. Tarda uno o dos minutos:
NODE_ENV=production npm run build
Cuando termine, vuelve a tu usuario con sudo:
exit
Paso 5: Ejecutar Strapi con systemd
Una unidad systemd arranca Strapi con el sistema, lo reinicia si falla y envía sus logs al journal. Crea el archivo:
sudo nano /etc/systemd/system/strapi.service
[Unit]
Description=Strapi CMS
After=network.target postgresql.service
Requires=postgresql.service
[Service]
Type=simple
User=strapi
Group=strapi
WorkingDirectory=/home/strapi/cms
Environment=NODE_ENV=production
ExecStart=/usr/bin/npm run start
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
Arranca el servicio y actívalo al inicio:
sudo systemctl daemon-reload
sudo systemctl enable --now strapi
sudo systemctl status strapi --no-pager
Strapi expone un endpoint de salud que responde 204 No Content cuando está listo:
curl -I http://127.0.0.1:1337/_health
HTTP/1.1 204 No Content
Si no responde, revisa el log con sudo journalctl -u strapi -n 50.
Paso 6: Configurar Nginx y HTTPS
Instala Nginx y Certbot con su plugin para Nginx:
sudo apt install nginx certbot python3-certbot-nginx
Crea un bloque de servidor para Strapi:
sudo nano /etc/nginx/sites-available/strapi
server {
listen 80;
listen [::]:80;
server_name tu_dominio;
client_max_body_size 50M;
location / {
proxy_pass http://127.0.0.1:1337;
proxy_http_version 1.1;
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_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
client_max_body_size permite subir archivos de hasta 50 MB a la biblioteca de medios; Nginx limita a 1 MB por defecto. Activa el sitio, comprueba la sintaxis y recarga:
sudo ln -s /etc/nginx/sites-available/strapi /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
Abre HTTP y HTTPS en el cortafuegos y solicita el certificado. Certbot modifica el bloque de servidor para usar HTTPS y redirigir HTTP:
sudo ufw allow 'Nginx Full'
sudo certbot --nginx -d tu_dominio
Comprueba que el sitio responde por HTTPS:
curl -I https://tu_dominio/_health
HTTP/2 204
Paso 7: Crear el administrador y probar la API
Abre https://tu_dominio/admin en el navegador. La primera vez Strapi muestra un formulario para crear el primer usuario administrador; hazlo cuanto antes, porque cualquiera que llegue a esa URL antes que tú podría registrarlo.
Notaen modo producción el Content-Type Builder es de solo lectura. Los tipos de contenido se crean en un entorno de desarrollo (
npm run developen tu equipo), se guardan como archivos ensrc/api/y se despliegan copiando el código al servidor y repitiendonpm run buildysudo systemctl restart strapi. El contenido en sí sí se edita en producción desde el Content Manager.
Para acceder a la API desde un frontend o un script, crea un token en Settings > API Tokens > Create new API Token, con tipo Read-only. Copia el token, porque solo se muestra una vez, y úsalo en la cabecera Authorization. Por ejemplo, si tu proyecto tiene un tipo de colección article:
curl -H "Authorization: Bearer tu_token_api" https://tu_dominio/api/articles
{"data":[...],"meta":{"pagination":{"page":1,"pageSize":25,"pageCount":1,"total":3}}}
Si prefieres que un tipo de contenido sea público sin token, concede los permisos find y findOne al rol Public en Settings > Users & Permissions plugin > Roles.
Paso 8: Copias de seguridad
Lo que necesitas guardar es la base de datos, los archivos subidos (/home/strapi/cms/public/uploads) y el .env. Haz un volcado de la base de datos con pg_dump como el usuario postgres:
sudo mkdir -p /var/backups/strapi
sudo -u postgres pg_dump -Fc strapi | sudo tee /var/backups/strapi/strapi-$(date +%F).dump > /dev/null
sudo tar -czf /var/backups/strapi/uploads-$(date +%F).tar.gz -C /home/strapi/cms public/uploads .env
ls -lh /var/backups/strapi
Programa esos comandos con cron o un temporizador systemd y copia el directorio fuera del servidor. Para restaurar la base de datos usa pg_restore -d strapi.
Solución de problemas
npm run buildtermina con "JavaScript heap out of memory" o el proceso muere. El servidor no tiene RAM suficiente para compilar el panel. Añade un archivo de swap de 2 GB o amplía la RAM del servidor y repite la compilación.- El servicio falla con errores de conexión a la base de datos. Revisa
DATABASE_HOST,DATABASE_USERNAMEyDATABASE_PASSWORDen el.envy repite la prueba conpsqldel paso 2. - El panel carga pero las URLs apuntan a
localhosto a HTTP. FaltaPUBLIC_URLen el.envourlen la configuración del servidor. Corrígelo y vuelve a ejecutarnpm run buildantes de reiniciar. - Nginx devuelve 502 Bad Gateway. Strapi no está escuchando en
127.0.0.1:1337. Compruebasudo systemctl status strapiy el journal. - Error 413 al subir archivos. Aumenta
client_max_body_sizeen el bloque de Nginx y recárgalo.
Conclusión
Ya tienes Strapi 5 en producción en Ubuntu 24.04, con PostgreSQL, gestionado por systemd y publicado por HTTPS detrás de Nginx. Como siguientes pasos, puedes definir tus tipos de contenido en local y desplegarlos al servidor, instalar el plugin de GraphQL si tu frontend lo prefiere, o mover la biblioteca de medios a un almacenamiento compatible con S3 mediante un proveedor de subida.
