# Containers, ports and volumes

What runs on a self-hosted server, which ports it opens, and where its data lives.

Every GoRunner container runs one image, `ghcr.io/ralve-org/gorunner-selfhost`, at the version in `GORUNNER_TAG`. `COMPOSE_PROFILES` in `.env` says which run on this server: the role, each built-in store, and `caddy`.

## Containers

| Container | What it does | Runs with |
| --- | --- | --- |
| `caddy` | Automatic HTTPS: ports `80` and `443` (and `443/udp`). Image `caddy:2.11-alpine`. | Automatic HTTPS |
| `api-gate` | Holds the app’s port, `3001`, open through every update. Published on `127.0.0.1`, or where `--app-port` says. | Role `all`, `api` |
| `api`, `api-twin` | Two copies of the dashboard, the API and the embed, behind the gate. 1 GB of memory each (`API_MEMORY_LIMIT`). | Role `all`, `api` |
| `worker` | Runs the workflows. `WORKER_REPLICAS` copies, 2 GB each (`WORKER_MEMORY_LIMIT`). | Role `all`, `worker` |
| `worker-next` | The new workers, only while an update rolls. | An update |
| `migrate` | Applies the migrations on each start and update, then stops. | Every role |
| `check` | The [preflight check](https://docs.gorunner.io/self-host/preflight-check), run by hand. | `docker compose run --rm check` |
| `postgres` | The built-in database, `postgres:15.6`, with `max_connections` 500 on a new install (200 on an older one, until `POSTGRES_MAX_CONNECTIONS` is raised). | A built-in database |
| `redis` | The built-in Redis, `redis:7-alpine`. | A built-in Redis |
| `seaweedfs`, `seaweedfs-s3` | The built-in file storage, `chrislusf/seaweedfs:4.33`, and a small relay in front of its S3 port, `8333`. | Built-in storage |

The release pins Redis, SeaweedFS and Caddy to the digest their tag named when it was tested. PostgreSQL keeps its exact version, so an update never restarts it.

Only `caddy` and `api-gate` publish ports on the server. With `METRICS_ENABLED`, each API and worker also answers on `9464` inside the Docker network (`9465` for `api-twin`).

## Volumes

- `gorunner_pgdata`: The built-in database.
- `gorunner_redisdata`: The built-in Redis.
- `gorunner_seaweeddata`: The built-in file storage.
- `gorunner_caddydata`, `gorunner_caddyconfig`: Caddy’s certificates and settings.

The prefix is the project, `gorunner` unless the setup was given `--project`. The install folder’s `certs/` is mounted read-only at `/certs` in every GoRunner container. [Back up and restore](https://docs.gorunner.io/self-host/backups) copies the volumes.

## On Kubernetes

- **Deployment `<release>-api`**: The app, 2 pods, behind the Service `<release>-api` on port 80 and your Ingress.
- **Deployment `<release>-worker`**: The workers, 1 pod by default.
- **The migrations Job**: Runs the check, then the migrations, once per install and upgrade. New pods wait for it.
- **The bundled stores**: PostgreSQL, Redis and SeaweedFS, one pod each, only when turned on. Evaluation only.
- **Secret, NetworkPolicy, PodDisruptionBudget**: The settings’ secrets, who may reach whom, and one app pod kept through drains.

Related: [How it fits together](https://docs.gorunner.io/self-host) · [Helm values](https://docs.gorunner.io/self-host/helm-values) · [Settings (.env)](https://docs.gorunner.io/self-host/settings) · [Remove GoRunner](https://docs.gorunner.io/self-host/uninstall)

Source: https://docs.gorunner.io/self-host/services
