Containers
A site can run your project instead of serving its files: a Node.js app and a MySQL database, declared in one small compose file, with Sitebin in front as the reverse proxy — the site's own address and your custom domains included.
How it works
- Put a
sitebin-container-compose.yamlin the site's root folder. - Upload your app into the folder a service mounts — each root folder of the site is a volume.
- Switch the site to Container on its edit page (or
PUT {"mode":"container"}).
From then on, every change to the compose file restarts the project — however it arrives: the edit page, the in-browser editor, a ZIP, WebDAV, FTP, the API or an agent through MCP.
The compose file
It looks like Docker Compose, cut down to what a site needs:
services:
app:
image: alpine-node-22
environment:
NODE_ENV: production
DB_HOST: db
DB_PORT: 3306
DB_USER: appuser
DB_PASSWORD: apppassword
DB_NAME: appdb
volumes:
- app:/usr/src/app # the site's root folder "app"
domains:
- "*:3000" # the site's own address -> port 3000
- "shop.example.com:3001" # a custom domain -> port 3001
egress: allowed # may reach the internet (default: denied)
depends_on: [db]
db:
image: mysql-8.4
environment:
MYSQL_ROOT_PASSWORD: rootpassword
MYSQL_DATABASE: appdb
MYSQL_USER: appuser
MYSQL_PASSWORD: apppassword
volumes:
- db:/var/lib/mysql
| Key | Meaning |
|---|---|
image | One of Sitebin's own images — never a registry reference:
alpine-node-22 (Node.js 22 on Alpine) or mysql-8.4 (MySQL 8.4 LTS).
Both are pinned to an exact, reviewed version. |
environment | A map or a KEY=value list, as in Compose.
There is no variable interpolation: $HOME stays the five characters $HOME. |
volumes | <folder>:<absolute path>, optionally :ro.
The folder is a root folder of the site — the same one the edit page, WebDAV and FTP show — and is created
if it does not exist yet. |
domains | "<host>:<port>", like a port mapping.
* is the site's own address (once per site); any other host is a
custom domain, claimed automatically and attached once its DNS proves it. |
egress | allowed or denied (the default): whether the
service may reach the internet. |
command, working_dir, depends_on | Optional.
depends_on orders the start; it does not wait for the other service to be ready, so connect with a retry. |
Any other key is an error that names it, shown on the edit page — so a
ports: copied from another project tells you it does
nothing instead of silently doing nothing.
Networking
- Services of one site share a private network and reach each other
by service name —
db:3306above. Sites never share a network. - Without
egress: alloweda service cannot reach the internet at all. - Sitebin reverse-proxies each
domainsentry to its port, with TLS, WebSockets and the site's view password, if it has one./_sitebin/*stays Sitebin's on every site address. - A site in Container mode is never served from its
files: its folders hold the database, and the compose file
holds passwords. A stopped project answers
503; a host no service is mapped to answers404.
The images
alpine-node-22 runs npm start
in the first mounted folder. If there is no node_modules
yet, it runs npm install first — which needs
egress: allowed; for an offline service, upload
node_modules with the app. With no package.json
it runs node index.js. Set command to run
anything else.
mysql-8.4 is the official image, tuned
to fit the container's memory. Mount a folder at
/var/lib/mysql to keep the data — without one, the data
lives in memory and is gone on the next restart.
Limits
- Containers: your plan caps the running services across all your sites — every service in every started project counts. A project that would go over is not started, and the edit page says by how much.
- Memory, CPU, processes: fixed per container by the instance (on the hosted service: 512 MB, half a CPU, 256 processes). You do not choose them.
- Storage: everything the containers write counts
against the site's storage. A project that grows past it is stopped —
never deleted; free some space and press Start. The
per-site file count does not apply in Container mode
(
node_modulesalone would break it). - Plan changes: when a plan ends or shrinks, projects over the new cap are stopped, newest first. Their files stay.
Running it
The edit page shows every service with its state, image, volumes and mappings — including the DNS record a custom domain still needs — plus Start, Stop, Restart and each service's recent log. The custom-domain editor is replaced by the mappings: the compose file is where domains are declared.
# switch a site to Container mode
curl -X PUT -H "X-Edit-Password: $PW" -H "Content-Type: application/json" \
-d '{"mode":"container"}' https://app.sitebin.io/api/sites/$EDIT_ID
# start / stop / restart (202; the site document comes back with container.status)
curl -X POST -H "X-Edit-Password: $PW" https://app.sitebin.io/api/sites/$EDIT_ID/containers/restart
# the last lines a service wrote
curl -H "X-Edit-Password: $PW" "https://app.sitebin.io/api/sites/$EDIT_ID/containers/app/logs?tail=200"
An account API token works in place of the edit password, as on every site endpoint. Switching back to Web server stops the project and serves the folders as files again.
Self-hosting
Container sites need the Enterprise edition in tiers mode,
SITEBIN_CONTAINERS=docker, the Docker Engine's socket
(Docker 26 or newer) and a max_containers value on the
tiers that may use them. The full list of settings is in
Configuration, and the security notes
in Operations & security.
services:
sitebin:
image: sitebin:latest-ee
group_add: ["988"] # the gid that owns /var/run/docker.sock on the host
volumes:
- sitebin-data:/data
- /var/run/docker.sock:/var/run/docker.sock
environment:
SITEBIN_ACCOUNT_MODE: tiers
SITEBIN_CONTAINERS: docker
SITEBIN_CONTAINERS_DOCKER_HOST=tcp://…).