SpipCP
Sites

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:

  1. 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).
  2. Write the per-app compose — a docker-compose.yml plus a starter webroot under the app's own directory /srv/docker/<app> (where <app> is the site's slug). Never a shared directory.
  3. Bring the stack up — run docker compose up -d under 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.
  4. Wait and smoke-test — poll the published port until it answers, then check it. A failed check leaves the site failed with 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.

The Compose tab on a Docker site
📷A Docker site → Compose: the raw docker-compose.yml is canonical; the Ports view flips on top, and Save → Apply stages then relaunches the app.img/docker-compose-tab.avif
A Docker site → Compose: the raw docker-compose.yml is canonical; the Ports view flips on top, and Save → Apply stages then relaunches the app.

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-gateway lets the container reach the database on the instance host.
  • The credentials are passed into the container as DB_HOST (defaults to host.docker.internal), DB_NAME, DB_USER, and DB_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 postgres or mysql container), 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.

On this page