Skip to content
dokploy-multi-tenant logo

Dokploy Multi-Tenant Patterns

dokploy-multi-tenant

Multi-tenancy patterns for Dokploy templates with network isolation: separate docker networks per tenant, shared infrastructure, and tenant-specific configuration.

SKILL.md

Full skill instructions

Dokploy Multi-Tenant Patterns

When to Use This Skill

  • When deploying multiple instances of the same template
  • When different clients/​projects need isolated deployments
  • When user asks about "multi-tenant" or "tenant isolation"
  • When planning organization-wide deployments

When NOT to Use This Skill

  • For single-instance deployments
  • For application-level multi-tenancy (built into app)

Prerequisites

  • Understanding of Docker networking
  • Clear tenant identification strategy
  • Knowledge of shared vs dedicated resources

Multi-Tenancy Strategy: Network Isolation

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:

  • Each tenant has isolated Docker network
  • Tenant services cannot communicate with other tenants
  • All tenants share Traefik via dokploy-network
  • Each tenant has dedicated domain/​subdomain

Core Patterns

Pattern 1: Tenant Network Naming

networks:
  ${TENANT_ID}-net:
    driver: bridge
  dokploy-network:
    external: true

Naming Convention:

  • Format: ${tenant_id}-${app_name}-net or ${tenant_id}-net
  • Examples: acme-corp-net, client-a-net, project-123-net

Pattern 2: Tenant Domain Strategy

Subdomain 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}`)"

Pattern 3: Tenant-Specific Environment

services:
  app:
    environment:
      TENANT_ID: ${TENANT_ID:?Set tenant identifier}
      TENANT_NAME: ${TENANT_NAME:?Set tenant name}
      TENANT_DOMAIN: ${TENANT_DOMAIN:?Set tenant domain}

Pattern 4: Isolated Volumes per Tenant

volumes:
  ${TENANT_ID}-app-data:
    driver: local
  ${TENANT_ID}-postgres-data:
    driver: local

Naming Convention:

  • Format: ${tenant_id}-${service}-${type}
  • Examples: acme-corp-postgres-data, client-a-app-uploads

Complete Example: Multi-Tenant Template

docker-compose.yml

services:
  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

template.toml

# 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}"

Deployment Strategies

Strategy 1: Subdomain Tenants

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

Strategy 2: Custom Domain Tenants

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

Strategy 3: Project-Based Tenants

Each project is a tenant:

[config.env]
TENANT_ID = "project-123"
TENANT_DOMAIN = "project-123.projects.example.com"

Resource Sharing vs Isolation

Shared Resources (Cost Effective)

ResourceSharedNotes
TraefikYesSingle instance routes all tenants
MonitoringYesCentral Prometheus/​Grafana
LoggingYesCentral logging stack
SSL CertsYesLetsEncrypt for all

Isolated Resources (Security/​Performance)

ResourceIsolatedNotes
Docker NetworkYesTenant-specific network
DatabaseYesDedicated database per tenant
VolumesYesTenant-specific volumes
CPU/​MemoryOptionalUse resource limits

Quality Standards

Mandatory Requirements

  • Tenant ID used in network name
  • Tenant ID used in volume names
  • Unique router names per tenant
  • Tenant domain configured
  • Isolated networks (no cross-tenant access)

Naming Conventions

  • Network: ${tenant_id}-net or ${tenant_id}-${app}-net
  • Volume: ${tenant_id}-${service}-data
  • Router: ${tenant_id}-${service}

Common Pitfalls

Pitfall 1: Duplicate router names

Issue: Two tenants with same router name conflict Solution: Include tenant ID in all router names

Pitfall 2: Shared volumes

Issue: Tenants overwrite each other's data Solution: Include tenant ID in volume names

Pitfall 3: Cross-tenant network access

Issue: Tenants can access each other's services Solution: Each tenant on separate network

Pitfall 4: Hardcoded tenant ID

Issue: Can't deploy multiple instances Solution: Use ${TENANT_ID} variable everywhere


Migration: Single to Multi-Tenant

To convert existing single-tenant template:

  1. Add TENANT_ID variable:
[variables]
tenant_id = "${username}"
  1. Update network name:
networks:
  ${TENANT_ID}-net:  # Was: app-net
    driver: bridge
  1. Update volume names:
volumes:
  ${TENANT_ID}-postgres-data:  # Was: postgres-data
    driver: local
  1. Update router names:
labels:
  - "traefik.http.routers.${TENANT_ID}-app.rule=..."  # Was: app
  1. Add tenant domain:
environment:
  TENANT_DOMAIN: ${TENANT_DOMAIN:?Set tenant domain}

Integration

Skills-First Approach (v2.0+)

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).

Related Skills

  • dokploy-compose-structure: Network patterns
  • dokploy-traefik-routing: Domain routing
  • dokploy-environment-config: Tenant variables
  • dokploy-multi-service: Multi-service dependency patterns

Invoked By

  • Special case: When user explicitly requests multi-tenant architecture
  • Not part of standard /​dokploy-create workflow
  • Can be manually invoked for advanced use cases

Usage Notes

  • This is an advanced pattern skill for specific multi-tenant scenarios
  • Standard single-tenant templates use the regular /​dokploy-create workflow
  • Use this skill when building SaaS platforms or multi-tenant applications

See: /​dokploy-create for standard workflow, this skill for multi-tenant variants

More skills from majiayu000

xiaohongshu logo
majiayu000/claude-arsenal

xiaohongshu

xiaohongshu

286 148
View
agent-task-conductor logo
majiayu000/claude-skill-registry

agent-task-conductor

Conduct multi-agent task orchestration and workflow coordination.

663 1
View
conductor-setup logo
majiayu000/claude-skill-registry

conductor-setup

Initialize project with Conductor artifacts (product definition,

663 1
View
animation-designer logo
majiayu000/claude-skill-registry

animation-designer

Expert in web animations, transitions, and motion design using Framer Motion and CSS

663 1
View
diagramming logo
majiayu000/claude-skill-registry

diagramming

Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...

663 1
View
h3-pg logo
majiayu000/claude-skill-registry-data

h3-pg

PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.

23 1
View
conductor-development logo
majiayu000/claude-skill-registry

conductor-development

Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...

663 1
View
conductor-status logo
majiayu000/claude-skill-registry

conductor-status

Display project status, active tracks, and next actions

663 1
View
dockerization logo
majiayu000/claude-skill-registry

dockerization

Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.

663 1
View

Popular AI tools

Kaiber logo
Video

Kaiber

Generate, edit, and beat-sync AI video with leading models in one workspace.

Paid
View
Vimcal logo
Productivity

Vimcal

The world's fastest calendar for remote work

Free
View

Transform Your Design with AI Designer by ImgCreator.ai

Freemium
View
Akool AI logo
Content & writing

Akool AI

Revolutionizing Video Production with AI-Powered Creativity

Paid
View

Extend an image past the frame and let AI fill the new aspect ratio.

Freemium
View
StarByFace logo
Security

StarByFace

Discover your celebrity doppelgänger with StarByFace!

Free
View
C

ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.

Freemium
View
Opus Clip logo
Coding & apps

Opus Clip

Opus.ai: Revolutionize Your Web Experience

Free
View