Directus es una plataforma de datos y CMS headless que se coloca sobre una base de datos SQL: cada tabla se convierte en una colección editable desde su panel web y accesible al instante por API REST y GraphQL. En este tutorial desplegarás Directus en Ubuntu 24.04 con Docker Compose, usando PostgreSQL como base de datos y Redis como caché, lo publicarás detrás de Nginx con HTTPS y crearás una colección que consultarás desde la API.

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.
  • Un usuario no root con privilegios sudo.
  • Docker Engine y el plugin de Docker Compose instalados desde el repositorio oficial de Docker, con tu usuario en el grupo docker.
  • Un dominio con un registro DNS A que apunte a la IP del servidor. En esta guía se usa tu_dominio.

Paso 1: Preparar el directorio del proyecto

Guarda la configuración de Directus en su propio directorio:

sudo mkdir -p /opt/directus
sudo chown $USER:$USER /opt/directus
cd /opt/directus

Directus necesita un secreto para firmar los tokens de sesión, y PostgreSQL una contraseña. Genera ambos con openssl y guárdalos en un archivo .env, que Docker Compose lee automáticamente:

cat > .env <<EOF
DIRECTUS_SECRET=$(openssl rand -hex 32)
POSTGRES_PASSWORD=$(openssl rand -hex 24)
[email protected]
ADMIN_PASSWORD=$(openssl rand -base64 18)
EOF
chmod 600 .env

Cambia ADMIN_EMAIL por tu correo y consulta la contraseña de administrador generada, porque la necesitarás para entrar al panel:

grep ADMIN_ .env

Paso 2: Escribir el archivo de Docker Compose

Crea docker-compose.yml con tres servicios: la base de datos, la caché y Directus:

nano /opt/directus/docker-compose.yml
services:
  database:
    image: postgres:16
    restart: unless-stopped
    environment:
      POSTGRES_USER: directus
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: directus
    volumes:
      - db_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD", "pg_isready", "-U", "directus", "-d", "directus"]
      interval: 10s
      timeout: 5s
      retries: 5

  cache:
    image: redis:7
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5

  directus:
    image: directus/directus:latest
    restart: unless-stopped
    ports:
      - "127.0.0.1:8055:8055"
    volumes:
      - uploads:/directus/uploads
      - extensions:/directus/extensions
    depends_on:
      database:
        condition: service_healthy
      cache:
        condition: service_healthy
    environment:
      SECRET: ${DIRECTUS_SECRET}
      PUBLIC_URL: https://tu_dominio

      DB_CLIENT: pg
      DB_HOST: database
      DB_PORT: 5432
      DB_DATABASE: directus
      DB_USER: directus
      DB_PASSWORD: ${POSTGRES_PASSWORD}

      CACHE_ENABLED: "true"
      CACHE_AUTO_PURGE: "true"
      CACHE_STORE: redis
      REDIS: redis://cache:6379

      ADMIN_EMAIL: ${ADMIN_EMAIL}
      ADMIN_PASSWORD: ${ADMIN_PASSWORD}

volumes:
  db_data:
  uploads:
  extensions:

Puntos importantes de esta configuración:

  • Directus publica el puerto 8055 solo en 127.0.0.1, así que no es accesible desde Internet hasta que Nginx lo sirva. PostgreSQL y Redis no publican ningún puerto: solo los ve Directus por la red interna de Compose.
  • PUBLIC_URL es la URL por la que accederán los usuarios; Directus la usa para generar enlaces y redirecciones.
  • CACHE_AUTO_PURGE vacía la caché de la API cuando se modifica contenido, para que los cambios se vean al momento.
  • ADMIN_EMAIL y ADMIN_PASSWORD solo se usan en el primer arranque, para crear el administrador inicial.
  • latest siempre descarga la versión más reciente. En producción es mejor fijar una versión concreta (por ejemplo directus/directus:11.x.y, consultando las etiquetas en Docker Hub) y actualizar a propósito.

Comprueba que el archivo es válido y que las variables del .env se sustituyen:

docker compose config --quiet && echo OK

Paso 3: Arrancar Directus

Descarga las imágenes y arranca los contenedores en segundo plano:

docker compose up -d

En el primer arranque Directus crea sus tablas en PostgreSQL y el usuario administrador. Sigue el log hasta ver que el servidor está escuchando:

docker compose logs -f directus
directus-1  | ... INFO: Server started at http://0.0.0.0:8055

Pulsa CTRL+C para dejar de seguir el log y comprueba el estado de los tres contenedores:

docker compose ps

Todos deben aparecer como Up, y database y cache como (healthy). Comprueba también el endpoint de salud de Directus:

curl http://127.0.0.1:8055/server/health
{"status":"ok"}

Paso 4: Configurar Nginx y HTTPS

Instala Nginx y Certbot con su plugin para Nginx:

sudo apt update
sudo apt install nginx certbot python3-certbot-nginx

