CodeWorlds
Back to collections
Guide19 min readCodeWorlds Team

Dokploy, a self-hosted PaaS built on Docker Swarm

Dokploy puts a PaaS panel on your own server: Docker Swarm, Traefik, PostgreSQL. Version 0.30.2, Apache 2.0 with a proprietary directory, and the real bill.

Dokploy, a self-hosted PaaS built on Docker Swarm

Dokploy installs a panel on your own server that builds applications from a Git repository or a container image, exposes them through Traefik and issues certificates. The current release is 0.30.2, published on 18 August 2026. The code is Apache 2.0, except for directories named proprietary, which carry a separate licence forbidding production use without a commercial agreement.

What the installer puts on your server

Installation is a single command that fetches install.sh from the vendor's domain, but that script does more than its length suggests. Before it runs anything it checks that you are root, that the system is Linux, that you are not inside a container, and that ports 80, 443 and 3000 are free. If any of those ports is taken it exits with an error rather than trying to work around the problem.

It then installs Docker pinned to version 28.5.0 and, on apt-based distributions, applies apt-mark hold to the docker-ce, docker-ce-cli and docker-ce-rootless-extras packages. That is a decision made for you: your server stops receiving Docker updates from the system repository until you lift the hold yourself. Keep it in mind during a security audit.

Next the script calls docker swarm leave --force, initialises a new swarm, creates the dokploy-network overlay network and the /etc/dokploy directory with permissions 777. It picks the swarm advertise address from the first private address on an interface other than docker, br- and veth, and when there is none it asks external services such as ifconfig.io and icanhazip.com for the public address. The database password and the auth secret go into Docker secrets, not into environment variables.

Code
Bash
# the core of the install: database, panel and proxy as three separate things
docker service create \
  --name dokploy-postgres \
  --constraint 'node.role==manager' \
  --network dokploy-network \
  --env POSTGRES_USER=dokploy \
  --env POSTGRES_DB=dokploy \
  --secret source=dokploy_postgres_password,target=/run/secrets/postgres_password \
  --env POSTGRES_PASSWORD_FILE=/run/secrets/postgres_password \
  --mount type=volume,source=dokploy-postgres,target=/var/lib/postgresql/data \
  postgres:16

docker service create \
  --name dokploy \
  --replicas 1 \
  --network dokploy-network \
  --mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock \
  --mount type=bind,source=/etc/dokploy,target=/etc/dokploy \
  --publish published=3000,target=3000,mode=host \
  --update-parallelism 1 \
  --update-order stop-first \
  --constraint 'node.role == manager' \
  dokploy/dokploy:v0.30.2

# the proxy starts as a plain container, not as a swarm service
docker run -d --name dokploy-traefik --restart always \
  --network dokploy-network \
  -v /etc/dokploy/traefik/traefik.yml:/etc/traefik/traefik.yml \
  -v /etc/dokploy/traefik/dynamic:/etc/dokploy/traefik/dynamic \
  -v /var/run/docker.sock:/var/run/docker.sock:ro \
  -p 80:80/tcp -p 443:443/tcp -p 443:443/udp \
  traefik:v3.6.7

Note one detail in that listing: the panel container gets /var/run/docker.sock mounted for writing. Anyone with admin rights in the panel effectively has root on the machine. That is not a Dokploy flaw but a property of this whole category of tools, and it is worth making staffing decisions with that fact in view.

Licence: Apache 2.0 and the proprietary directory

This is the most important thing in the article, so I checked it from three sides.

The first source is the licence file in the repository. It is called LICENSE.MD, uppercase including the extension, so tools probing for LICENSE or LICENSE.md get a 404 and may conclude there is no licence at all. Its text splits the repository in two. Anything under a directory named /proprietary falls under the licence in LICENSE_PROPRIETARY.md. Everything else is under the Apache License 2.0.

LICENSE_PROPRIETARY.md contains the Dokploy Source Available License version 1.0. Its core: that code may be used in production only if you, and any entity you represent, have agreed to and comply with a valid commercial agreement from Dokploy. You may modify it and publish patches, but Dokploy retains all rights to those modifications, and they may only be exploited with that licence in hand. Copying and modifying for development and testing is allowed without a subscription. Copying, merging, publishing, distributing, sublicensing and selling are forbidden.

