Dokploy Access Control#
Dokploy uses a layered access-control model that operates at three distinct levels:
- Network/routing layer — Traefik exposes (or hides) the Dokploy UI and user applications.
- Authentication gate —
enforceSSOcontrols who can log in to Dokploy itself; forward-auth (OAuth2 proxy) adds OIDC protection to deployed applications. - Deployment gate —
remoteServersOnlycontrols where workloads can be deployed.
All three layers apply only to self-hosted installations. Cloud deployments ignore remoteServersOnly and enforceSSO entirely .
Traefik Exposure of the Dokploy UI#
On first boot, createDefaultServerTraefikConfig() writes dokploy.yml into the dynamic Traefik directory. It creates:
- Router
dokploy-router-app— matchesHost(\dokploy.docker.localhost`) && PathPrefix(`/`)on theweb` (HTTP) entry point. - Service
dokploy-service-app— load-balances tohttp://dokploy:<PORT>(default3000) withpassHostHeader: true.
This default config is unprotected (no authentication middleware). The Dokploy panel is exposed on HTTP port 80; HTTPS is added by updating the domain settings via the UI, which overwrites this config with a production router using the websecure entry point and a Let's Encrypt cert resolver .
Important: The Traefik API itself is configured with
insecure: true, meaning it is accessible without authentication on its default port. In production, restrict access to this port at the firewall level.
enforceSSO — Restrict Login to SSO Only#
| Attribute | Value |
|---|---|
| Schema field | webServerSettings.enforceSSO (boolean, default false) |
| Update procedure | settings.updateEnforceSSO — enterpriseProcedure (owner/admin + valid enterprise license) |
| Cloud support | ❌ Throws BAD_REQUEST on cloud |
When enforceSSO = true:
- The login page (
pages/index.tsx) fetches the setting via server-side props and passes it to the<SignInWithSSO enforce={true} />component. - The component hides the email/password form and renders the SSO button only .
- A public tRPC query
sso.enforceSSOallows the frontend to check this flag before any authenticated session exists .
Enforcement is UI-only — the email/password API routes still exist. Pair with OIDC + forward-auth if you need hard network-layer enforcement.
remoteServersOnly — Block Local Deployments#
| Attribute | Value |
|---|---|
| Schema field | webServerSettings.remoteServersOnly (boolean, default false) |
| Update procedure | settings.updateRemoteServersOnly — enterpriseProcedure |
| Cloud support | ❌ Throws BAD_REQUEST on cloud |
When remoteServersOnly = true, routers for applications, Compose stacks, and databases check (IS_CLOUD || webServerSettings?.remoteServersOnly) && !input.serverId and reject the mutation with a TRPCError if no serverId is provided. This forces all resources to be deployed on an explicitly designated remote server rather than the local Dokploy host. The check lives within each individual resource router — there is no central middleware for it.
Forward-Auth (SSO Gate for Deployed Applications)#
Forward-auth adds an OIDC authentication layer in front of user-deployed applications — it is separate from Dokploy's own login. It is implemented as a Docker Swarm service dokploy-forward-auth running oauth2-proxy v7.6.0 on port 4180, attached to dokploy-network.
Setup#
Configured via SetupForwardAuthOptions:
oidc— clientId, clientSecret, issuer URL, optional scopes andskipDiscoveryauthDomain— the domain that hosts/oauth2/*endpointscookieSecret— 16/24/32-byte HMAC-derived secretemailDomains— allowed email domains (default*)
Traefik Integration#
For each domain with forwardAuthEnabled = true, Dokploy writes two Traefik middlewares :
forward-auth-{appName}-{key}—forwardAuthmiddleware pointing to{scheme}://{authDomain}/oauth2/auth; forwardsX-Auth-Request-User,X-Auth-Request-Email,X-Auth-Request-Preferred-Username,Authorizationheaders downstream.forward-auth-{appName}-{key}-errors— intercepts 401–403 responses and redirects to/oauth2/sign_in?rd={url}.
A central router forward-auth-oauth on authDomain matches PathPrefix(\/oauth2/`)` with priority 1000 to handle the OAuth2 callback and sign-in flow.
The forwardAuthEnabled flag lives on each Domain record; it is toggled per-domain and is documented as part of the Traefik domain routing config.
API / tRPC Procedure Reference#
| Procedure | Type | Guard |
|---|---|---|
settings.updateRemoteServersOnly | Mutation | enterpriseProcedure, self-hosted only |
settings.updateEnforceSSO | Mutation | enterpriseProcedure, self-hosted only |
sso.enforceSSO | Query | Public (no auth required) |
The enterpriseProcedure wrapper validates both role (owner/admin) and a valid enterprise license on every call . Read queries on cloud return null or "" for self-hosted-only fields.
Key Source Files#
| File | Purpose |
|---|---|
packages/server/src/setup/traefik-setup.ts | Traefik static config, createDefaultServerTraefikConfig, middleware setup |
packages/server/src/setup/forward-auth-setup.ts | dokploy-forward-auth Swarm service definition and env config |
packages/server/src/utils/traefik/domain.ts | createRouterConfig() — per-domain router with forwardAuthEnabled support |
apps/dokploy/server/api/routers/settings.ts | updateRemoteServersOnly, updateEnforceSSO mutations |
packages/server/src/schema | webServerSettings table — remoteServersOnly, enforceSSO fields |