Crea un bloque de servidor para Directus:

sudo nano /etc/nginx/sites-available/directus
server {
    listen 80;
    listen [::]:80;
    server_name tu_dominio;

    client_max_body_size 100M;

    location / {
        proxy_pass http://127.0.0.1:8055;
        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 100 MB; el límite por defecto de Nginx es 1 MB. Las cabeceras Upgrade y Connection permiten el uso de WebSockets si más adelante los activas. Activa el sitio, comprueba la sintaxis y recarga:

sudo ln -s /etc/nginx/sites-available/directus /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

Abre HTTP y HTTPS en el cortafuegos y solicita el certificado. Certbot configura HTTPS y la redirección desde HTTP:

sudo ufw allow 'Nginx Full'
sudo certbot --nginx -d tu_dominio

Comprueba el acceso por HTTPS:

curl https://tu_dominio/server/health
{"status":"ok"}

Abre https://tu_dominio en el navegador e inicia sesión con el correo y la contraseña del .env. Cambia la contraseña desde tu perfil de usuario y, después, elimina las líneas ADMIN_EMAIL y ADMIN_PASSWORD del .env y del docker-compose.yml, ya que no vuelven a usarse.

Paso 5: Crear una colección y publicarla por API

En Directus cada colección es una tabla de PostgreSQL. Crea una de prueba desde el panel:

  1. Ve a Settings > Data Model y pulsa Create Collection.
  2. Llámala articles y deja la clave primaria por defecto.
  3. Añade un campo title de tipo Input y otro body de tipo WYSIWYG o Markdown.
  4. En Content > Articles, crea un par de artículos y guárdalos.

Por defecto nada es público. Para que cualquiera pueda leer los artículos sin autenticarse, ve a Settings > Access Policies, abre la política Public y concede el permiso de lectura (Read) sobre articles.

Consulta la colección desde la API REST:

curl https://tu_dominio/items/articles
{"data":[{"id":1,"title":"Primer artículo","body":"..."},{"id":2,"title":"Segundo artículo","body":"..."}]}

Para contenido que no debe ser público, no toques la política Public. En su lugar crea un usuario para tu aplicación con un rol que tenga solo los permisos necesarios, genera un token estático en el campo Token de ese usuario y envíalo en la cabecera Authorization: Bearer tu_token.

Paso 6: Copias de seguridad

Los datos de Directus están en la base de datos PostgreSQL y en el volumen uploads. Vuelca la base de datos desde el contenedor:

sudo mkdir -p /var/backups/directus
cd /opt/directus
docker compose exec -T database pg_dump -U directus -Fc directus | sudo tee /var/backups/directus/directus-$(date +%F).dump > /dev/null

Archiva los archivos subidos generando un tar dentro del contenedor de Directus y guardándolo en el servidor:

docker compose exec -T directus tar -czf - -C /directus uploads | sudo tee /var/backups/directus/uploads-$(date +%F).tar.gz > /dev/null
ls -lh /var/backups/directus

Guarda también /opt/directus/.env y docker-compose.yml: sin el SECRET original se invalidan las sesiones y tokens existentes. Programa estos comandos con cron o un temporizador systemd y copia las copias fuera del servidor.

Paso 7: Actualizar Directus

Directus aplica automáticamente las migraciones de base de datos al arrancar una versión nueva. Haz una copia de la base de datos como en el paso 6, cambia la etiqueta de la imagen si la tienes fijada y recrea el contenedor:

cd /opt/directus
docker compose pull
docker compose up -d
docker compose logs --tail 50 directus

Solución de problemas

  • El contenedor de Directus se reinicia en bucle. Revisa docker compose logs directus. Los errores de conexión a la base de datos suelen deberse a haber cambiado POSTGRES_PASSWORD después del primer arranque: PostgreSQL solo la aplica al crear el volumen.
  • No puedes iniciar sesión con la contraseña del .env. El administrador inicial solo se crea con la base de datos vacía. Si ya existía, restablece la contraseña con docker compose exec directus npx directus users passwd --email [email protected] --password nueva_contraseña.
  • Nginx devuelve 502 Bad Gateway. Directus no escucha todavía en 127.0.0.1:8055. Comprueba docker compose ps y el log.
  • Error 413 al subir archivos. Aumenta client_max_body_size en el bloque de Nginx y recárgalo.
  • La API devuelve 403 en /items/articles. La política Public no tiene permiso de lectura sobre esa colección, o la petición necesita un token.

Conclusión

Ya tienes Directus funcionando en Ubuntu 24.04 con Docker Compose, PostgreSQL y Redis, publicado por HTTPS detrás de Nginx y sirviendo una colección por API REST. Como siguientes pasos, puedes definir roles y políticas para tu equipo editorial, usar Flows para automatizar tareas cuando cambie el contenido, o mover los archivos subidos a un almacenamiento compatible con S3 con las variables STORAGE_LOCATIONS.