Skip to content
Deploying / Directus

Directus

Installing the Directus template -- a headless CMS and data API on SQLite -- and signing in for the first time.

Directus wraps a SQL database with a real-time API and an admin app for its content. The template runs it on SQLite, so it needs nothing but the machine: no accessory, no external database.

Image directus/directus:11.17.4
Port 8055, behind kamal-proxy
Health check /server/health
Volumes database, uploads, extensions
Singleton yes

Before you start

  • A server that is registered, and a ready runner
  • A hostname. Directus builds its links from its public URL, so the environment is blocked until it has one. If you leave the domain blank and the server has an IP address, KamalCloud makes up a *.sslip.io hostname that already resolves to the server, so this rarely blocks.

Installing

Templates → Directus → Install. The form asks for:

Field
Name the app’s name, which is also the Kamal service and the prefix of every volume
Runner where Kamal runs
Environment production unless you want something else
Server the machine Directus runs on
Domain the hostname it is served on, e.g. cms.example.com. Left blank, it gets an sslip.io hostname
Admin email the first account. Defaults to admin@example.com – change it

Install creates the app and does not deploy it. If you typed a domain, point an A record for it at the server, then press Deploy.

What the install sets

Plain variables, in the destination config:

Variable Value
PUBLIC_URL https:// plus the environment’s first domain, filled in at each deploy
DB_CLIENT sqlite3
DB_FILENAME /directus/database/data.db
WEBSOCKETS_ENABLED true
IP_TRUST_PROXY true, because kamal-proxy is always in front
ADMIN_EMAIL what you typed on the form

Secrets, generated once at install:

Secret
KEY random base64. Directus reads it at every boot
SECRET random base64, used to sign sessions and tokens
ADMIN_PASSWORD 32 random letters and digits

Regenerating KEY or SECRET signs everyone out and invalidates every token Directus has issued, so leave them alone once the app is in use.

PUBLIC_URL is not stored. It is worked out from the domain each time KamalCloud renders the config, so changing the domain and deploying again is enough to move it.

Signing in

  1. Open Environment → Variables and read ADMIN_PASSWORD. Secret values are shown to admins only.
  2. Go to https://<your domain>/admin and sign in with the admin email and that password.

Changing the admin password

Directus reads ADMIN_PASSWORD once: on the first boot, against an empty database. On every boot after that it skips the step, so editing the secret changes nothing.

To change it for real, open Environment → Shell – a shell on the machine, not in the container – and run the Directus CLI inside the running container:

docker exec -it $(docker ps -q --filter label=service=<app name> | head -1) \
  npx directus users passwd --email <admin email> --password '<new password>'

Then update ADMIN_PASSWORD too, so the variable does not mislead the next person who reads it.

Data and backups

The three volumes are registered for backup at install, each named <app name>-<volume> on the host:

  • database – the SQLite file. It is marked to stop containers: Directus writes to it continuously, and a live tar of SQLite does not restore. Each backup of it is a short outage.
  • uploads – files added through the admin app
  • extensions – anything you install into /directus/extensions

None of them is scheduled until you set a schedule and pick a bucket on the volume.

Upgrading

The template is pinned to 11.17.4, the last release of the 11 line, and that is deliberate. Directus 12 enforces licensing on self-hosted instances: they run on a free Core tier where SSO, custom permission rules on access policies and self-hosted LLM connections stop working without a paid licence, and a new instance is enforced from its first boot.

11.17.4 has none of that, and it will also get no further fixes. If you move to 12, change the image tag on the app and deploy. Because the database, uploads and extensions each have their own volume, the new image picks up all three. Take a backup of the database volume first.

Troubleshooting

  • Blocked: “Directus reads its own address” – the environment has no domain. Install normally adds an sslip.io one, so this happens when the server had no IP address at install or the domain was removed. Add one under Domains and deploy.
  • The admin password does not work – you probably changed ADMIN_PASSWORD after the first boot. Use the CLI above.
  • Two containers during a deploy – they should not overlap. As a singleton the app deploys with no drain time, because two Directus processes writing one SQLite file is worse than a short gap.