Bitdoze Logo

How To Deploy A Docker Compose App in Dokploy

Deploy any Docker Compose app in Dokploy with this step-by-step guide. Covers the Domains tab, Traefik labels, environment variables, and troubleshooting.

DragosDragos23 min read
How To Deploy A Docker Compose App in Dokploy

Dokploy is an open-source, self-hostable Platform as a Service (PaaS) for deploying and managing applications with Docker and Traefik. It has 36,300+ GitHub stars and regular releases (currently at v0.29.x), and it’s a free alternative to Vercel, Heroku, and Netlify. For comparisons, see how Dokploy stacks up against Coolify and Kamal 2 or our self-hosted server panels roundup.

This guide walks through deploying any Docker Compose app in Dokploy. I’ll use a Flowise AI + PostgreSQL stack as the running example, but the same workflow applies to any compose file.

Video note

The video was recorded with an earlier Dokploy version. The workflow is the same, but the UI may look slightly different. The Domains tab is now the recommended method for configuring domains.

Prerequisites

Before you start, make sure you have everything in place:

  • A VPS running Linux (Ubuntu 22.04+ or Debian 12+). A Hetzner CX22 at ~€4.49/mo works well. You can get an affordable VPS from Hetzner or a budget VPS from Hostinger
  • Dokploy installed and accessible at its dashboard URL. See our guide to install and configure Dokploy on your VPS
  • Docker and Docker Compose v2 installed (the Dokploy installer handles this)
  • Ports 80 and 443 open on the VPS firewall (required for Traefik and Let’s Encrypt)
  • A domain name with DNS access (to create an A record)
  • The Docker Compose file for the app you want to deploy

Ports 80 and 443

If these ports are blocked by your firewall or cloud provider, Let’s Encrypt certificate issuance will fail silently. Double-check before proceeding.

Don't want to self-host?

Dokploy Cloud is available starting at $4.50/mo per server if you’d rather skip managing the infrastructure yourself.

Flowise example: the Docker Compose file we’ll deploy

Here’s the compose file we’ll use throughout this guide. It runs Flowise AI with a PostgreSQL backend. This is a clean version: no Traefik labels and no dokploy-network. Dokploy handles networking and routing through the Domains tab or Isolated Deployments.

services:
  flowise-db:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: ${POSTGRES_DB}
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    volumes:
      - flowise-db-data:/var/lib/postgresql/data
    restart: unless-stopped
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
      interval: 5s
      timeout: 5s
      retries: 5

  flowise:
    image: flowiseai/flowise:latest
    healthcheck:
      test: wget --no-verbose --tries=1 --spider http://localhost:${PORT}
    volumes:
      - flowiseai:/root/.flowise
    environment:
      DEBUG: false
      PORT: ${PORT}
      FLOWISE_USERNAME: ${FLOWISE_USERNAME}
      FLOWISE_PASSWORD: ${FLOWISE_PASSWORD}
      APIKEY_PATH: /root/.flowise
      SECRETKEY_PATH: /root/.flowise
      LOG_LEVEL: info
      LOG_PATH: /root/.flowise/logs
      DATABASE_TYPE: postgres
      DATABASE_PORT: 5432
      DATABASE_HOST: flowise-db
      DATABASE_NAME: ${POSTGRES_DB}
      DATABASE_USER: ${POSTGRES_USER}
      DATABASE_PASSWORD: ${POSTGRES_PASSWORD}
    restart: on-failure:5
    depends_on:
      flowise-db:
        condition: service_healthy
    entrypoint: /bin/sh -c "sleep 3; flowise start"

volumes:
  flowiseai:
    driver: local
  flowise-db-data:
    driver: local

A few things to note:

  • No networks: section. Dokploy handles networking for you (via the Domains tab or Isolated Deployments).
  • No labels: block. Traefik routing is configured through the Domains tab, not in the compose file.
  • No container_name. Setting this in Dokploy causes issues with logs and metrics. Dokploy generates its own container names.
  • No version: key. Docker Compose v2 ignores it and may warn about it. If you’re bringing your own compose file with version: "3.8", just remove that line.
  • ${VAR_NAME} syntax. Environment variables are referenced this way because Dokploy writes UI-defined vars to a .env file. More on this in the environment variables section.

For a refresher on compose syntax, see essential Docker commands. The official docs have more examples at the Dokploy Docker Compose docs and the official example.

Point the domain to your server (DNS)

Before deploying, point your domain or subdomain to the Dokploy server:

  • Add an A record in your DNS settings:
    • Name: the subdomain you want (e.g., flowise for flowise.yourdomain.com)
    • Value: your server’s IP address
DNS A Record

DNS validation

Since Dokploy v0.22.0, the Domains tab includes built-in DNS validation. It checks whether your domain is correctly pointing to your server before you deploy.

This is Dokploy’s recommended approach. You paste your compose file as-is, then configure the domain and port through the UI. Dokploy injects the Traefik labels and networking config automatically.

