Skip to content

Self-hosting with Compose

The repository ships deploy/compose/compose.yaml: Postgres 17, NATS JetStream, RustFS (an S3-compatible object store), Valkey and, with --profile app, the Slipway server (all mode) and one docker-executor runner.

Terminal window
git clone https://github.com/slipway-systems/slipway && cd slipway
podman compose -f deploy/compose/compose.yaml --profile app up -d --build

For the five-minute path see the quickstart. This page covers what to change before it holds real data.

The shipped file contains development-only credentials and a development master key. Provide your own through an environment file:

Terminal window
# .env (keep out of version control; mode 600)
SLIPWAY_BASE_URL=https://slipway.example.com
SLIPWAY_SESSION_SECRET=$(openssl rand -hex 32)
SLIPWAY_MASTER_KEY=$(openssl rand -hex 16) # exactly 32 bytes; see Backups

Also change the Postgres and RustFS passwords in the file and set SLIPWAY_VALKEY_PASSWORD (the compose Valkey requires a password; the default is slipway and the server’s SLIPWAY_CACHE_URL follows it), and do not publish 5432, 4222, 9000, 9001 or 6379 outside the host: remove those ports: entries or bind them to 127.0.0.1.

Run a reverse proxy (Caddy, Traefik, nginx) terminating TLS and forwarding to slipway:8080. Slipway streams logs over long-lived HTTP/2 or HTTP/1.1 responses, so disable response buffering and use long timeouts. Runners connect over a WebSocket at /api/v1/runner/connect; Caddy and Traefik pass upgrades by default, nginx needs the usual Upgrade/Connection headers on that location.

slipway.example.com {
reverse_proxy slipway:8080 {
flush_interval -1
transport http { read_timeout 1h }
}
}

Set SLIPWAY_BASE_URL to that public URL. It is used for OIDC redirects, webhook URLs and the job-token issuer.

For anything business-critical, replace the bundled Postgres, RustFS and Valkey with managed services and point Slipway at them (see Configuration). Keep NATS with a persistent volume.

The bundled runner uses the host’s Docker or Podman socket, which gives jobs control of the host. For real workloads run runners on separate machines, or use the Kubernetes executor. See Runner security. Create a pool and give the runner its token:

Terminal window
export SLIPWAY_RUNNER_TOKEN=<token>
podman compose -f deploy/compose/compose.yaml --profile app up -d runner
Terminal window
podman compose -f deploy/compose/compose.yaml --profile app ps
podman compose -f deploy/compose/compose.yaml logs -f slipway
curl -fsS https://slipway.example.com/readyz

Update by pulling or rebuilding the image and recreating the service. Migrations run when the server starts. See Upgrades and take a backup first.

Volume Contents Back up
pgdata Postgres data Yes: use pg_dump or physical backups
natsdata JetStream state Optional: queues and events (see Backups)
miniodata Logs, artifacts, caches Yes, if you need artifact history
runner-work Job workspaces No

One host is one failure domain. For high availability use the Helm chart on Kubernetes.