Docker site type
A site type that runs a containerized app from a compose file inside an instance — each app with its own directory, port, and route — served and managed like any other site.
The docker (compose) site type runs a containerized app from a docker-compose.yml inside an
instance, served through the same domain → route → port → SSL chain as every other site. It's a
peer of your WordPress / PHP / static / Node sites, and it's per-app: an instance hosts many
Docker apps, each with its own compose directory, published port, compose project, and route.
Many Docker apps per instance
A Docker app is a site. An instance hosts many of them, each with its own compose directory
(/srv/docker/<app>), its own published port (not a shared 8080), its own compose project,
and its own route. Two Docker apps in one instance sit side by side and never collide — just like
two Node apps. Once running, see and control them all from the
Docker management plane.
What it is
The Docker type works like every other site type — same wizard, same validation, same launch flow. The only difference is its runtime: a container, rather than software installed on the host. You create a Docker app from the new-site wizard like any other type, and it gets a served port, a domain, and SSL the same way.
How it works
Launching a Docker site runs these steps inside the instance:
- Install docker — only if it's not already there, then start it. Docker isn't a catalog service; it's installed as part of the launch (the same way the Node type installs its runtime).
- Write the per-app compose — a
docker-compose.ymlplus a starter webroot under the app's own directory/srv/docker/<app>(where<app>is the site's slug). Never a shared directory. - Bring the stack up — run
docker compose up -dunder the app's own compose project, so two Docker apps in one instance never share state and each container is clearly attributed to its site. The site's environment plus its served port fill in the compose file's${VAR}values. - Wait and smoke-test — poll the published port until it answers, then check it. A failed check
leaves the site
failedwith a remedy, never green — the same rule as every type.
How the port reaches the web
The compose service publishes its container port on the instance at the site's served port — allocated the same way a Node/PHP/static site gets one. When you attach a domain, the node's reverse proxy (Caddy) routes the hostname to that port, exactly as it does for a Node app. Two Docker apps get two ports and two routes; nothing about routing is docker-specific.
Editing the compose file (the Compose tab)
A Docker site gets a Compose tab (right after Environment) that edits its docker-compose.yml in
place — the same way the Environment editor works: the raw file is the
source of truth, a table flips on top, and a two-step Save → Apply stages then relaunches.
- Raw is the source of truth. The whole
docker-compose.yml— your#comments, blank lines, and ordering — is the editable text, and it's saved and kept (it comes back on reload). Paste a whole file in the YAML view; nothing is rewritten or reordered behind your back. - The table flips on top. The Ports view shows a per-service table (service, image, container port, published port, restart) built from that text. Editing a service's published port in the table changes only that one line — every other line, comment, and the container port stay put. Switching between YAML and Ports never loses a comment.
- Two-step Save → Apply. Save stages the file. Apply changes relaunches the app so the edited compose lands in the instance. Just like the env editor: nothing changes until you apply.
- Port-collision guard. Each port on an instance must be unique, so Save refuses a published
port another site on the same instance already uses, with a clear
port N is taken by site "X"message — before a relaunch could fail. Pick a free port and Save again.
Read-only without manage permission
Viewing the Compose tab needs the sites view permission; editing (Save / Apply) needs the
sites manage permission (admin-only) — the same grants as the environment editor. The tab shows
only for docker-type sites.
Connecting to a database
When you tick "create a database" for a Docker app, SpipCP installs the database engine on the
instance host and creates a database and user, just like a Node or WordPress site. Because a container
has its own network, 127.0.0.1 inside the container is the container — not the host — so the
starter compose wires the connection for you:
extra_hosts: host.docker.internal:host-gatewaylets the container reach the database on the instance host.- The credentials are passed into the container as
DB_HOST(defaults tohost.docker.internal),DB_NAME,DB_USER, andDB_PASSWORD— your app reads them like any container environment variable.
Point your image at the right vars
Your image must read DB_HOST / DB_NAME / DB_USER / DB_PASSWORD (or you map them to whatever
names your image expects in the compose environment: block). The DB runs on the host, reached at
host.docker.internal from inside the container — not localhost.
Managing & monitoring
Once a Docker app is running, the Docker management plane is where you see and control it — fleet-wide and per-app:
- Status, health, CPU, memory, size — refreshed regularly and shown honestly (a crash-looping or unhealthy container reads as degraded / failed, never green).
- Lifecycle — start, stop, restart, recreate, and pull (the update path) per app.
- Live logs — container logs streamed into the browser.
- Alerts — down, restart-loop, unhealthy, CPU, memory, and disk rules that fire through your email and webhook notification channels.
Backups — full coverage
A Docker app backs up like any other site (through restic), and a Docker app gets full coverage — all three places a containerized app keeps state ride the same backup:
- The compose directory (
/srv/docker/<app>) — the compose file plus any bind-mounted data directories under it. - A containerized database — if your app runs its own DB as a compose service (e.g. a
postgresormysqlcontainer), the backup dumps it from inside the container and the restore reloads it. - Named docker volumes — volumes declared in the compose file are captured into the backup and re-hydrated on restore, even though they live outside the app directory.
Declare your named volumes
Named volumes are covered when they're declared in the app's compose file, so SpipCP knows which ones belong to the app. The containerized DB's own credentials stay inside the container — the panel never has to hold them to dump or reload it.
Caveats
- Not a catalog service — docker is installed as part of the launch, not as a catalog service, so it doesn't appear on the instance's Services tab.
- One compose service in the starter; edit the compose file for more, but the served port and smoke check track the single published port.
- Instance-local — the container runs inside one instance; there's no orchestration across instances. Each app is its own site, managed fleet-wide by the management plane.
Environment editor
Edit a site's environment in a real .env code editor (line numbers, syntax highlighting) or a key/value table — comments are saved, and how the variables reach your app (wp-config, process env) depends on the site type.
Set up (guided journeys)
The Networking "Set up" surface turns each DNS posture into a resumable checklist whose progress is read from your live fleet — leave for your registrar, come back days later, and it shows exactly where you are.