For details on how Traefik works under the hood, see how Traefik works as a reverse proxy in Docker.

Step 1: create the compose service

  1. In the Dokploy dashboard, go to Projects and either create a new project or select an existing one.
  2. Click Create ServiceCompose.
  3. Give it a name (e.g., flowise).
  4. In General, select Raw as the source.
  5. Paste the clean compose file from above.
  6. Click Save.
Dokploy Compose

Step 2: add a domain

  1. Go to the Domains tab.
  2. Click Add Domain.
  3. Fill in the fields:
    • Domain: enter your domain (e.g., flowise.yourdomain.com)
    • Service Name: select the service from the dropdown (e.g., flowise. This is the key from your compose file)
    • Internal Port: the port your app listens on inside the container (3000 for Flowise)
    • Certificate Provider: select Let’s Encrypt for automatic HTTPS
  4. Click Save.
Dokploy Domain add

Dokploy will inject the required Traefik labels into the final compose file. You don’t need to add them manually.

Step 3: verify with Preview Compose

After configuring your domain, click the Preview Compose button. This shows you the final compose file Dokploy will actually execute, with all injected Traefik labels, network config, and domain settings. This is a critical verification step. Check that:

  • The Traefik labels include your domain and the correct port
  • The dokploy-network has been injected (or an isolated network if you enabled that)
  • No unexpected changes were made to your services

Ready to deploy

If Preview Compose shows the Traefik labels and your domain correctly, you’re ready to deploy.

Method 2: manual Traefik labels (advanced)

For most users, Method 1 is sufficient. Use manual Traefik labels only when you need custom configuration: middleware (auth, rate limiting), multiple host rules, custom entrypoints, or non-standard TLS config.

When to use manual labels

  • You need Traefik middleware (basic auth, rate limiting, custom headers)
  • You’re routing multiple domains to a single service
  • You need custom entrypoints or TLS settings beyond what the Domains tab offers

If none of these apply, stick with the Domains tab.

Adding dokploy-network and Traefik labels

With this approach, you modify the compose file to include the dokploy-network and Traefik labels:

services:
  flowise:
    image: flowiseai/flowise:latest
    networks:
      - dokploy-network
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.flowiseai.rule=Host(`flowise.yourdomain.com`)"
      - "traefik.http.routers.flowiseai.entrypoints=websecure"
      - "traefik.http.routers.flowiseai.tls.certResolver=letsencrypt"
      - "traefik.http.services.flowiseai.loadbalancer.server.port=3000"
    # ... rest of your service config

networks:
  dokploy-network:
    external: true

The Traefik label format:

labels:
  - "traefik.enable=true"
  - "traefik.http.routers.<unique-name>.entrypoints=websecure"
  - "traefik.http.routers.<unique-name>.tls.certResolver=letsencrypt"
  - "traefik.http.routers.<unique-name>.rule=Host(`app.yourdomain.com`)"
  - "traefik.http.services.<unique-name>.loadbalancer.server.port=3000"

Replace <unique-name> with a unique identifier for your service, set the Host() to your domain, and set the port to whatever your app listens on internally.

Every service that needs to communicate (e.g., the app and its database) must be on dokploy-network. For more on Traefik, see Traefik FREE Let’s Encrypt Wildcard Certificate.

Isolated Deployments (Advanced tab)

Dokploy’s Isolated Deployments feature is a third option for networking. When enabled, Dokploy:

  • Creates a per-app isolated network automatically
  • Connects Traefik to that isolated network
  • Eliminates the need to manually add dokploy-network to every service
  • Prevents service name conflicts when running multiple instances of the same app

To enable it: go to the Advanced tab for your compose service and toggle Isolated Deployments.

Zero modifications needed

When using Isolated Deployments together with the Domains tab, your compose file can be used as-is. No networks: section, no labels, no modifications at all. Just paste and deploy.

This is available for both Raw and Git provider compose services. See the Utilities docs for details.

Configuring Environment Variables in Dokploy

The Flowise example uses ${VAR_NAME} syntax throughout. Here’s how that works in Dokploy.

Understanding the .env file mechanism

When you set environment variables in Dokploy’s Environment tab, they are written to a .env file on the server. Your compose file must reference them with ${VAR_NAME} syntax (or use env_file: - .env). This is different from application services, where vars are injected directly into containers.

For the Flowise example, add these in the Environment tab:

PORT=3000
POSTGRES_USER='user'
POSTGRES_PASSWORD='pass'
POSTGRES_DB='flowise'
FLOWISE_USERNAME=bitdoze
FLOWISE_PASSWORD=bitdoze
Dokploy env

Variables are not auto-injected

Environment variables set in the UI are NOT automatically injected into containers. You must reference them as ${VAR_NAME} in your compose file or add env_file: - .env to your service definition.

