Box services
A Slothbox environment template can declare services — databases, caches, and
other supporting containers that run alongside your projects on the box. Each
service is a Docker image. When a box is baked, Slothbox assembles the
template's services into a generated docker-compose.yml and brings them up with
docker compose, so a Postgres, a Redis, and your app all start together on the
same instance.
Services used to be installed from hand-written apt scripts. They are now
Docker images assembled into a per-box docker-compose.yml. The service
keys you pick (postgres, redis, and so on) are unchanged, but each one now
maps to an image and tag, and you can bring your own image or import an existing
compose file. Existing templates are rebaked onto the Docker model on their next
bake — there's nothing to migrate by hand. Language runtimes (Node, Python, and
so on) are not affected: they are still installed natively on the box, not run
as containers.
Where services are configured
Services belong to an environment template, which describes how a box is built. You add them in the web app's template builder ("Add service"), and the same shape is available over the API on the template body — see the API reference for the template schemas.
A service comes from one of two sources:
- A curated catalog image — a small, vetted set we maintain (see below).
- A custom image — any image from any registry, including private registries.
You can also import an existing docker-compose.yml as a starting point: the
web app reads your compose file and turns each service into a template service
you can then tweak. This is the quickest way to bring an existing local stack
onto a box — see importing a compose file for
exactly what carries over.
A template can declare up to 20 services, and each service up to 20 published ports and 20 volumes.
The curated catalog
The catalog is a maintained allowlist of common services, each pinned to an
official image. The full, live list is available from GET /catalog/services
(it populates the "Add service" picker), and currently covers:
| Service | Image | Tags | Default port |
|---|---|---|---|
| PostgreSQL | postgres | 16, 15 | 5432 |
| Redis | redis | 7 | 6379 |
| MySQL | mysql | 8 | 3306 |
| DynamoDB Local | amazon/dynamodb-local | 2.5 | 8000 |
Catalog services are trusted: each image is curated and vetted by Slothbox. They are pulled from their official upstream registry at bake time.
To add one, you pick the service and a tag. Catalog images are pinned to a digest when you save the template, so a template bakes the exact image it was built against (see pinning). Pinning is best-effort: in the rare case the registry can't be reached at save time, the image is left on its tag.
Networking and persistence
Catalog services are configured to behave well on a single-tenant box out of the box:
- Loopback only. Service ports are published on
127.0.0.1, never on a public interface — the database is reachable from your project on the box, but not from the internet. The defaults also mirror the old single-tenant auth setup (for example, Postgres usestrustauth on loopback), so connecting from the box just works. - Persistent by default. Stateful services keep their data in a named Docker
volume (
<service>-data), so it survives container restarts and the box being stopped and started. DynamoDB Local defaults to in-memory; to make it persist, set itscommandto-jar DynamoDBLocal.jar -sharedDb -dbPath /home/dynamodblocal/data— the path must be exactly/home/dynamodblocal/data, which is where its data volume is mounted.
Configuring a service
Every service — catalog or custom — accepts the same config block to tailor
how it runs:
| Field | What it does |
|---|---|
env | Non-secret environment variables, merged over the catalog defaults. |
command | Override the container's command (a string or array). |
ports | Ports to publish (on loopback). Replaces the default port list. |
volumes | Extra mounts: a named volume (cache:/data) or a bind mount (/host:/path). |
resources | Optional cpus and mem_limit caps for the container. |
Because ports replaces the defaults rather than adding to them, include the
default port explicitly if you still want it — for Postgres,
"ports": [5432, 5433] publishes both, while "ports": [5433] would drop 5432.
Service env values are literals, written into the box's service
configuration as-is — there is no secret injection for service environment
variables yet, so keep passwords and API tokens out of service env. For your
application code, use project-level environment variables and
secrets, which do support referencing your organization's secrets
by name.
On box launch, services are brought up before your projects' setup runs, so setup scripts can reach a database or cache straight away. There is no health-gated ordering beyond that: a service may still be finishing its own internal startup when setup begins, so a script that needs it ready should retry its first connection.
Importing a compose file
The compose importer turns each service in a docker-compose.yml into a
template service. It keeps the fields that map onto the template model and
warns about anything it drops, so review the import before saving:
| Compose input | What the importer does |
|---|---|
image | Kept. A missing tag defaults to latest. |
container_name | Kept. |
ports | Kept (published on loopback). |
environment | Kept, as literal values. |
volumes — named, short syntax (data:/var/lib/x) | Kept. |
command | Kept (string or array). |
build: | Service skipped — only prebuilt images can be imported. |
depends_on | Dropped, with a warning. |
Bind mounts (./local:/path) | Dropped, with a warning. |
Long-syntax volumes entries | Dropped, with a warning. |
| YAML anchors and aliases | Dropped, with a warning. |
Block-scalar command values | Dropped, with a warning. |
Environment interpolation (${VAR}) | Dropped, with a warning. |
Top-level networks, volumes, secrets, configs | Dropped, with a warning. |
Every imported service becomes an
unverified custom image — even
a stock postgres:16 imported this way is treated as a custom image rather
than being mapped back to the curated catalog entry.
On the box
A few useful facts when you're troubleshooting a service on a running box:
- The generated compose file is at
/etc/slothbox/docker-compose.yml, and each service's environment file is at/etc/slothbox/services/<name>.env. - The usual compose commands work against it:
docker compose -f /etc/slothbox/docker-compose.yml psanddocker compose -f /etc/slothbox/docker-compose.yml logs <service>. - Container logs use the
json-filedriver and rotate at 10 MB across 3 files per container, so they won't fill the disk. - Container health is reported on the box's health heartbeat, so you can see a failing service from the box page without SSHing in.
Next steps
- Custom images — bring your own image from any registry, and how image pinning works.
- Private registries — pull private images with org-level registry credentials (Docker Hub, GHCR, or ECR).