Deployment

Dokploy

Deploy the Traefik-fronted production compose stack on Dokploy.

Ductor ships a Dokploy-flavored compose file, docker-compose.dokploy.yml, that runs the production image behind Dokploy's Traefik ingress. It serves the REST/Connect API and the Scalar docs on :8080 and exports OTLP traces to VictoriaTraces; Traefik routes the public hostnames and issues TLS. The hostnames below (api.ductor.io, docs.ductor.io, …) are the reference deployment's — treat them as examples and substitute your own.

HTTPS :8080 OTLP Client Traefik ingress ductor-api timescale dragonfly victoriatraces

What's different from the dev compose

  • The ductor service builds the production target (not development).
  • Passwords come from Dokploy environment variables, not hardcoded defaults.
  • The full VictoriaMetrics observability stack is included and tracing is on.
  • The service joins both the internal ductor network and Dokploy's dokploy-network (with a stable ductor-api alias) so Traefik and in-cluster callers can route to it.

The single :8080 surface

The API listener serves everything on :8080:

PathServes
/docsScalar API reference UI
/openapi.yamlThe OpenAPI spec
/healthLiveness endpoint (used by the container healthcheck)

The ductor service command and key configuration:

# Overrides the baked Dockerfile CMD to drop the removed --grpc-addr flag —
# the current `serve` command no longer defines it (gRPC rides Connect on :8080).
command: ["serve", "--http-addr=:8080", "--metrics-addr=:9090"]
environment:
  DUCTOR_DATABASE_URL: postgres://ductor:${POSTGRES_PASSWORD}@timescale:5432/ductor?sslmode=disable
  DUCTOR_CACHE_URL: redis://:${DRAGONFLY_PASSWORD}@dragonfly:6379
  DUCTOR_API_ENABLED: "true"
  DUCTOR_API_ADDR: ":8080"
  DUCTOR_API_ALLOWED_HOSTS: "localhost,127.0.0.1,::1,0.0.0.0,api.ductor.io,docs.ductor.io,ductor-api"
  DUCTOR_CONNECTOR_ENCRYPTION_KEY: ${CONNECTOR_ENCRYPTION_KEY}
  DUCTOR_ROUTER_QUEUE_ENABLED: "true"
  DUCTOR_ROUTING_DAG_BRIDGE_ENABLED: "true"
  DUCTOR_AGGREGATOR_BACKEND: "redis"
  DUCTOR_TRACING_ENABLED: "true"
  DUCTOR_TRACING_ENDPOINT: "victoriatraces:4317"
  DUCTOR_TRACING_GRPC: "true"
networks: [ductor, dokploy-network]

allowed_hosts must include your domains and loopback

DUCTOR_API_ALLOWED_HOSTS is a DNS-rebinding allowlist with exact-match semantics — requests whose Host header isn't on it are rejected. It must include every hostname Traefik forwards and loopback (localhost/127.0.0.1), because the container's healthcheck hits http://localhost:8080/health. Drop loopback and the container is marked unhealthy and Traefik stops routing to it.

Required environment

Provide these as Dokploy environment variables (they come from the Dokploy Environment tab and are never committed):

VariablePurpose
POSTGRES_PASSWORDTimescaleDB password (used in DUCTOR_DATABASE_URL)
DRAGONFLY_PASSWORDDragonfly password (used in DUCTOR_CACHE_URL)
CONNECTOR_ENCRYPTION_KEYBase64 32-byte AEAD master key for connector credentials
GF_ADMIN_PASSWORDGrafana admin password
DUCTOR_AUTH_API_KEYSDB/static API keys, if you enable key auth (optional)
DUCTOR_VERSIONImage version tag (optional; defaults to prod)

The reference deployment boots app-open (DUCTOR_AUTH_ENABLED defaults to false); lock it down with Traefik basic-auth in front, or switch to OIDC / DB-backed API keys via the auth env vars. For a production posture, follow the production checklist.

Deploy steps

Create the app in Dokploy from the repository, selecting Docker Compose and docker-compose.dokploy.yml.

Set the environment variables above.

Add domains in Dokploy for the ductor service (e.g. your API host), which provisions Traefik routing and TLS. Ensure those hosts are in DUCTOR_API_ALLOWED_HOSTS.

Deploy. The compose file sets DUCTOR_DATABASE_AUTO_MIGRATE: "true", so the schema migrates on first boot. For stricter control, set it to false and run ductor migrate up as a one-off (see Migrations).

Verify by hitting https://<your-domain>/health and the Scalar reference at https://<your-domain>/docs.

Backups and observability

Dokploy can schedule Postgres backups of the timescale service directly. The compose file also brings up the full observability stack (Grafana on :3000), so metrics, logs, and traces are available out of the box — see Observability and Backup & restore.