A few additional notes:

  • Encryption at rest: since v0.29.12, all environment variables are encrypted using AES-256-GCM.
  • Shared variables: Dokploy supports project-level (${{project.VAR_NAME}}) and environment-level (${{environment.VAR_NAME}}) shared variables. Useful when multiple services in the same project share credentials. See the Variables docs.

For a deeper dive on Docker environment variables, see how Docker environment variables work with ARG and ENV.

Deploy and verify your app

After configuring your compose file, environment variables, and domain, it’s time to deploy:

  1. Go to General and click Deploy.
  2. Switch to the Deployments tab to watch the build logs.
  3. Wait for a “success” status.

Checking deployment logs

The Deployments tab shows real-time logs. A successful deploy ends with the containers running and Traefik routing traffic. If you see errors, the logs will point to the specific issue (wrong image tag, missing env var, port conflict, etc.).

Verifying the app is running

Once the deploy succeeds, verify it:

curl -I https://flowise.yourdomain.com

You should get an HTTP/2 200 response. The SSL certificate should be valid. Traefik issues it automatically via Let’s Encrypt.

SSL timing

It can take up to 10 seconds for Traefik to issue a Let’s Encrypt certificate after the first deployment. If you get a certificate error immediately, wait a moment and try again.

Backups for Docker Compose Apps

Since v0.22.0 (May 2025), Dokploy supports database backups and volume backups for Docker Compose services. If you’re running anything with persistent data, set this up early.

Database backups (PostgreSQL)

The Flowise example uses PostgreSQL. Dokploy can back up PostgreSQL, MariaDB, MySQL, and MongoDB databases within Docker Compose services. You configure this in the service’s backup settings and point it to an S3-compatible destination.

To set up Cloudflare R2 as your backup destination, see how to configure Dokploy backups with Cloudflare R2.

Volume backups

Dokploy can back up Docker named volumes to S3-compatible storage. This covers the flowiseai and flowise-db-data volumes in our example.

Named volumes only

Volume backups only work with named volumes (like flowiseai:), NOT bind mounts (like ./data:/app/data). If your compose file uses bind mounts, you’ll need a different backup strategy.

See the Volume Backups docs for configuration details.

Troubleshooting common issues

DNS not propagated

Symptom: browser shows “server not found” or Dokploy’s DNS validation fails in the Domains tab.

Cause: the A record isn’t set, or the TTL hasn’t expired yet.

Fix: check your DNS record:

dig flowise.yourdomain.com +short

This should return your server’s IP. If it doesn’t, verify the A record in your DNS provider. DNS propagation can take a few minutes to a few hours depending on your provider.

Port mismatch (502 Bad Gateway)

Symptom: you get a 502 Bad Gateway or connection refused after deploying.

Cause: the port configured in the Domains tab (or Traefik labels) doesn’t match the port the app actually listens on inside the container.

Fix: check your app’s documentation for its default port. For Flowise, it’s 3000 (controlled by the PORT env var). Make sure the Internal Port in the Domains tab matches.

Services can't communicate

Symptom: the app starts but can’t connect to its database (e.g., Flowise can’t reach PostgreSQL).

Cause: services are not on the same network.

Fix: if you’re using the Domains tab without Isolated Deployments, make sure all services that need to communicate are on dokploy-network. Or enable Isolated Deployments in the Advanced tab. Dokploy handles networking for you. Also verify that the service name in your connection string matches the key in the compose file (e.g., flowise-db, not localhost).

Container name issues

Symptom: logs or metrics not showing in the Dokploy dashboard.

Cause: container_name is set in the compose file.

Fix: remove the container_name directive. Dokploy generates its own container names for tracking logs, metrics, and deployments. Setting it manually breaks this.

For more debugging commands, see essential Docker commands. To monitor your server after deployment, set up server monitoring with Beszel and Uptime Kuma.

Updating and maintaining your compose app

After the initial deployment, you’ll eventually need to update images, change environment variables, or modify the compose file. Dokploy makes this straightforward. Edit the config and redeploy.

For the full update workflow (including how to handle image tags, rollbacks, and redeployments), see our guide on updating your deployed Docker Compose apps in Dokploy.

Conclusions

Deploying a Docker Compose app in Dokploy comes down to two approaches:

  1. Domains tab (recommended): paste your compose file as-is, configure the domain and port in the UI, and Dokploy handles the rest. No label editing, no network config.
  2. Manual Traefik labels (advanced): for when you need custom routing, middleware, or non-standard TLS setup.

With Isolated Deployments enabled, you can take the cleanest path: zero modifications to your compose file. Paste, set environment variables, add a domain, and deploy.

Don’t skip backups. Set up database backups for any stateful service and volume backups for persistent data. It takes five minutes and saves you from data loss.

How to Update Docker Compose Apps in Dokploy

If you are interested in more self-hosted apps, you can discover more self-hosted Docker containers or check toolhunt.net self hosted section.