com um clique
dokploy-multi-tenant
// Multi-tenancy patterns for Dokploy templates with network isolation: separate docker networks per tenant, shared infrastructure, and tenant-specific configuration.
// Multi-tenancy patterns for Dokploy templates with network isolation: separate docker networks per tenant, shared infrastructure, and tenant-specific configuration.
Integrate Cloudflare services with Dokploy templates: R2 storage, DNS challenge for SSL, Zero Trust Access, Workers, WAF, and Tunnel. Default to CF services for external dependencies.
Generate Docker Compose files following Dokploy conventions with proper networking, volumes, and service patterns. Use when creating new Dokploy templates or converting existing compose files.
Environment variable patterns for Dokploy templates including required vs optional syntax, secrets, connection strings, and configuration organization.
Health check patterns for different service types in Dokploy templates. Covers HTTP, PostgreSQL, MongoDB, Redis, MySQL, and custom health checks.
Multi-service architecture patterns for Dokploy templates including dependency chains, service communication, and complex stack design. Use when building templates with 2+ services.
Security best practices for Dokploy templates: secrets management, network isolation, least privilege, image security, and hardening recommendations.
| name | dokploy-multi-tenant |
| description | Multi-tenancy patterns for Dokploy templates with network isolation: separate docker networks per tenant, shared infrastructure, and tenant-specific configuration. |
| version | 1.0.0 |
| author | Home Lab Infrastructure Team |
This implementation uses separate Docker networks per tenant with shared infrastructure:
┌────────────────────────────────────────────────────────────────┐
│ Shared Infrastructure │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Traefik │ │ Monitoring │ │ Logging │ │
│ │ (dokploy) │ │ (shared) │ │ (shared) │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │ │
│ │ dokploy-network │
└─────────┼──────────────────────────────────────────────────────┘
│
┌─────┴─────┬─────────────┬─────────────┐
│ │ │ │
┌───┴───┐ ┌───┴───┐ ┌───┴───┐ ┌───┴───┐
│Tenant1│ │Tenant2│ │Tenant3│ │TenantN│
│ net │ │ net │ │ net │ │ net │
│ │ │ │ │ │ │ │
│ ┌───┐ │ │ ┌───┐ │ │ ┌───┐ │ │ ┌───┐ │
│ │App│ │ │ │App│ │ │ │App│ │ │ │App│ │
│ │DB │ │ │ │DB │ │ │ │DB │ │ │ │DB │ │
│ └───┘ │ │ └───┘ │ │ └───┘ │ │ └───┘ │
└───────┘ └───────┘ └───────┘ └───────┘
Characteristics:
networks:
${TENANT_ID}-net:
driver: bridge
dokploy-network:
external: true
Naming Convention:
${tenant_id}-${app_name}-net or ${tenant_id}-netacme-corp-net, client-a-net, project-123-netSubdomain per Tenant:
# tenant1.example.com
# tenant2.example.com
labels:
- "traefik.http.routers.${TENANT_ID}.rule=Host(`${TENANT_ID}.${BASE_DOMAIN}`)"
Custom Domain per Tenant:
# app.tenant1.com
# app.tenant2.com
labels:
- "traefik.http.routers.${TENANT_ID}.rule=Host(`${TENANT_DOMAIN}`)"
Path-Based Tenancy (Not Recommended):
# example.com/tenant1
# example.com/tenant2
labels:
- "traefik.http.routers.${TENANT_ID}.rule=Host(`${DOMAIN}`) && PathPrefix(`/${TENANT_ID}`)"
services:
app:
environment:
TENANT_ID: ${TENANT_ID:?Set tenant identifier}
TENANT_NAME: ${TENANT_NAME:?Set tenant name}
TENANT_DOMAIN: ${TENANT_DOMAIN:?Set tenant domain}
volumes:
${TENANT_ID}-app-data:
driver: local
${TENANT_ID}-postgres-data:
driver: local
Naming Convention:
${tenant_id}-${service}-${type}acme-corp-postgres-data, client-a-app-uploadsservices:
app:
image: myapp:1.0.0
restart: always
depends_on:
postgres:
condition: service_healthy
environment:
# Tenant identification
TENANT_ID: ${TENANT_ID:?Set tenant identifier}
TENANT_NAME: ${TENANT_NAME:-${TENANT_ID}}
# Domain
APP_DOMAIN: ${TENANT_DOMAIN:?Set tenant domain}
APP_URL: https://${TENANT_DOMAIN}
# Database
DATABASE_URL: postgresql://${DB_USER:-app}:${DB_PASS}@postgres:5432/${DB_NAME:-app}
# Security
SECRET_KEY: ${SECRET_KEY:?Set secret key}
networks:
- ${TENANT_ID}-net
- dokploy-network
labels:
- "traefik.enable=true"
- "traefik.http.routers.${TENANT_ID}-app.rule=Host(`${TENANT_DOMAIN}`)"
- "traefik.http.routers.${TENANT_ID}-app.entrypoints=websecure"
- "traefik.http.routers.${TENANT_ID}-app.tls.certresolver=letsencrypt"
- "traefik.http.services.${TENANT_ID}-app.loadbalancer.server.port=8080"
- "traefik.docker.network=dokploy-network"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
postgres:
image: postgres:16-alpine
restart: always
volumes:
- ${TENANT_ID}-postgres-data:/var/lib/postgresql/data
environment:
POSTGRES_DB: ${DB_NAME:-app}
POSTGRES_USER: ${DB_USER:-app}
POSTGRES_PASSWORD: ${DB_PASS:?Set database password}
networks:
- ${TENANT_ID}-net
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DB_USER:-app} -d ${DB_NAME:-app}"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
volumes:
${TENANT_ID}-postgres-data:
driver: local
networks:
${TENANT_ID}-net:
driver: bridge
dokploy-network:
external: true
# Multi-Tenant Application Template
# Each deployment creates an isolated tenant environment
[variables]
tenant_id = "${username}" # User provides tenant identifier
tenant_domain = "${domain}"
db_password = "${password:32}"
secret_key = "${base64:64}"
[[config.domains]]
serviceName = "app"
port = 8080
host = "${tenant_domain}"
[config.env]
# ===========================================
# Tenant Configuration
# ===========================================
TENANT_ID = "${tenant_id}"
TENANT_NAME = "${tenant_id}"
TENANT_DOMAIN = "${tenant_domain}"
# ===========================================
# Database
# ===========================================
DB_NAME = "app"
DB_USER = "app"
DB_PASS = "${db_password}"
POSTGRES_DB = "app"
POSTGRES_USER = "app"
POSTGRES_PASSWORD = "${db_password}"
# ===========================================
# Security
# ===========================================
SECRET_KEY = "${secret_key}"
Each tenant gets tenant.example.com:
# Dokploy deployment for Tenant "acme"
[config.env]
TENANT_ID = "acme"
TENANT_DOMAIN = "acme.example.com"
DNS Setup:
*.example.com → Your Dokploy server
Each tenant brings their own domain:
# Dokploy deployment for Tenant with custom domain
[config.env]
TENANT_ID = "acme"
TENANT_DOMAIN = "app.acmecorp.com"
DNS Setup (per tenant):
app.acmecorp.com CNAME your-dokploy-server.example.com
Each project is a tenant:
[config.env]
TENANT_ID = "project-123"
TENANT_DOMAIN = "project-123.projects.example.com"
| Resource | Shared | Notes |
|---|---|---|
| Traefik | Yes | Single instance routes all tenants |
| Monitoring | Yes | Central Prometheus/Grafana |
| Logging | Yes | Central logging stack |
| SSL Certs | Yes | LetsEncrypt for all |
| Resource | Isolated | Notes |
|---|---|---|
| Docker Network | Yes | Tenant-specific network |
| Database | Yes | Dedicated database per tenant |
| Volumes | Yes | Tenant-specific volumes |
| CPU/Memory | Optional | Use resource limits |
${tenant_id}-net or ${tenant_id}-${app}-net${tenant_id}-${service}-data${tenant_id}-${service}Issue: Two tenants with same router name conflict Solution: Include tenant ID in all router names
Issue: Tenants overwrite each other's data Solution: Include tenant ID in volume names
Issue: Tenants can access each other's services Solution: Each tenant on separate network
Issue: Can't deploy multiple instances
Solution: Use ${TENANT_ID} variable everywhere
To convert existing single-tenant template:
[variables]
tenant_id = "${username}"
networks:
${TENANT_ID}-net: # Was: app-net
driver: bridge
volumes:
${TENANT_ID}-postgres-data: # Was: postgres-data
driver: local
labels:
- "traefik.http.routers.${TENANT_ID}-app.rule=..." # Was: app
environment:
TENANT_DOMAIN: ${TENANT_DOMAIN:?Set tenant domain}
This skill is part of the skills-first architecture - an advanced pattern loaded when multi-tenant architecture is specifically required (not part of standard workflow).
dokploy-compose-structure: Network patternsdokploy-traefik-routing: Domain routingdokploy-environment-config: Tenant variablesdokploy-multi-service: Multi-service dependency patterns/dokploy-create workflow/dokploy-create workflowSee: /dokploy-create for standard workflow, this skill for multi-tenant variants