The second source is the fields in package registries. The platform itself is not on npm, because it ships as a container image. There are three helper packages, and each declares a different licence: @dokploy/cli says MIT, @dokploy/sdk says ISC, @dokploy/mcp says Apache-2.0.

The third source is the contents of the published packages. I unpacked all three. Each contains real compiled code, in dist and build respectively, so none of them is a stub. Each also contains a licence file. And here the mismatch shows: @dokploy/sdk has "license": "ISC" in package.json, yet the package ships a LICENSE file with the full MIT text and the header "Copyright (c) 2026 Dokploy". The field and the file disagree. ISC is the default npm inserts when nothing is declared, so most likely nobody set the field and the file is what governs. If you keep a dependency licence register, record both values with a note.

Now the part agencies care about. The proprietary directories exist and their contents are named. There are at least two: apps/dokploy/server/api/routers/proprietary and packages/server/src/services/proprietary. Under those paths live the license-key, sso, scim, audit-log, custom-role, forward-auth and whitelabeling modules.

The conclusion is surprisingly favourable for agencies and deserves stating plainly. Running Dokploy for clients, hosting other people's applications on it and charging money for that is not forbidden, because the core is Apache 2.0 with no hosted-service clause. What you may not use in production without an agreement with Dokploy is single sign-on, SCIM, the audit log, fine-grained roles, forward authentication and white labelling. The licence key is checked through the licenseKey.activate, licenseKey.validate and licenseKey.haveValidLicenseKey endpoints, and each user carries an enableEnterpriseFeatures flag in the database.

Two caveats. The licence says "if that directory exists", so its contents can grow between releases, and at every upgrade you have to check whether the feature you depend on has moved behind the gate. The GitHub interface reports NOASSERTION and the name "Other" for this repository, so an automated metadata collector will tell you nothing useful. This is the opposite of Coolify, where a single Apache 2.0 file covers everything and there is no directory carved out for commercial customers.

Version, release cadence and npm packages

Release 0.30.2 reached npm on 18 August 2026 at 21:42 UTC, while its entry in the GitHub releases feed carries a modification timestamp of 20 August, meaning the notes were edited after publication. The releases feed gives modification timestamps, not premiere dates, and that is how I read them here.

The cadence is dense. The ten releases visible in the feed span 7 July to 20 August 2026, with three of them, 0.29.8, 0.29.9 and 0.29.10, sharing the same 7 July timestamp. Then: 0.29.11 on 9 July, 0.29.12 on 13 July, 0.29.13 on 21 July, 0.29.14 on 6 August, 0.30.0 on 14 August, 0.30.1 on 18 August. The major version still starts with zero, which at this pace means breaking changes can land in a patch release.

The repository itself contains a range mismatch that will bite you on the first attempt to build from source. The root package.json requires Node ^24.4.0 and pnpm >=9.12.0 in its engines field, but the @dokploy/api and @dokploy/schedules packages require pnpm >=10.22.0. The root packageManager field pins pnpm@10.22.0, so the higher bound is the real minimum. The root range is simply out of date.

Watch out for the npm packages, because one of them is not from the project.

PackageVersionlicense fieldFile in the tarballOrigin
@dokploy/cli0.30.2MITLICENSE.md, MIT textDokploy/cli, published by siumauricio
@dokploy/sdk0.30.2ISCLICENSE, MIT textno repository field, published by siumauricio
@dokploy/mcp0.30.2Apache-2.0LICENSE, Apache 2.0 textDokploy/mcp, published by siumauricio
dokploy0.1.3field absentnot inspectedLukeHagar/Dokploy-ts-sdk, published by lukehagar

The unscoped dokploy package is a third-party client generated by Speakeasy, last published on 21 October 2025, with a single dependency on zod in the ^3.20.0 range and no license field. The repository address in its metadata now redirects to a different account, LukasParke/Dokploy-ts-sdk. It is not a vendor package and should not be installed on the assumption that it is.

