# Teams and self-hosted relay

Share one Mac's devices with teammates on other networks through a relay your team runs itself, with Docker Compose or systemd on one Linux server.

Silan Macs that are not on one network meet at a relay. The relay routes only sealed packets it cannot open, and only between Macs whose people share a team. **Each team runs its own relay.** Silan has no default team server: a new Mac has none until you type your team's address or open an invite link.

Silan's own relay is private. It serves the people already on it and the people they invite, and it tells everyone else to set up their team's own server. This page is how.

## What a team can do

- Hold devices for the team from one Mac. The Mac keeps sharing after you quit Silan, and can stay awake while devices are shared.
- A teammate books a shared device from their own Mac, sees its picture live and uses it by hand or with their agent.
- Risky steps on a shared device ask the device's owner first.
- A waiting line when a device is busy, and take-back by the owner.

## What you need

- A Linux server. Two vCPUs and 4 GB are enough for a few thousand Macs.
- A DNS name for the relay, for example `relay.example.com`, with an A (and AAAA) record to the server.
- Ports 80 and 443 (TCP) and 443 (UDP) open to the internet.
- A sign-in. The relay signs people in through your company's OpenID Connect provider (Microsoft Entra ID, Google Workspace, Okta, Keycloak and others), or through WorkOS.
- The relay image `silan-relay:<version>` from Silan, or built from the repository with `docker build -f relay/Dockerfile -t silan-relay:latest .`.

The relay runs on Linux today; it is the one part of Silan that does.

## Way 1: Docker Compose and Caddy

The kit is the `relay/deploy/self-host/` folder: `compose.yaml` (the relay and Caddy for TLS), `compose.backup.yaml` (backups to an S3-compatible store), `Caddyfile`, `relay.env.example` and `env.example`.

### 1. Register the relay at your sign-in

Make a new OpenID Connect client (web application, confidential, with a client secret) at your identity provider:

- Redirect URI: `https://relay.example.com/signin/callback`.
- Grant: authorization code. Scopes: `openid email profile offline_access`.
- The ID token or user info must carry `email` and `email_verified: true`. The relay lets in only verified emails. Microsoft Entra ID sends no `email_verified` claim: there, set `SILAN_RELAY_OIDC_TRUST_EMAIL=yes`.
- Note the issuer URL, the client id and the client secret.

### 2. Set it up on the server

```sh
cp env.example .env              # set SILAN_RELAY_DOMAIN and SILAN_RELAY_IMAGE
cp relay.env.example relay.env   # set the lines marked CHANGE
mkdir -p secrets
head -c 32 /dev/urandom | base64 > secrets/seal_key
printf '%s\n' 'THE CLIENT SECRET' > secrets/oidc_client_secret
sudo chown 10001:10001 secrets/*  # the relay runs as uid 10001 in its container
sudo chmod 600 secrets/*
docker compose config --quiet    # checks the files
docker compose up -d
```

`secrets/seal_key` seals the sign-in tokens the relay keeps. Keep a copy in your password manager: a restored database needs the same key, or everyone must sign in again.

### 3. Check it

```sh
docker compose ps                         # relay: healthy
docker compose logs relay | grep "Relay hub listening"
curl https://relay.example.com/health     # {"macs":0,"videoMacs":0,"dataVersion":...,"signIn":"oidc"}
```

### Backups and upgrades

The relay keeps everything in one SQLite file. With `LITESTREAM_REPLICA_URL` set in `relay.env` and the store's key in `secrets/`, `docker compose -f compose.yaml -f compose.backup.yaml up -d` copies each change to your S3-compatible bucket. A new server with the same seal key and backup settings restores the newest copy before the relay starts.

To upgrade, set the new image in `.env`, then `docker compose pull` and `docker compose up -d`. Macs lose the link for a few seconds and connect again.

## Way 2: systemd on a plain Linux server

The kit is the `relay/deploy/server/` folder: `install.sh`, `silan-relay.service`, `relay.conf.example`, `litestream.yml` and a `Caddyfile`. No Docker on the server; the two programs (`silan-relay-hub` and `litestream`) are copied out of the image on a computer that has Docker.

1. Rent an Ubuntu 24.04 server, open TCP 22, 80, 443 and UDP 443, point DNS at it, and make a private bucket for backups.
2. Build the image and copy the two programs into `relay/deploy/server/`, then copy the whole `relay/deploy` folder to the server.
3. Install Caddy from its own package source. Then `./install.sh --domain relay.example.com --dry-run`, and the same without `--dry-run`. It makes the user, folders, service and seal key, and never overwrites a secret or a settings file. Run it again for each upgrade.
4. Put the secrets in `/etc/silan-relay/secrets/` (root only, mode 600): the seal key, your sign-in's credentials, the backup store's key. Set the bucket in `litestream.yml` and `public_url` in `relay.conf`.
5. `systemctl start silan-relay`, then `curl https://relay.example.com/health`.

The hub runs as Litestream's child, so the restore finishes before the hub opens the database, and the relay never runs without backups.

## Who may make an account

The server kit's `relay.conf.example` sets `sign_ups = private`. A person may make an account only when they already have one, their email is in `allowed_emails` or `allowed_emails_file`, or a team on the relay invited them. Everyone else sees "This Silan server is private. Set up your team's own server." Accounts and Macs already linked keep working.

To let one more person in, add their email to the allowed-emails file, one per line. No restart: the hub reads the file at each new sign-in. With `sign_ups = open`, anyone your sign-in lets in makes an account.

The Docker kit's `relay.env` defaults to open sign-ups behind your company sign-in. Set `SILAN_RELAY_SIGN_UPS=private` and `SILAN_RELAY_ALLOWED_EMAILS=...` to close it.

## Point each Mac at your relay

On each Mac, **Settings › Account & Team**. Under **No team server yet**, type the address (`relay.example.com`) and press **Use this server**. Silan checks that it answers as a Silan relay, keeps it, and turns on **Sign in**. Your sign-in's page opens in the browser.

An invite link fills the server in by itself. In setup, the team ways ask for the server at **Sign in**.

## Teams and invites

Teams live on the relay. With company sign-in the relay sends no invite emails: send the invite link the relay makes, or let the person sign in with the email the invite names, and they join at once.

## Logs and privacy

With `log_detail = counters` (the default in the kits) the relay's log lines hold only words and numbers: no ids, names, emails or addresses. Caddy's request log has no query strings, headers or addresses. The relay stores no app ids, buttons, fields, phone names or Wi-Fi addresses; the Mac names are the only names in its database.

## A test on one Mac

`compose.dex-test.yaml` runs Dex as a stand-in company sign-in with two made-up people and the relay on `http://127.0.0.1:47990`, for a test only. The steps are at the top of the file.