Deploy an app with Dokploy
Deploy an app through Dokploy on a Cube and give it a domain — including the one switch to leave off, the port the Krova mapping needs, and what to check after.
This picks up where Install Dokploy on a Cube left off: Dokploy is running and you can reach its dashboard. Now put an actual app behind a domain.
The Dokploy half is the same as it would be on any server — their docs cover it well. What is specific to a Cube is who issues the certificate, and that is the one thing worth reading carefully.
Step 1 — Create a project and a service
In Dokploy, create a Project, then Create Service inside it. The options are Application, Database, Compose, Template and Import. For a web app you want Application.
Step 2 — Choose a source
On the service's General tab, the Provider row offers GitHub, GitLab, Bitbucket, Gitea, Docker, plain Git, and Drop.
The Git providers need an OAuth connection set up in Dokploy's settings first — GitHub tells you so rather than failing later. If you just want to see the whole path working end to end, Docker needs nothing configured: give it a public image and press Save.
traefik/whoami:latestThat image is a useful first deploy because it echoes the request back to you — so once it is live, the response itself tells you the routing worked and what reached the container.
Step 3 — Add the domain in Dokploy, with HTTPS off
On the service's Domains tab choose Add Domain:
- Host — the hostname, e.g.
app.example.com. - Container Port — the port your container listens on. For
traefik/whoamithat is80. - HTTPS — leave it off.
That last one matters. The switch tells Dokploy's Traefik to request its own Let's Encrypt certificate, and on a Cube that cannot succeed: a Cube has no inbound address of its own, so an ACME challenge issued from inside it can never be validated. Krova issues the certificate at its edge instead and forwards plain HTTP inward.
With HTTPS off, the domain row in Dokploy reads HTTP and Cert: none. That is the correct state, not a missing step — the certificate exists, it just lives one layer out.
Step 4 — Deploy
Back on General, press Deploy and confirm. Dokploy pulls the image and starts it as a Docker Swarm service. On the Cube you can watch the result directly:
docker service lsYour service appears alongside dokploy and dokploy-postgres, and should read 1/1.
Step 5 — Add the domain on the Cube
Dokploy is serving the domain now, but Krova does not know about it yet. Add it on the Cube's Networking tab.
Use Port 80 — that is Dokploy's Traefik, not your container's port. Traefik then routes by hostname to the right container, which is why one mapping covers every app you deploy through Dokploy rather than needing one per container.
Step 6 — Check what actually arrived
Load the domain. With traefik/whoami the response shows the full path the request took:
Hostname: 7402d1632397
RemoteAddr: 10.0.1.4:53358
GET / HTTP/1.1
Host: app.example.com
Cf-Connecting-Ip: 203.0.113.50Hostnameis the container ID — you reached the app, not an error page.RemoteAddris Dokploy's Traefik on the Swarm overlay network, which is the hop in front of your container.Cf-Connecting-Ipis the real client address, preserved through the whole chain — so per-visitor logging and rate limiting behave the way you expect.
When something does not work
- 503 from the domain — Krova reached your Cube but not your app. Check the service is
1/1indocker service ls, and that the container port on the domain matches what the image actually listens on. - The domain never appears in Krova — sync reads live routing, so redeploy the service after adding the domain in Dokploy.
- A certificate warning — check the HTTPS switch in Dokploy is off. If Traefik is trying to serve its own certificate, that is the one it failed to obtain.
Next steps
- Install Dokploy on a Cube — if you have not set the Cube up yet.
- Run a Node.js app on a Cube — the same result without a PaaS, using systemd directly.
- Custom domains — per-domain settings and the Cloudflare specifics.