A separate trap when reading dependencies: do not attribute to the core what the cloud modules pull in. The @dokploy/api package depends on inngest 3.40.1 and redis 4.7.0, and @dokploy/schedules on bullmq 5.67.3 and ioredis 5.4.1. A standard install.sh deployment starts neither Redis nor those two services. The panel core, @dokploy/server, has no license field in its package.json at all, but it is not published to npm, so the repository licence governs it.

Traefik inside and the default configuration

The answer to the proxy question is Traefik, not Caddy. The configuration is generated from code rather than from a text template, so it can be read exactly.

Starting with the image version: the vendor gives two different numbers. The install.sh script served from dokploy.com starts traefik:v3.6.7, while the TRAEFIK_VERSION constant in the 0.30.2 source defaults to 3.6.25 and can be overridden by an environment variable of the same name. A fresh install and a proxy re-initialisation from the panel can therefore bring up different Traefik versions. I give both numbers and flag the discrepancy.

/etc/dokploy/traefik/traefik.yml
YAML
# /etc/dokploy/traefik/traefik.yml, as release 0.30.2 generates it
global:
  sendAnonymousUsage: false
providers:
  swarm:
    exposedByDefault: false
    watch: true
  docker:
    exposedByDefault: false
    watch: true
    network: dokploy-network
  file:
    directory: /etc/dokploy/traefik/dynamic
    watch: true
entryPoints:
  web:
    address: ":80"
  websecure:
    address: ":443"
    http3:
      advertisedPort: 443
    http:
      tls:
        certResolver: letsencrypt
api:
  insecure: true
certificatesResolvers:
  letsencrypt:
    acme:
      email: test@localhost.com
      storage: /etc/dokploy/traefik/dynamic/acme.json
      httpChallenge:
        entryPoint: web

Three things in this file need your attention after installation. api.insecure set to true enables the Traefik API without authentication; port 8080 is not published by default, but a toggle in the panel can expose it, and then anyone can reach it. The ACME email address is test@localhost.com, a placeholder, so you will not receive certificate expiry warnings. The challenge is HTTP only, which means no wildcard certificates from this resolver without extra configuration.

Traefik's anonymous telemetry is switched off, which is a good and rarely seen default.

Multiple servers, Swarm and the single point of failure

Dokploy runs on Docker Swarm rather than plain Docker, and that cuts both ways.

On the plus side: adding another machine is designed into the product, not bolted on. The database has a server table with ipAddress, port, username defaulting to root, sshKeyId, serverType valued deploy or build, buildsConcurrency defaulting to 1, and enableDockerCleanup off by default. Metrics configuration lives in the jsonb metricsConfig column, with refreshRate, port, token, retentionDays, cronJob and the thresholds.cpu and thresholds.memory limits. The API exposes server.setup, server.validate, cluster.addWorker, cluster.addManager, cluster.getNodes and swarm.getNodeApps. The separate build type lets you move image builds off the machines serving traffic, which on a single server is often the difference between a working site and a crawling one.

On the minus side, and this deserves saying plainly: the panel is not highly available. The dokploy service starts with --replicas 1 and a node.role == manager constraint, updates in stop-first order, and its database is a single dokploy-postgres service with a local volume on that same manager machine. If that node dies, you lose the panel and the state database with it. Applications spread across worker nodes keep running as long as the swarm retains manager quorum, but you cannot deploy a new version, read logs through the panel or change a domain.

LayerScales beyond one serverSurvives loss of the panel node
Applications and Compose servicesyes, through swarm worker nodesyes, while the swarm has quorum
Image buildsyes, through build type serversyes
Dokploy panelno, one replica on the managerno
Panel state databaseno, local volumeno
Traefika separate container per servertraffic on that server stops

If you want a platform where the vendor takes care of control-plane availability, look at Render, Railway or Fly.io instead. Dokploy gives you control and a server bill, but responsibility for panel continuity stays on your side.

Backups and disaster recovery

The built-in database backups are concrete and have a readable model. The backup table has schedule holding a cron expression, enabled, database, prefix, serviceName, destinationId, keepLatestCount, includeEncryptionKey on by default, and backupType valued database or compose. The target is described by the destination table with accessKey, secretAccessKey, bucket, region, endpoint, provider and additionalFlags, meaning any S3-compatible store.

