Deployment guide

Portainer vs Dokploy: which to deploy in 2026?

Deploy on a VPS Cloud →

Comparison

Portainer vs Dokploy: which to deploy in 2026?

Portainer and Dokploy are two web interfaces for managing Docker containers on a VPS. Portainer is the established tool — stable, well-documented, but shaken in 2026 by the end of the Community Edition and by CVEs scoring 9.4. Dokploy is the open-source challenger, PaaS-ready, addressing exactly what Portainer CE no longer covers. This guide helps you decide: architecture, licenses, security, migration.

12 min read10 steps
Contents· Why self-host a deployment interface on a VPS1/14
  1. 01Why self-host a deployment interface on a VPS
  2. 02What you gain by deploying this template on your VPS
  3. 03Portainer in 2026: the end of the Community Edition
  4. 04Critical Portainer 2.x CVEs: check and patch
  5. 05Dokploy CVE: the hardcoded secret (< 0.29.3)
  6. 06Prerequisites to host Portainer or Dokploy
  7. 07Minimum recommended resources
  8. 08Deploy Dokploy on a VPS (≥ 0.29.13)
  9. 09Portainer as an alternative — quick installation
  10. 10Portainer 2.x vs Dokploy — full comparison 2026
  11. 11When to stay on Portainer, when to move to Dokploy
  12. 12Migration from Portainer to Dokploy: concrete steps
  13. 13Troubleshooting: common errors
  14. 14The two tools are not always mutually exclusive

Why self-host a deployment interface on a VPS

A bare VPS with Docker leaves you with one interface: the command line. That works for one machine, gets tedious for five, and becomes unmanageable for a team. A web interface centralises logs, image updates, environment variables and TLS certificates — without forcing you to maintain a full CI/CD pipeline from day one.

Two families compete: managers (Portainer, Yacht) that expose Docker as-is, and lightweight PaaS (Dokploy, Coolify, CapRover) that add a deployment layer — Git branches, automatic domains, Let's Encrypt certificates. The difference is not cosmetic: it determines whether your developers can deploy on their own or need SSH access.

What you gain by deploying this template on your VPS

  • Deploy from Git or Docker Hub in a few clicks, no SSH required
  • Automatic TLS certificate management via Let's Encrypt
  • Versioned environment variables, isolated per project
  • Centralised logs and web terminal from your browser
  • Health dashboard: CPU, RAM, container status
  • Manage Docker volumes and networks without memorising commands

Portainer in 2026: the end of the Community Edition

Portainer CE (Community Edition) was the reference tool for years. With Portainer 3, the vendor ended the Community Edition: Portainer 3 has no CE edition, and CE 2.45 is the last Community release. Portainer 3 ships as Business Edition (free for up to three nodes with the "3 Nodes Free" licence), puts Kubernetes first for new features and keeps Docker, Swarm and Podman. CE 2.45 instances keep running and receive the 2.45 LTS fixes until August 2027, but no new features.

This shift has several practical consequences. New installations looking for a free Docker interface have no CE roadmap. The portainer/portainer-ce images still exist and receive fixes from the 2.45 branch, but will not evolve further. And critically — Portainer 2.x has accumulated critical flaws, including two CVEs scoring 9.4, which remain exploitable on any unpatched installation.

If you are still running Portainer 2.x, the question is not whether to migrate on principle: it is whether your instance is up to date and whether the risk is acceptable.

Critical Portainer 2.x CVEs: check and patch

Two CVEs affect every Portainer branch up to the fixed versions below (versions before 2.33.0 are end-of-life and will not be fixed):

