Skip to main contentYour first top-up gets $5 in bonus credit — one-time, for every new account. Create your account
Krova CloudKrova Cloud

Install Dokploy on a Cube

Install Dokploy on a Cube to get a self-hosted PaaS — deploy apps from Git, with Traefik and automatic TLS. Includes the one step the installer gets wrong on a Cube.

Dokploy is an open-source, self-hosted PaaS — a web UI over Docker Swarm and Traefik that deploys apps from a Git repository, provisions databases, and issues TLS certificates. It is the self-hosted answer to Heroku or Vercel, and a Cube is a good place to run it: you get root, real resources, and no per-seat pricing.

The install itself is one command. The part worth reading carefully is Step 4 — the installer finishes by printing a URL that does not work on a Cube, and following it will leave you thinking the install failed when it did not.

Before you start

Dokploy's own requirements are 2 GB RAM and 30 GB of disk, on Ubuntu 24.04 among other distributions.

That 30 GB puts this guide above the Welcome tier, which caps a Cube at 20 GB. You need Starter or above — saving a payment card unlocks Starter, which allows 40 GB. Everything else here fits comfortably.

  • A Cube of 2 vCPU, 4 GB RAM, 40 GB disk — about $0.0140/hour, roughly $0.34/day or $10/month if left running.
  • An SSH key pair, as with any Cube.
  • Optionally a domain you control, if you want to reach Dokploy at a real address rather than through a tunnel.

Step 1 — Create the Cube

Create a Cube with the Ubuntu 24.04 + Docker image. The installer will install Docker itself if it is missing, but starting from the Docker image skips that step and a few minutes of package work.

Size it at 2 vCPU / 4 GB / 40 GB. Dokploy idles at a few hundred MB, but every app and database you deploy runs on the same Cube, so the headroom is the point.

Step 2 — Connect over SSH

ssh root@<cube-host> -p <port>

If you have deleted and recreated a Cube, your SSH client may refuse to connect with a host-key warning. Host ports are recycled, so a new Cube can be handed the port a previous one used — and it has its own host key. Drop the stale entry and reconnect:

ssh-keygen -R "[<cube-host>]:<port>"

Before installing, confirm the ports Dokploy needs are free:

ss -ltn | grep -E ":(80|443|3000)\s"

That should print nothing. The installer refuses to run if 80, 443 or 3000 is already in use.

Step 3 — Run the installer

Dokploy publishes a single install script. Fetch it, look at it, then run it — piping a remote script straight into a shell is worth avoiding as a habit, even from a project you trust:

curl -fsSL https://dokploy.com/install.sh -o install.sh
less install.sh
sh install.sh

It initialises Docker Swarm, starts Dokploy and a PostgreSQL container for its own state, and pulls Traefik to handle inbound traffic. Give it a few minutes. When it finishes you should see two healthy services:

docker service ls

Both dokploy and dokploy-postgres should read 1/1.

Step 4 — Ignore the URL it prints

The installer ends with "Please go to http://<some-ip>:3000". On a Cube that address will not load. Nothing is broken — the installer asks the internet what your public IP is, and because a Cube reaches the internet through its host, the answer it gets back is the host's address, not the Cube's. Port 3000 was never published there, so the connection simply times out.

Reach it over an SSH tunnel instead. Run this on your machine:

ssh -L 3000:localhost:3000 root@<cube-host> -p <port>

Leave it open and visit http://localhost:3000. You should get Dokploy's Setup the server screen.

Step 5 — Create the admin account first

That first screen is an unauthenticated registration form, and it creates the server's administrator. Whoever loads it first becomes the admin.

So create your account before Dokploy is reachable from anywhere else. Doing it through the tunnel means the form is only ever exposed to your own machine. If you publish port 3000 first and register afterwards, anything that reaches the port in between can claim the server.

Once you have registered and logged in, the tunnel has done its job.

Step 6 — Give it a real address

A tunnel is fine for setup, but you will not want to open one every time. Point a domain at the Cube instead.

The important thing to understand first: TLS is terminated at Krova's edge, not inside your Cube. A Cube has no inbound address of its own, so a certificate requested by something running inside it can never be validated. Dokploy ships Traefik and Traefik can normally issue its own certificates — on a Cube it cannot, and it does not need to. Krova issues and renews the certificate for you, and forwards plain HTTP to a port inside the Cube.

Map the domain

Add a DNS record for your domain pointing at dns.krova.cloud (the Cube's networking tab has a copy button for it). Then, on that tab, choose Add Domain:

  • Domain — the hostname, e.g. dokploy.example.com.
  • Port3000, the port the Dokploy UI listens on inside the Cube. This is the field to get right: the default is 80, which is Traefik, not the dashboard.
  • This app serves HTTPS itself — leave it unchecked. Dokploy serves the dashboard over plain HTTP internally; Krova adds the TLS.

The domain appears as Active with HTTPS live once the certificate is issued, and the dashboard is then reachable at https://your-domain with no tunnel and no published port 3000.

If your DNS is behind Cloudflare

With the orange cloud on, set Cloudflare's SSL/TLS mode to Full.

  • Flexible fetches the origin over plain HTTP and causes an endless redirect loop.
  • Full (Strict) fails, because Krova's ingress presents a self-signed origin certificate. Full encrypts to the origin without demanding a publicly-trusted certificate there, which is exactly the right setting.

Krova detects a proxied domain and shows this warning on the mapping itself, so you do not have to remember which mode you picked.

Domains for the apps you deploy

Krova notices Dokploy running on the Cube and offers domain sync: it reads the domains Dokploy is actually serving and creates the matching routes here, so each hostname is only entered once.

Sync reads Dokploy's live routing config, so a domain you have only just added in Dokploy shows up after you redeploy the service or reload its proxy. Anything not routable — Dokploy's internal *.docker.localhost names, for instance — is ignored, and domains you added here by hand are left alone rather than overwritten.

Or a TCP port mapping, allow-listed

If you would rather reach port 3000 directly without a domain, add a TCP port mapping for 3000 and put your own IP in the IP Whitelist.

Do not publish port 3000 without an allow-list. It is an admin control panel for a machine that can deploy arbitrary code; leaving it open to the internet is the worst version of this setup.

What it costs

The Cube described here bills at about $0.0140/hour — roughly $0.34/day, or $10/month if you leave it running. Usage is metered by the minute.

Unlike a database you can pause, a PaaS is usually the thing everything else depends on, so plan on leaving it running. If you do power the Cube off, Dokploy and its containers come back with the disk — you are billed only for storage while it is stopped.

Cleaning up

Deleting the Cube removes Dokploy, every app it deployed, and its database along with the disk. If anything on it matters, snapshot first — and remember that Dokploy's own state lives in its PostgreSQL container, so a snapshot of the Cube is what captures it.

Next steps

  • Custom domains — required for serving Dokploy and its apps over HTTPS.
  • Deploy PostgreSQL on a Cube — if you would rather run a database directly than through Dokploy.
  • Cubes — resizing, snapshots, and how billing works when a Cube is stopped.