The databaseType enum covers postgres, mariadb, mysql, mongo, libsql and web-server. Two observations from that list. The web-server value is a backup of Dokploy's own database, also available manually through backup.manualBackupWebServer, so the panel state can be taken off the server. Redis is not on the list, even though Dokploy can create and manage it; for volumes there is a separate mechanism with the volumeBackups.create and volumeBackups.runManually endpoints.

What the database backup does not cover matters just as much. The entire file layer lives in /etc/dokploy and falls outside that mechanism. You will find the traefik, traefik/dynamic, traefik/dynamic/certificates, logs, applications, compose, ssh, monitoring, registry, schedules, volume-backups, volume-backup-lock and patch-repos subdirectories there. The acme.json certificate store sits there too.

Code
Bash
# what you actually have to take off the server to restore everything
tar czf dokploy-etc-$(date +%F).tar.gz /etc/dokploy

# dump the panel database straight from the swarm task, without the panel
CID=$(docker ps -q -f name=dokploy-postgres)
docker exec "$CID" sh -c \
  'pg_dump -U dokploy -d dokploy -Fc -f /tmp/dokploy.dump'
docker cp "$CID":/tmp/dokploy.dump ./dokploy.dump

# restoring onto a clean install: the custom format goes through pg_restore
docker exec -i "$CID" pg_restore -U dokploy -d dokploy --clean --if-exists \
  < ./dokploy.dump

These three commands are not a product feature, they are something you have to arrange yourself. The names in them are real: the service is called dokploy-postgres, the user and database are both dokploy, and the password sits in a Docker secret mounted at /run/secrets/postgres_password. If you want to understand the difference between the custom format and a plain text dump, read the PostgreSQL article, because an outage is the wrong time to learn it.

The bill and how it compares

The vendor's cloud variant has a server-rendered pricing page, so it could be read without a browser. The Hobby plan costs 4.50 dollars per month per server and includes one server, one organisation, one user, two environments, one volume backup per application, one backup per database and one scheduled job per application, with Discord support. The Startup plan starts at 15 dollars per month and includes three servers, three organisations, unlimited users, environments, backups and scheduled jobs, basic Admin and Developer roles, two-factor authentication, and email and chat support. Additional servers cost 4.50 dollars per month in both plans. The Enterprise plan has two delivery modes, cloud and self hosted, and is priced through sales. There is also an Agency plan available only on request.

I checked the arithmetic of that ladder, because it is not obvious. Three servers on Hobby cost 13.50 dollars, while Startup with the same three servers costs 15.00. At four servers Hobby comes to 18.00 and Startup to 19.50. So the higher plan buys you the removal of limits rather than compute, and for single-person use Hobby stays cheaper regardless of machine count. The annual billing toggle is labelled "Yearly (20% discount)", but the annual amounts do not render without JavaScript. From the stated 20 per cent that works out to 43.20 dollars a year for Hobby and 144 dollars for Startup, though that is my arithmetic, not a figure the vendor printed. The answers in the questions section of that page, including the one to "Do I need to provide my own server?", also fail to render without JavaScript, so I do not quote them.

Now an honest self-hosting bill, with the assumptions stated. Assume a two-core, 4 GB server at 8 dollars a month; that is an assumption, check with your provider. Assume two hours a month for system updates, log review, Docker cleanup and a restore drill, valued at 50 dollars an hour; that is also an assumption and yours may be zero or three times higher.

ItemDokploy self-hostedDokploy Cloud, Startup plan
Panel0 USD, on your server15 USD a month, three servers included
Application server8 USD a month (assumption)8 USD a month, still yours
Panel updatesyoursthe vendor's
Panel backupsyoursthe vendor's
Administrator time2 h a month, 100 USD (assumption)less, but not zero
Total under these assumptions108 USD a month, of which 100 USD is your time23 USD a month plus your time, reduced but not zero

The takeaway from that table is that self-hosting is not free, it moves the cost from an invoice to your calendar. Fifteen dollars a month buys panel maintenance, not application maintenance, because the worker machines remain yours in both variants.

