Skip to content
SilanDocs
Main site

Safety and teams

Teams and self-hosted relay

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.

  • 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.
  • 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.

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.

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.
Terminal window
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.

Terminal window
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"}

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.

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.

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.

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 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.

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.

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.