Skip to content

feat(directus): mount per-project extensions folder into Directus ser…#10

Merged
NicoKaempf merged 2 commits into
mainfrom
feat/directus-extensions-mount
Jul 6, 2026
Merged

feat(directus): mount per-project extensions folder into Directus ser…#10
NicoKaempf merged 2 commits into
mainfrom
feat/directus-extensions-mount

Conversation

@NicoKaempf

@NicoKaempf NicoKaempf commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Was

Fügt dem generierten Directus-Service-Compose einen absoluten Bind-Mount ${projectsDir}/${container.id}/extensions → /directus/extensions hinzu, damit eigene Directus-Extensions pro Projekt bereitgestellt werden können — ohne Custom-Image.

Wichtig: Swarm legt den Ordner NICHT selbst an

Anders als standalone docker run -v erstellt Docker Swarm eine fehlende Bind-Mount-Quelle nicht, sondern lehnt den Task ab (invalid mount config … bind source path does not exist — im lokalen Single-Node-Swarm verifiziert). Deshalb legt createDockerComposeFile() den extensions-Ordner vor dem stack deploy per fs.mkdir(..., { recursive: true }) an. Ein leerer Ordner = „keine Extensions" = unverändertes Verhalten für bestehende Services.

Marketplace

Directus lädt Extensions lesend → der (deploy.party-owned) Ordner reicht dafür. Der Marketplace schreibt Installs aber als uid 1000 in den Ordner und braucht ihn daher auf 1000:1000 gechownt (verifiziert: uid 1000 bekommt sonst Permission denied). Aktuell manueller Schritt.

⚠️ Rollout-Hinweis

Directus-Services, die aktuell Store-Extensions installiert haben, halten diese nur ephemer. Beim ersten Redeploy nach diesem Change überschattet der leere Host-Ordner sie → sie verschwinden. Vorher docker cp <task>:/directus/extensions/. /data/projects/<id>/extensions/ sichern oder neu installieren. Betrifft alle Directus-Services der Instanz.

Verifiziert

  • tsc -p tsconfig.build.json --noEmit → Exit 0
  • Swarm-Reject ohne Ordner reproduziert; mit mkdir startet der Service sauber
  • uid-1000-Schreibtest bestätigt den chown-Bedarf

…vice

Add an absolute bind mount `${projectsDir}/${container.id}/extensions ->
/directus/extensions` to the generated Directus service compose so custom
Directus extensions can be provided per project without a custom image.

- Absolute path because Swarm bind mounts do not resolve relative paths.
- Docker auto-creates the (empty, root-owned) folder on deploy; an empty
  folder means "no extensions" = unchanged behaviour for existing services.
- Directus loads extensions read-only, so root ownership is fine for that.
  To let the Directus Marketplace write installs here, chown the folder to
  1000:1000 (the node/directus container user).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the API’s Directus Docker Compose generator to bind-mount a per-project extensions directory from the host into the Directus container, enabling custom Directus extensions without requiring a custom image.

Changes:

  • Add envConfig usage to locate the configured projects directory at compose-generation time.
  • Mount ${projectsDir}/${container.id}/extensions to /directus/extensions in the generated Directus service compose.

…t reject

Docker Swarm does NOT auto-create a missing bind-mount source (unlike
standalone `docker run`); it rejects the task with "invalid mount config
... bind source path does not exist". Verified in a local single-node swarm.

createDockerComposeFile() now mkdir's `${projectsDir}/${container.id}/extensions`
before deploy, so the Directus extensions bind mount added in the previous
commit does not break existing/new Directus services on redeploy.

Also corrects the compose comment (the folder is created by deploy.party, not
automatically by Docker) and documents that the Marketplace needs the folder
chowned to 1000:1000 (verified: uid 1000 gets "Permission denied" otherwise).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

Comment on lines +121 to +123
// Swarm rejects a service whose bind-mount source path is missing, so the
// per-project extensions folder (see getDirectus) must exist before deploy.
await fs.mkdir(`${envConfig.projectsDir}/${container.id}/extensions`, { recursive: true });
@NicoKaempf NicoKaempf merged commit ab388e3 into main Jul 6, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants