Traefik Configuration#
Dokploy provisions and manages all Traefik configuration on startup and at deploy time. There are two layers: a static config (traefik.yml) that Traefik reads once on startup, and a dynamic config directory that Traefik hot-reloads continuously via its file provider.
File Layout#
The paths() helper resolves all config locations based on environment:
| Environment | Base path |
|---|---|
| Production / remote server | /etc/dokploy |
| Development | ./.docker |
Key paths derived from this base:
MAIN_TRAEFIK_PATH→{BASE_PATH}/traefik— holdstraefik.ymlDYNAMIC_TRAEFIK_PATH→{BASE_PATH}/traefik/dynamic— the file-provider watch directoryCERTIFICATES_PATH→{DYNAMIC_TRAEFIK_PATH}/certificates— per-cert subdirectories
The Traefik container bind-mounts both paths :
{MAIN_TRAEFIK_PATH}/traefik.yml→/etc/traefik/traefik.yml{DYNAMIC_TRAEFIK_PATH}→/etc/dokploy/traefik/dynamic
Static Configuration (traefik.yml)#
getDefaultTraefikConfig() generates the static config. Key settings:
- Providers:
file(watches/etc/dokploy/traefik/dynamic,watch: true),docker(exposedByDefault: false, networkdokploy-network), andswarmin production . - Entry points:
webonTRAEFIK_PORT(default 80),websecureonTRAEFIK_SSL_PORT(default 443) with HTTP/3 . Ports are overridable via env varsTRAEFIK_PORT,TRAEFIK_SSL_PORT,TRAEFIK_HTTP3_PORT. - ACME / Let's Encrypt: Certificate resolver named
letsencrypt, usinghttpChallengeon thewebentry point, storage at{DYNAMIC_TRAEFIK_PATH}/acme.json. - API:
insecure: true(dashboard accessible without auth by default) .
createDefaultTraefikConfig() writes this to disk only if traefik.yml does not yet exist . Remote servers use getDefaultServerTraefikConfig(), which always enables production providers and resolvers.
The Traefik version is controlled by the TRAEFIK_VERSION env var (default 3.6.7) .
Dynamic Configuration (File Provider)#
All files dropped in DYNAMIC_TRAEFIK_PATH are picked up by Traefik automatically because the file provider runs with watch: true . No Traefik restart is required when these files change.
Dokploy writes several well-known files into this directory:
| File | Written by | Purpose |
|---|---|---|
dokploy.yml | createDefaultServerTraefikConfig() | Default router pointing to the Dokploy API container |
middlewares.yml | createDefaultMiddlewares() | redirect-to-https middleware (permanent redirect scheme) |
{appName}.yml | writeTraefikConfig() / writeTraefikConfigRemote() | Per-app routers, services, and path middlewares for non-Compose apps |
acme.json | Traefik itself | ACME certificate storage (permissions set to 600 on boot) |
certificates/{id}/certificate.yml | certificate.ts service | TLS cert registration for manually uploaded certificates |
The FileConfig TypeScript interface represents the structure of every .yml file written into this directory. It covers http (routers, services, middlewares), tcp, udp, and tls (certificates, options, stores) sections.
⚠️ Certificate Subdirectory Limitation#
Traefik's file provider is non-recursive — it only watches the top level of DYNAMIC_TRAEFIK_PATH. Certificate YAML files are currently written to certificates/{id}/certificate.yml, which is one level too deep for Traefik to discover . This causes Traefik to fall back to its self-signed default cert instead of using the uploaded certificate, breaking Cloudflare Full (Strict) mode.
Workaround until this is fixed in code: copy the file to the top level manually:
cp /etc/dokploy/traefik/dynamic/certificates/<id>/certificate.yml \
/etc/dokploy/traefik/dynamic/<id>-certificate.yml
Traefik picks it up immediately because watch: true is active.
Per-App Dynamic Config ({appName}.yml)#
For non-Compose applications, Dokploy writes all routing config as a single per-app YAML file. The full FileConfig object is serialized to YAML and written to {DYNAMIC_TRAEFIK_PATH}/{appName}.yml. Multiple domains on the same app are all stored in this one file, keyed by domain.uniqueConfigKey — e.g., routers are named {appName}-router-{uniqueConfigKey} and {appName}-router-websecure-{uniqueConfigKey} for the HTTP/HTTPS pair.
manageDomain() always fully regenerates this file on every domain update. Manual edits to these files are overwritten on the next deploy. See issue #4415 for the open feature request to support merge-based per-domain config persistence.
Middleware Architecture#
The getDefaultMiddlewares() / createDefaultMiddlewares() pair writes middlewares.yml with a single middleware definition :
http:
middlewares:
redirect-to-https:
redirectScheme:
scheme: https
permanent: true
This is referenced as redirect-to-https@file by routers that need HTTP→HTTPS redirection.
The full set of middleware types available via FileConfig includes: addPrefix, basicAuth, chain, circuitBreaker, compress, forwardAuth, headers, ipWhiteList, rateLimit, redirectRegex, redirectScheme, retry, stripPrefix, and others . However, ipWhiteList / ipAllowList has no built-in Dokploy UI or code path — it exists only in the type definitions. To use IP-based filtering, you must manually write a middleware definition into a custom YAML file in the dynamic directory and reference it by name in the Domain.middlewares array. Because Dokploy regenerates the per-app file but not custom YAML files you add separately, a separately named file will persist across deploys.
Traefik Container Provisioning#
Two launch modes exist depending on the Docker deployment strategy:
- Standalone (
initializeStandaloneTraefik()): Docker container nameddokploy-traefik, restart policyalways, ports bound from env vars. - Swarm (
initializeTraefikService()): Docker Swarm service pinned to manager nodes via placement constraints, updated in-place usingForceUpdate.
Both modes mount the same MAIN_TRAEFIK_PATH and DYNAMIC_TRAEFIK_PATH volumes, join dokploy-network, and bind /var/run/docker.sock for Docker provider discovery .
Key Source Files#
| File | Purpose |
|---|---|
packages/server/src/setup/traefik-setup.ts | Static config generation, container/service provisioning, default middleware bootstrap |
packages/server/src/utils/traefik/file-types.ts | FileConfig TypeScript interface — schema for all dynamic YAML files |
packages/server/src/utils/traefik/types.ts | MainTraefikConfig interface — schema for traefik.yml |
packages/server/src/constants/index.ts | paths() — all filesystem path constants |
packages/server/src/utils/traefik/domain.ts | manageDomain(), writeTraefikConfig() — per-app router/service generation |