CVE-2026-44848 (CVSS 9.4) — The /plugins/* endpoints of the Docker API proxied by Portainer bypass authorization checks. A standard (non-admin) user with access to a Docker environment can install and enable a Docker plugin, which runs as root on your host.

CVE-2026-44849 (CVSS 9.4) — The Swarm restrictions mechanism can be bypassed: a Portainer user with reduced rights can perform actions normally reserved for administrators on a Swarm cluster.

Fixed versions: 2.33.8, 2.39.2, 2.41.0. Further critical flaws have been published since, fixed in 2.45.2 and 2.45.3 and with no fix on the 2.39 branch: target 2.45.3 LTS, the latest release as of 7 November 2026.

To check your version:

docker exec portainer /portainer --version

To update:

docker pull portainer/portainer-ce:lts
docker stop portainer
docker rm portainer
docker run -d \
  --name=portainer \
  --restart=always \
  -p 127.0.0.1:9443:9443 \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v portainer_data:/data \
  portainer/portainer-ce:lts

If you are below 2.45.3, update before continuing to use the instance. This command publishes the interface on 127.0.0.1 only: reach it through an SSH tunnel (ssh -L 9443:127.0.0.1:9443 user@your-vps, then https://localhost:9443) or a reverse proxy. Add -p 8000:8000 only if you use Edge agents. Portainer exposed on the internet without patches is a direct intrusion vector into your Docker host.

Dokploy CVE: the hardcoded secret (< 0.29.3)

Dokploy is not without vulnerabilities. CVE-2026-45631 (CVSS 10.0) affected default installations prior to 0.29.3: when the BETTER_AUTH_SECRET variable was not set — and the install script did not set it — the code fell back to a hardcoded value, identical on every instance. Anyone could forge a token and take over the administrator account, without authentication.

The fix landed in 0.29.3, together with a migration script to run after updating. Many other critical flaws (command injections, missing access controls) were fixed up to 0.29.13: do not stay below it, and target the latest release (0.31.0 as of 7 November 2026). To check and update:

# Check the installed version (service image tag)
docker service inspect dokploy --format '{{.Spec.TaskTemplate.ContainerSpec.Image}}'

# Update via the official script
curl -sSL https://dokploy.com/install.sh | sh -s update

Since 0.29.3, Dokploy reads BETTER_AUTH_SECRET from a Docker secret (BETTER_AUTH_SECRET_FILE variable). After updating, check that the service uses it:

docker service inspect dokploy --format '{{range .Spec.TaskTemplate.ContainerSpec.Env}}{{println .}}{{end}}' | grep BETTER_AUTH_SECRET_FILE

If the line is missing, run the official security script published with 0.29.3: it generates a unique secret and updates the service.

curl -sSL https://dokploy.com/security/0.29.3.sh | bash

Prerequisites to host Portainer or Dokploy

Both tools run on Docker. Dokploy requires slightly more resources as it bundles a PostgreSQL database and a Traefik proxy alongside the main service.

Minimum recommended resources

  • Portainer 2.x: the vendor publishes no hardware minimum; 2.45.3 is validated with Docker 28.5.1 and 29.8.1 — runs on a small VPS
  • Dokploy: at least 2 GB RAM and 30 GB disk according to the official documentation — PostgreSQL and Traefik run alongside the main service
  • A domain or subdomain pointing to your VPS (Dokploy needs it for automatic certificates)
  • Ports 80 and 443 open if you use Let's Encrypt via Traefik (Dokploy)
  • Root or sudo SSH access for initial installation

Deploy Dokploy on a VPS (≥ 0.29.13)

  1. Install via the official script

    The simplest and most up-to-date method:

    curl -sSL https://dokploy.com/install.sh | sh

    The script installs Docker if needed, initialises Docker Swarm, creates the dokploy and dokploy-postgres services plus the dokploy-traefik container (configuration in /etc/dokploy/), generates a random BETTER_AUTH_SECRET stored in a Docker secret and starts everything.

  2. Verify the BETTER_AUTH_SECRET

    After installation, make sure the service reads its secret:

    docker service inspect dokploy --format '{{range .Spec.TaskTemplate.ContainerSpec.Env}}{{println .}}{{end}}' | grep BETTER_AUTH_SECRET_FILE

    You should see a BETTER_AUTH_SECRET_FILE=/run/secrets/... line: the value (64 hex characters generated by openssl rand -hex 32) stays in the Docker secret and never appears in clear text. If the line is missing (older installation), run the official security script:

    curl -sSL https://dokploy.com/security/0.29.3.sh | bash
  3. Access the interface and create the admin account

    Dokploy listens on port 3000 by default. Open http://<your-vps-ip>:3000 in your browser. The first visit prompts you to create the administrator account. Do this immediately — the interface is public until this account exists.

  4. Configure your domain and enable HTTPS

    In Settings → Web Server → Server Domain, enter your FQDN (dokploy.yourdomain.com). Traefik automatically retrieves a Let's Encrypt certificate via ACME HTTP-01. Your DNS must point to the VPS before this step. Once the interface is served over HTTPS, close port 3000 to the internet, as Dokploy's hardening guide recommends: ufw alone does not filter Docker-published ports, so use ufw-docker or your provider's firewall.

  5. Update Dokploy

    Dokploy exposes an update button in Settings → Web Server, or use the script:

    curl -sSL https://dokploy.com/install.sh | sh -s update

    With the update argument, the script pulls the latest release image and updates the dokploy service without overwriting your configuration or projects. Without it, the script runs a full installation, which fails on a server where Dokploy is already installed (ports 80, 443 and 3000 in use).

Portainer as an alternative — quick installation

If you prefer to stay on Portainer (existing instance or deliberate choice), the reference command:

docker run -d \
  --name=portainer \
  --restart=always \
  -p 127.0.0.1:9443:9443 \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v portainer_data:/data \
  portainer/portainer-ce:lts

Access through an SSH tunnel (ssh -L 9443:127.0.0.1:9443 user@your-vps, then https://localhost:9443) or a reverse proxy. Replace lts with 2.45.3 to pin the version and avoid silent updates.

Portainer 2.x vs Dokploy — full comparison 2026

Scroll the table

CriterionPortainer 2.xDokploy
LicenceCE free (zlib licence)Apache 2.0 (except /proprietary folder)
CE futureCE stops at 2.45 (fixes until August 2027)Active roadmap, growing community
Active CVEsCVE-2026-44848 + 44849 (CVSS 9.4) and later advisories: target 2.45.3CVE-2026-45631 (CVSS 10.0) if < 0.29.3; target ≥ 0.29.13
Minimum RAMNot published (lightweight tool)2 GB (PostgreSQL + Traefik included)
Git deploymentYes (Compose stacks from a Git repository)Yes (GitHub, GitLab, Gitea, Bitbucket)
TLS certificatesManual (external reverse proxy)Automatic Let's Encrypt via Traefik
App templatesYes (built-in library)Yes (imported Docker Compose)
Private registryYesYes
Integrated CI/CDGitOps updates (polling or webhook)Git webhooks + notifications
KubernetesYes (CE and BE)No (Docker Compose / Swarm)
Multi-serverYes (endpoints)Yes (remote servers over SSH)
InterfaceMature, exhaustiveModern, project-oriented

When to stay on Portainer, when to move to Dokploy

Staying on Portainer 2.x makes sense in three situations: you already manage a Docker Swarm or Kubernetes cluster with complex configurations; you have teams that know the interface well with documented runbooks; or you need the level of detail on networks and volumes that Portainer exposes natively.

In these cases, the non-negotiable requirement is being on an up-to-date version (2.45.3 as of 7 November 2026) and restricting access to the interface: never expose port 9000/9443 directly on the internet, place Portainer behind a reverse proxy with additional authentication if non-admin users access it.

Migrating to Dokploy is the right decision if: you are starting fresh on a new VPS; you want developers to deploy from Git without SSH; you manage multiple domains and do not want to maintain Nginx/Traefik manually; or you are looking for an alternative after the end of CE (Portainer 3 has no Community Edition) for your Docker use case.

Migration from Portainer to Dokploy: concrete steps

  1. Export your Portainer inventory

    Before migrating, list your active stacks and containers:

    docker ps --format 'table {{.Names}}	{{.Image}}	{{.Status}}'
    docker volume ls
    docker network ls --filter driver=bridge

    For each Portainer stack, retrieve the docker-compose.yml from the interface (Stacks → your stack → Editor) or from the filesystem.

  2. Back up data volumes

    Named volumes contain your application data. Back them up before any operation:

    docker run --rm \
      -v <volume_name>:/data \
      -v $(pwd):/backup \
      alpine tar czf /backup/<volume_name>.tar.gz /data

    Repeat for each critical volume.

  3. Install Dokploy on the same VPS or a dedicated VPS

    If migrating on the same host, stop Portainer first to free the ports:

    docker stop portainer && docker rm portainer

    Then run the Dokploy installation (see procedure above). Dokploy uses Traefik on ports 80/443 — verify no other service occupies them.

  4. Recreate your projects in Dokploy

    In Dokploy, create a Compose Project for each Portainer stack:
    1. Projects → New project
    2. Add a Docker Compose type service
    3. Paste your docker-compose.yml or point to your Git repository
    4. Configure environment variables in the Environment tab
    5. Assign a domain — Dokploy configures Traefik automatically

  5. Verify and switch DNS

    Deploy first on a test subdomain (test.yourdomain.com). Once validated, update your DNS entries to point to Dokploy. Traefik issues certificates automatically once DNS propagates.

Troubleshooting: common errors

Portainer — interface unreachable after update
Verify that the portainer_data volume is properly mounted. An update without a named volume starts from an empty base and prompts for admin account creation again.

Portainer — TLS handshake error on port 9443
Portainer generates a self-signed certificate. Your browser warns you correctly. Place Portainer behind a reverse proxy (nginx, Caddy) with a real certificate for secure production access.

Dokploy — Traefik not generating a certificate
Most common cause: DNS has not yet propagated to the VPS. Check with dig +short your-domain.com. Traefik waits for a valid DNS response before starting the ACME challenge. If DNS is correct, verify port 80 is open (ufw allow 80).

Dokploy — Git deployment failing silently
Check the service logs in the interface (Deployments → Logs tab). On a private repository, a frequent cause is a missing SSH key, or one not authorised on the repository. Dokploy lets you create one in Settings → SSH Keys (Create SSH Key button), to add as a deploy key on the repository; for GitHub, GitLab, Gitea or Bitbucket, you can also connect the provider in Dokploy's Git settings.

The two tools are not always mutually exclusive

Portainer can manage multiple remote Docker endpoints from a single interface — including a VPS where Dokploy is installed. Some teams keep Portainer as an observation tool and Dokploy as a deployment tool. This is not an antipattern if roles are clearly separated. The cost: two surfaces to patch. If you have chosen this architecture, make sure both tools are up to date — see the CVEs at the start of the article.

To go further: alternatives to Portainer CE, complete Dokploy deployment guide and the critical Dokploy CVE 2026 update.

Deploy Dokploy on your VPS in minutes

On a ServOrbit VPS with root access, Dokploy installs manually and sets up Docker, Traefik and TLS certificates. Install a version ≥ 0.29.13, patched and production-ready.