commit bb562b42eae19c78e1010c997eb17f39362fdcaf
parent 57fb0b991d8190dae62e35d8f95765e71e2543e5
Author: finwo <finwo@pm.me>
Date: Sat, 26 Sep 2026 18:40:13 +0200
Add a compose file that builds and runs the stack locally
Diffstat:
2 files changed, 58 insertions(+), 2 deletions(-)
diff --git a/deploy/docker-compose.yml b/deploy/docker-compose.yml
@@ -29,11 +29,17 @@ services:
# Must match how the outside world reaches this, because workers are
# handed absolute callback URLs built from it.
CONDUCTOR_PUBLIC_URL: "${CONDUCTOR_PUBLIC_URL:-http://127.0.0.1:8080}"
- # Without these two, sessions do not survive a restart and stored
- # secrets are kept in the clear. Generate with: openssl rand -hex 32
+ # Without these two, every access token stops verifying at restart
+ # and stored secrets are kept in the clear. openssl rand -hex 32
CONDUCTOR_SESSION_SECRET: "${CONDUCTOR_SESSION_SECRET:-}"
CONDUCTOR_SECRET_KEY: "${CONDUCTOR_SECRET_KEY:-}"
CONDUCTOR_ADMIN_PASSWORD: "${CONDUCTOR_ADMIN_PASSWORD:-}"
+ # localhost and 127.0.0.1 are different origins, and only registered
+ # ones may be signed in from. Defaults to public_url alone.
+ CONDUCTOR_LOCAL_REDIRECT_URIS: "${CONDUCTOR_LOCAL_REDIRECT_URIS:-http://127.0.0.1:8080,http://localhost:8080}"
+ CONDUCTOR_OIDC_DISCOVERY_URL: "${CONDUCTOR_OIDC_DISCOVERY_URL:-}"
+ CONDUCTOR_OIDC_CLIENT_ID: "${CONDUCTOR_OIDC_CLIENT_ID:-}"
+ CONDUCTOR_OIDC_ADMIN_ROLE: "${CONDUCTOR_OIDC_ADMIN_ROLE:-}"
CONDUCTOR_DATABASE_URL: "${CONDUCTOR_DATABASE_URL:-}"
CONDUCTOR_S3_ENDPOINT: "${CONDUCTOR_S3_ENDPOINT:-}"
CONDUCTOR_S3_BUCKET: "${CONDUCTOR_S3_BUCKET:-}"
diff --git a/docker-compose.yml b/docker-compose.yml
@@ -0,0 +1,50 @@
+# docker-compose.yml - built from this tree, for local use. Signs in as
+# admin / conductor. deploy/docker-compose.yml is the deployment one.
+#
+# docker compose up -d --build
+# docker compose exec conductor node src/admin-cli.js token:add local
+# CONDUCTOR_WORKER_TOKEN=<token> docker compose --profile worker up -d
+
+name: conductor-dev
+
+services:
+ conductor:
+ build:
+ context: .
+ dockerfile: deploy/Dockerfile
+ ports:
+ - "${CONDUCTOR_PORT:-8080}:8080"
+ environment:
+ CONDUCTOR_PUBLIC_URL: "http://localhost:${CONDUCTOR_PORT:-8080}"
+ # localhost and 127.0.0.1 are different origins.
+ CONDUCTOR_LOCAL_REDIRECT_URIS: "http://localhost:${CONDUCTOR_PORT:-8080},http://127.0.0.1:${CONDUCTOR_PORT:-8080}"
+ # Signs access tokens. Fixed, so a restart does not sign you out.
+ CONDUCTOR_SESSION_SECRET: development-session-secret-not-for-real-use
+ # Encrypts secrets at rest. 32 bytes, hex or base64.
+ CONDUCTOR_SECRET_KEY: "0000000000000000000000000000000000000000000000000000000000000000"
+ CONDUCTOR_ADMIN_PASSWORD: conductor
+ # Short, so the refresh path gets exercised.
+ CONDUCTOR_ACCESS_TTL: "60"
+ LOG_LEVEL: "${LOG_LEVEL:-info}"
+ volumes:
+ - dev-data:/data
+
+ worker:
+ profiles: ["worker"]
+ build:
+ context: .
+ dockerfile: deploy/Dockerfile.worker
+ depends_on:
+ - conductor
+ environment:
+ CONDUCTOR_URL: http://conductor:8080
+ CONDUCTOR_WORKER_NAME: local
+ # Interpolation happens before profiles are filtered, so this cannot
+ # be required or it would break `up` without the worker.
+ CONDUCTOR_WORKER_TOKEN: "${CONDUCTOR_WORKER_TOKEN:-}"
+ CONDUCTOR_WORKER_CONCURRENCY: "2"
+ volumes:
+ - /var/run/docker.sock:/var/run/docker.sock
+
+volumes:
+ dev-data: