Directus wraps any SQL database with an instant REST and GraphQL API and a polished admin app. You model data as regular database tables; Directus provides the editing UI, permissions, file management, automation flows and webhooks. It’s popular as a headless CMS and as a back office for internal tools.

Check the Directus license for your use case — it’s free for many organisations, with conditions for larger companies.

1. Compose file

With Docker installed:

mkdir -p ~/directus && cd ~/directus

compose.yaml:

services:
  database:
    image: postgis/postgis:16-3.4-alpine     # or postgres:17
    restart: unless-stopped
    environment:
      POSTGRES_USER: directus
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_DB: directus
    volumes:
      - db:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD", "pg_isready", "-U", "directus"]
      interval: 10s
      retries: 5

  cache:
    image: redis:7-alpine
    restart: unless-stopped

  directus:
    image: directus/directus:11
    restart: unless-stopped
    depends_on:
      database:
        condition: service_healthy
    ports:
      - "127.0.0.1:8055:8055"
    volumes:
      - ./uploads:/directus/uploads
      - ./extensions:/directus/extensions
    environment:
      SECRET: ${SECRET}
      PUBLIC_URL: https://cms.example.com
      DB_CLIENT: pg
      DB_HOST: database
      DB_PORT: "5432"
      DB_DATABASE: directus
      DB_USER: directus
      DB_PASSWORD: ${DB_PASSWORD}
      CACHE_ENABLED: "true"
      CACHE_STORE: redis
      REDIS: redis://cache:6379
      ADMIN_EMAIL: [email protected]
      ADMIN_PASSWORD: ${ADMIN_PASSWORD}

volumes:
  db:
cat > .env <<EOF
SECRET=$(openssl rand -hex 32)
DB_PASSWORD=$(openssl rand -base64 24)
ADMIN_PASSWORD=$(openssl rand -base64 18)
EOF
chmod 600 .env
mkdir -p uploads extensions
docker compose up -d
docker compose logs -f directus

ADMIN_EMAIL/ADMIN_PASSWORD create the first admin on the initial start; change the password after logging in. PUBLIC_URL must match the URL users visit. Pin the image to the version you’ve tested.

The uploads directory must be writable by the container’s user (UID 1000 in the official image): sudo chown -R 1000:1000 uploads extensions.

2. HTTPS reverse proxy

server {
    listen 80;
    server_name cms.example.com;
    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";
    }
}
sudo nginx -t && sudo systemctl reload nginx
sudo certbot --nginx -d cms.example.com

The WebSocket headers support Directus’s realtime features.

3. Model data and set permissions

In the admin app (Settings → Data Model), create collections (tables) and fields. Directus can also attach to an existing database and expose its tables.

Settings → Access Policies / Roles: give the Public policy read access only to collections that should be public, and create API tokens or roles for your front ends with exactly the permissions they need. Everything is denied by default.

4. Files

Uploads go to ./uploads by default. For scale or multiple servers, configure an S3-compatible storage location (STORAGE_LOCATIONS=s3 plus STORAGE_S3_* variables) — e.g. MinIO. Directus generates image thumbnails on the fly with transformation parameters.

5. Flows and webhooks

Flows run automation on events (item created, schedule, webhook): send emails, call external APIs, transform data — useful to trigger static site rebuilds when content changes.

6. Backups

docker compose exec -T database pg_dump -U directus -Fc directus > directus-$(date +%F).dump
tar czf directus-uploads-$(date +%F).tar.gz uploads extensions

Directus’s data model lives in the database, so a dump contains both content and schema. Directus can also export the schema as a snapshot file (directus schema snapshot) to track in Git and apply to other environments.

7. Upgrades

docker compose pull && docker compose up -d

Database migrations run on startup. Back up first and read the release notes, especially across major versions.

Directus vs Strapi

  • Directus — database-first: works on existing SQL schemas, data modelled in the UI and stored as real tables.
  • Strapi — code-first: content types defined in your project’s code, customised with JavaScript.

See headless CMS options. A Docker VPS with 2–4 GB RAM runs Directus, PostgreSQL and Redis comfortably.

  • Directus
  • Headless CMS
  • Docker