Against the competition: Coolify is the closest equivalent, and the differences are concrete rather than cosmetic. Coolify has a uniform Apache 2.0 licence with no directory carved out for commercial customers, and its cloud variant costs 5 dollars a month for two servers plus 3 dollars for each additional one. Dokploy has a licence gate on enterprise features, but in exchange it has a Docker swarm with first-class addition of manager and worker nodes. Choosing between them means choosing between a simpler licence and a built-in cluster.

Common mistakes

The first is running the installer on a machine that already runs a Docker swarm. The script calls docker swarm leave --force without asking, and that destroys the existing cluster along with its service definitions.

The second is npm install dokploy in the belief that it installs the official client. That package comes from a third party, has been stuck at version 0.1.3 since October 2025 and has no licence field. The official packages carry the @dokploy scope.

The third is using features from the proprietary directories in production without an agreement with the vendor. Single sign-on, SCIM, the audit log, fine-grained roles and white labelling are present in the code and technically work once a key is activated, but the licence ties production use to a commercial agreement.

The fourth is treating a scheduled database backup as a backup of everything. The whole /etc/dokploy directory falls outside it, including acme.json, the SSH keys for remote servers and the generated Compose files.

The fifth is assuming that adding a worker node makes the panel fault-tolerant. The panel and its database are pinned to the manager node and run one replica each.

The sixth is leaving test@localhost.com in the ACME configuration and api.insecure enabled. The first costs you certificate expiry warnings, the second opens the Traefik API if you ever publish port 8080.

The seventh is handing out panel admin accounts to people you would not give root on the server. The panel has the Docker socket mounted for writing, so it is exactly the same level of access.

The eighth is pinning to a Traefik version from a single source. The installer and the release source give two different versions, so check what is actually running with docker inspect dokploy-traefik.

FAQ

May I use Dokploy commercially, hosting client applications?

Yes. The core is Apache 2.0, which does not forbid offering the product as a service or charging for it. The restriction applies only to code in the proprietary directories, that is single sign-on, SCIM, the audit log, fine-grained roles, forward authentication and white labelling. Production use of those requires a valid agreement with Dokploy Technology.

How does Dokploy differ from Coolify?

In three ways. Dokploy runs on Docker Swarm and has built-in addition of manager and worker nodes, which Coolify does not offer in that form. Coolify's licence is uniform, Apache 2.0 for everything, while Dokploy has a directory carved out under a restricted licence. The cloud pricing counts differently: Dokploy charges 4.50 dollars per server, Coolify charges 5 dollars for two servers plus 3 dollars for each additional one.

Will Dokploy survive the loss of the server the panel runs on?

Not as far as the panel is concerned. The dokploy service has one replica pinned to the manager node, and its PostgreSQL database sits on a local volume on that same machine. Applications on worker nodes keep running as long as the swarm has quorum, but you cannot deploy. Recovery needs both a panel database dump and a copy of the /etc/dokploy directory.

Which npm package is the official one?

The official ones are @dokploy/cli, @dokploy/sdk and @dokploy/mcp, all at version 0.30.2, published from the siumauricio account. The unscoped dokploy package belongs to a third party. The platform itself is not published to npm, only as the dokploy/dokploy image.

What does running this yourself actually cost?

Under the assumptions in the table above, a server at 8 dollars and two hours of administration at 50 dollars, it comes to 108 dollars a month, of which 100 is your time. The server itself is the smallest line on the bill. If your time is cheap, or you already maintain servers anyway, the arithmetic looks entirely different.

Does Dokploy use Traefik or Caddy?

Traefik. The installer starts a dokploy-traefik container from the traefik:v3.6.7 image, while the TRAEFIK_VERSION constant in the 0.30.2 source points at 3.6.25. The main configuration lives in /etc/dokploy/traefik/traefik.yml and the dynamic rules in /etc/dokploy/traefik/dynamic, which is watched continuously.

Sources: the Dokploy/dokploy repository, the vendor's pricing page, package metadata on npm.

Read next

We use cookies to enhance your experience on the site