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.

Containers are an Enterprise feature, and on the hosted service a paid-plan feature: Pro runs up to 3 containers and Studio up to 20, counted across all of your sites. See Pricing.

How it works

  1. Put a sitebin-container-compose.yaml in the site's root folder.
  2. Upload your app into the folder a service mounts — each root folder of the site is a volume.
  3. 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"
    http: [3000, 3001]            # the ports it speaks HTTP on; each gets an address
    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
KeyMeaning
imageOne 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.
environmentA 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.
httpThe ports the service speaks HTTP on — one, or a list of up to 10. Each one gets an address of its own (see Addresses); which domain serves which port is set on the site, never in this file. A service without http has no address.
egressallowed or denied (the default): whether the service may reach the internet.
command, working_dir, depends_onOptional. 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. The key is http, not Compose's expose: in Docker that means internal only, and files from elsewhere often carry it on their database.

Addresses

Every HTTP port gets a generated address. The first port in the file gets the site's own address, <id>.sitebin.app; every further port an address of its own with a random name, as hard to guess as the site's — so an admin port is not found by reading the app's address. A port keeps its address as long as the file lists it, and a renamed service keeps the site's own address.

Custom domains are added on the edit page, through the API or by an agent over MCP, exactly as for any other site — the same DNS proof, the same certificates — and each one serves a port: the one you pick, by default the port of the site's own address. Every address can serve, redirect to another of the site's domains with the status code you choose, or — a generated address, once a domain serves the same port — be switched off, as described in Redirects and the generated address. A redirect is answered before the view password is asked for, so a visitor of example.com unlocks only www.example.com.

None of this is in the compose file, so changing an address never restarts the app. A port that leaves the file takes its generated address with it; a domain pointed at it stays attached and answers 404 until you point it at another port — Sitebin never moves a domain to another service on its own.

Networking

  • Services of one site share a private network and reach each other by service name — db:3306 above. Sites never share a network.
  • Without egress: allowed a service cannot reach the internet at all.
  • Sitebin reverse-proxies each address to the port it serves, 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; an address serving no port the file declares answers 404.

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 Docker Official Image mysql, 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: set per container by the instance's operator (on the hosted service, by default: 512 MB, half a CPU, 256 processes). You do not choose them yourself; the operator can change them for one container or for all, and a running container takes the new values without being restarted.
  • 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_modules alone 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 HTTP ports with their addresses, what it uses right now, plus Start, Stop, Restart and each service's recent log. Below it, the custom-domain card lists every generated address and every domain with what it does — the DNS record a domain still needs and Check now included.

Usage, refreshed every 10 seconds: each running service's memory, CPU and processes against its limits, and its public traffic in and out per second — your visitors' requests and its own connections to the internet, not what your services exchange with each other. When several services of a project serve HTTP, the visitors' traffic is shown once for the project.

# 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"

# what each running service uses; in_bps / out_bps are BYTES per second,
# null until the second measurement
curl -H "X-Edit-Password: $PW" https://app.sitebin.io/api/sites/$EDIT_ID/containers/stats

# a domain for the second port, and pointing it at another port later
curl -X POST -H "X-Edit-Password: $PW" -H "Content-Type: application/json" \
     -d '{"domain":"api.client.com","target":"app:3001"}' https://app.sitebin.io/api/sites/$EDIT_ID/domains
curl -X PUT -H "X-Edit-Password: $PW" -H "Content-Type: application/json" \
     -d '{"endpoint":"app:3000"}' https://app.sitebin.io/api/sites/$EDIT_ID/domains/api.client.com/target

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
The Docker socket is root on the host. Run container sites on a server dedicated to Sitebin, and prefer a socket proxy (SITEBIN_CONTAINERS_DOCKER_HOST=tcp://…).