Installation
One command installs Docker, Traefik, Postgres, the control plane and the agent on a fresh Linux server.
As root, on the server:
curl -fsSL https://deplo.build/install.sh | bashIt asks for a domain. Press Enter and it generates one: the dashboard answers on
https://deplo-<hex>.nip.io, which resolves to your server with no DNS to set up.
The browser warns about the certificate once - genuinely once, the installer mints
it and keeps it - because no public authority issues for a nip.io address.
Already running Dokploy or Coolify?
The installer offers to take that machine over instead: it brings your
projects across, then takes ports 80, 443 and 3000 from the old panel and
inherits its certificates. Answer no and nothing is installed. See Take over
your VPS.
What you need
Start from a clean, stock server
A fresh VPS with nothing installed: no Docker, no Nginx, Apache or Caddy already bound to 80/443, no other control panel. The installer is built for that starting point, it's the only way to guarantee the exact experience described on this page. Anything already occupying those ports gets in the way of Traefik and certificate issuance.
| What | Requirement |
|---|---|
| A server | Ubuntu 24.04, Debian, or any other modern Linux distro, x86-64 or arm64, and root access for the length of one install command. Fresh, with nothing on it yet: no Docker, no reverse proxy on 80/443, no other control panel. Docker is installed for you if it is missing, and systemd has to be there: it is what runs the agent, so without it the dashboard comes up but the machine cannot run apps. |
| Size | 2 cores, 4 GB of RAM, 30 GB of disk is the minimum, 4 cores and 8 GB the comfortable size. Both are about your apps, not about Deplo: the platform itself fits in about 1 GB. On 2 GB it installs and runs, and then there is almost nothing left to deploy on it, so we advise against it. The installer warns below the minimum and refuses below 8 GB free on /, where Docker images alone do not fit. |
| Ports | 80 and 443 reachable from the internet, 9443 on every server, this machine included. Port 3000 is bound to 127.0.0.1 and needs nothing opened. |
| Outbound HTTPS | To ghcr.io for the image, to get.docker.com when Docker is missing, and to Let's Encrypt for the certificate. The first two are checked before anything is installed. |
| A domain | Optional. Useful, not required: the generated nip.io hostname works from the first deploy. |
| Docker knowledge | None. It is available as an escape hatch, never as a prerequisite. |
Check the machine before you commit to it
curl -fsSL https://deplo.build/install.sh | bash -s -- --check runs the preflight and exits, changing nothing on the host. It prints every blocking problem and every warning, so a server that cannot finish the install says so in ten seconds instead of halfway through.
Create your account
The installer prints a setup link at the end, next to the dashboard address:
Set up https://deplo.example.com/setup?key=a3f9c1d84b7e2065That link is the only way to create the first account. Without it the panel shows This instance isn't set up yet and nothing can be claimed - a fresh install answers on a public address whose name reaches certificate transparency logs within seconds, so the first account has to belong to whoever ran the installer rather than to whoever arrives first.
Lost the link?
Re-run the installer on the server. It prints the same link again - the key is generated once into /opt/deplo/.env and never rotates.
The link stops working on its own the moment the account exists. From then on the address goes to the sign-in page, and the key means nothing.
Open it. A fresh install starts completely empty, and the link opens the setup screen, Welcome to Deplo. It runs once: a workspace name, a username (lowercase letters, numbers, - and _), a display name, an admin email and a password, checked for length and character mix and against the Have I Been Pwned breach list. Click Create workspace to finish. That account is the instance owner: the tier above instance admin, and the only one that can hand the instance to somebody else later.
How it works
The installer is a shell script served from the repository. It is idempotent: secrets are generated once into /opt/deplo/.env, so running it again updates the containers in place and never rotates anything. If that file already exists, the script switches itself to update mode.
Everything it writes lands in /opt/deplo (secrets, the compose file, the
Traefik stack, build staging, issued certificates), see
Ports, networks, files for the full
layout on this host and on every server it later enrolls.
Three containers come up:
postgres:16-alpineon aninternalnetwork, not published to the host.ghcr.io/deplocloud/deplo, publishing port3000on127.0.0.1only: a panel on an open port is a login page on the internet with no TLS in front of it, so the dashboard is never reachable at<server-ip>:3000, only through Traefik. If the proxy itself is what broke, the way in is an SSH tunnel:ssh -L 3000:localhost:3000 root@your-server, then openhttp://localhost:3000.traefik:v3.7, holding80and443, and serving the dashboard over HTTPS.
Neither Traefik nor the control plane ever gets the Docker socket. See How Deplo works for why.
What the installer changes on the host
| Change | Why |
|---|---|
| Installs Docker if absent | Via get.docker.com, then enables the service |
Rewrites default-address-pools in /etc/docker/daemon.json | Docker's defaults allow about 31 networks and Deplo uses one per app, so an untouched host fails on its 32nd deploy. An existing pool config is never clobbered, the old file is kept as daemon.json.deplo-bak, and the new one is validated with dockerd --validate before it's used |
Creates the deplo Docker network | Every app joins it, which is how apps reach each other by name |
| Enrolls this machine as a server | Waits for /api/health, then runs the agent installer against http://127.0.0.1:3000 |
Address pool changes don't restart Docker on their own
If containers are already running when the address pools change, the installer skips the Docker restart and tells you to do it in a maintenance window. Nothing is broken until then, but the new pool doesn't apply yet.
Update it later
Re-run the same command. It pulls the newer image and restarts the stack, and your secrets stay exactly as they were. Pin a version with DEPLO_VERSION=0.4.1 in front of the command, or leave it to take latest.
The dashboard also checks for releases on its own and shows an update banner. See Upgrade for the full procedure, including the server agents, which version on their own clock.
Run it with Compose instead
docker-compose.yml in the repository runs the control plane and its Postgres behind Traefik. It's a readable, hand-editable starting point, not a copy of what the installer writes: the installer routes the panel through Traefik's file provider rather than container labels, precisely so the panel's own route can be changed from the panel later.
docker network create deplo
export DEPLO_DOMAIN=deplo.example.com # required: it is the only address it serves
export DEPLO_SECRET=$(openssl rand -base64 48)
export DEPLO_DB_PASSWORD=$(openssl rand -base64 24)
export DEPLO_SETUP_KEY=$(openssl rand -hex 8) # then open /setup?key=<it>
docker compose up -dGoing this way, you enroll the host as a server yourself from Settings -> Servers, exactly like any other machine.
Limits and gotchas
DEPLO_SETUP_KEYis yours to set here. The installer generates one; Compose does not. Leave it unset and the first account is created by whoever reaches/setupfirst.DEPLO_SECRETis not rotatable. It derives every encryption key, every session signature and the agent certificate authority. Change it and every stored secret becomes unreadable, every session ends, and every agent certificate is re-minted. Back it up with the rest of/opt/deplo/.env.- The domain must resolve before the certificate can issue. Let's Encrypt validates over HTTP on port 80. Point the A record first, install second, or re-run the installer once DNS is live. The generated address answers meanwhile.
- Agent enrollment failure is not fatal. If it fails, the dashboard still comes up and the script says so. Re-running the installer retries it.
localhost,*.localand a bare IP address are refused asDEPLO_DOMAIN. The panel needs a hostname a certificate can be issued for. Give none and the installer generates one.
If it does not work
Common failures
docker composenot found. The script requires Compose v2. Install Docker's own packages rather than a distribution'sdocker.io.- The dashboard does not answer. From the server,
curl http://127.0.0.1:3000/api/health. If that works, the proxy is the problem; if it does not, checkdocker psshows thedeplocontainer and readdocker logs deplo. A failure to reach Postgres is the usual cause. - The domain shows a certificate warning. The A record isn't resolving to this server yet, or port 80 is closed. See Domains and TLS.
- Anything else: Servers and agents.
See also
Did this page help you?