# Several servers

Give the workflows more room: one server for the dashboard and the API, others for the workers.

One server is right for most installations. Every server runs the same image; `GORUNNER_ROLE` says what it does.

- `all`: Everything. The default.
- `api`: The dashboard and the API. People, webhooks and your proxy reach it. It runs no workflows.
- `worker`: The workers: workflows, schedules and recovery. Nobody reaches it from outside.

Every server shares [your own database, Redis and storage](https://docs.gorunner.io/self-host/own-stores) (storage may be none), the same `ENCRYPTION_KEY`, and the same version. On Kubernetes, raise `worker.replicas` instead.

## 1. Set up the main server

On the server people reach, run the setup with the role `api`. It asks the way in, mail and your stores, then prints the setup code and how to add workers.

Create the admin account as usual. See [First sign-in](https://docs.gorunner.io/self-host/first-sign-in).

```bash
./setup.sh --role api
```

## 2. Add a worker server

On each worker server, [download the bundle](https://docs.gorunner.io/self-host/install-docker#download-the-bundle) of the **same version**. Run the setup with the role `worker`, the address people open, and the main server’s key.

At “The value for --encryption-key (not shown):”, paste the value after `ENCRYPTION_KEY=` in the main server’s `.env`. Then give the same mail and stores.

You should see the check passes, the workers start, and the setup says GoRunner runs there as a worker for your address.

A worker given another key stops at the check, before anything starts.

```bash
./setup.sh --role worker --encryption-key - \
  --public-url https://automations.example.com
```

## 3. Run more workers on one server

Set `WORKER_REPLICAS` in that server’s `.env`, then apply it.

```bash
./deploy.sh "$(cat VERSION)"
```

## 4. Update in order

Update the `api` server first, then each worker server straight after, with the same version. The first server to start a version updates the database; the check then refuses a worker that is still behind.

```bash
# on the api server, then on each worker server
./deploy.sh v2026.10.30
```

## Database connections

Every process keeps a pool of connections, and together they must fit the database’s `max_connections`. The check counts the processes on the other servers and writes each server’s pool, `DB_MAX_CONNS`. If a later server doesn’t fit, raise the database’s limit or lower `DB_MAX_CONNS` where the check says.

**What if no worker runs?**

Nothing runs, and schedules wait. The check on an `api` server says so until a worker reports.

**Can a script answer the questions?**

Pipe the key on standard input and give everything else as flags: `printf '%s\n' "$KEY" |./setup.sh -y --role worker --encryption-key - …`, with the same mail and stores as the main server.

**Can several servers go back to an older version?**

Not below v2026.10.3: v2026.10.0 to v2026.10.2 knew one server only. The update refuses, and changes nothing. Once an installation has run v2026.10.58, not below v2026.10.57 either: nothing refuses that, and the way back is a backup.

## Related

- [Your own database, Redis and storage](https://docs.gorunner.io/self-host/own-stores): What each store must be · 10 min
- [Update](https://docs.gorunner.io/self-host/update): One command, no gap · 5 min
- [The Health page](https://docs.gorunner.io/self-host/health): Workers live and busy slots · 4 min

Source: https://docs.gorunner.io/self-host/several-servers
