Deplo

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 | bash

It 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.

WhatRequirement
A serverUbuntu 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.
Size2 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.
Ports80 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 HTTPSTo 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 domainOptional. Useful, not required: the generated nip.io hostname works from the first deploy.
Docker knowledgeNone. 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=a3f9c1d84b7e2065

That 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-alpine on an internal network, not published to the host.
  • ghcr.io/deplocloud/deplo, publishing port 3000 on 127.0.0.1 only: 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 open http://localhost:3000.
  • traefik:v3.7, holding 80 and 443, 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

ChangeWhy
Installs Docker if absentVia get.docker.com, then enables the service
Rewrites default-address-pools in /etc/docker/daemon.jsonDocker'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 networkEvery app joins it, which is how apps reach each other by name
Enrolls this machine as a serverWaits 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 -d

Going this way, you enroll the host as a server yourself from Settings -> Servers, exactly like any other machine.

Limits and gotchas

  • DEPLO_SETUP_KEY is yours to set here. The installer generates one; Compose does not. Leave it unset and the first account is created by whoever reaches /setup first.
  • DEPLO_SECRET is 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, *.local and a bare IP address are refused as DEPLO_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 compose not found. The script requires Compose v2. Install Docker's own packages rather than a distribution's docker.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, check docker ps shows the deplo container and read docker 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?

On this page