Add a Server (Relay)¶
What this is: bringing a new relay onto the network. A "server" here is the box in the middle that passes everyone's messages around, stores chat and drawings, and covers a patch of ground. When you'd do it: standing up a new site, adding capacity, or covering a new area. How long it takes: an afternoon for the box itself; the part you do on the Directory is a couple of minutes.
This one is different from the rest of this guide. It isn't a single web form. Two people are involved:
- a deployment engineer (your IT/cloud person) who stands the box up, and
- an Admin who authorises the new server from the Directory.
If you're the operator and not the engineer, your job is mostly Step 3 — the rest is here so you understand what your engineer is doing and why.
Who can do this: an Admin authorises the server (only an Admin can register a new one). Standing up the box needs a deployment engineer with access to your cloud project (or the Linux host). You need both.
The shape of it¶
flowchart LR
A["Engineer stands<br/>up the box"] --> B["Admin registers it<br/>in the Directory<br/>(address, role,<br/>coverage area)"]
B --> C["Directory issues a<br/>ServerToken"]
C --> D["Token goes on<br/>the box; server boots"]
D --> E["Server joins &<br/>relays its area"]
The box can't do anything until it has a ServerToken — a signed permit from the Directory that says who it is, the highest classification it may carry, and which area it covers. The engineer builds the box; the Admin issues the token; the token goes on the box; the server comes to life.
Before you start¶
- An Admin login to the Directory.
- A deployment engineer with access to the cloud project (or a Linux host) for the box.
- Decide four things up front (see Step 2 below): the server's address (hostname), its coverage area, its classification ceiling, and its token validity period. All four are fields on the Create Device form.
Step 1 — Stand up the box¶
The server is one program. There are three ways to run it; pick one. For real deployments, use the cloud path — it's the supported, repeatable one.
Option A — Cloud (recommended)¶
Production servers are a single container on a Google Cloud VM, provisioned with
Terraform/OpenTofu. This lives in the infrastructure repo — your engineer copies the
terraform/environments/server-demo/ stack to a new environment and applies it:
That creates the VM, a static IP, and the empty secret slots the server reads on boot
(its TLS cert, its identity token, and its ServerToken). The infrastructure repo
README has the full walkthrough — follow it, don't improvise.
Option B — Docker¶
docker build -t server:latest .
docker run -d --name server \
-e WAYPOINT_LISTEN="tls/0.0.0.0:7447" \
-e WAYPOINT_DIRECTORY_URL="https://<your-directory-host>" \
-e WAYPOINT_TLS_CERT_PATH="/etc/waypoint/certs/server.crt" \
-e WAYPOINT_TLS_KEY_PATH="/etc/waypoint/certs/server.key" \
-e WAYPOINT_TLS_CA_PATH="/etc/waypoint/certs/node-ca.crt" \
-e WAYPOINT_SERVICE_IDENTITY_TOKEN_PATH="/etc/waypoint/service-identity.token" \
-e WAYPOINT_SERVER_TOKEN_PATH="/etc/waypoint/server.token" \
-v waypoint-data:/var/lib/waypoint \
-v $(pwd)/pki:/etc/waypoint/certs:ro \
-p 7447:7447 -p 9090:9090 \
server:latest
Full reference: DOCKER.md in the server repo.
Option C — Native Linux binary¶
A minimal /etc/waypoint/config.toml sets the listen locator, the TLS cert/key paths, the
data directory, the Directory URL, and the two token paths. The server repo README has a
ready-to-edit example.
What every box needs (all three options)¶
| Thing | Where it goes | What it's for |
|---|---|---|
| TLS cert + key + peer CA | /etc/waypoint/certs/ |
how clients and peer servers trust this box |
| Service identity token | /etc/waypoint/service-identity.token |
the server's own login to the Directory |
| ServerToken | /etc/waypoint/server.token |
the permit with its classification ceiling + coverage area (Step 2/3) |
| Data directory | /var/lib/waypoint |
stored chat/drawings — must be on an encrypted (LUKS/SED) disk |
| Listen port | 7447 (and health on 9090) |
where clients connect |
Security note: the data directory holds message content and must sit on an encrypted volume. Don't skip this — see the deployment guide in the
serverrepo.
Step 2 — Decide what to register¶
When the Admin registers the server, the Directory mints its ServerToken from these details. You enter all of them on the form — agree them with your engineer first:
| Setting | Plain meaning | Example |
|---|---|---|
| Server Address | the hostname (or IP) clients reach it on; this is the form's Server Address field | relay-north.example.mil |
| Coverage area | the geographic cells it serves (see How geofencing works below) | gcpuv, gcpuy, gcpvh |
| Classification ceiling | the highest classification this relay may carry; traffic above it is dropped at the gate | Secret |
| Token validity (days) | how long the ServerToken stays valid before you reissue | 30 |
A note on each of the two you might not expect:
- Classification ceiling: pick it from the form's Classification dropdown (Unclassified → Top Secret). This sets the server's ceiling directly — there is no separate enrolment API. The level is stored on the device, so Reissue Credentials keeps it (and you can change it later by editing the device). A server left at Unclassified caps all its traffic to Unclassified, so choose deliberately for a classified network.
- Token validity (days): the form's ServerToken validity field, 1–365 days (defaults to 30). The value is stored on the device, so reissuing reuses it. Renew by reissuing the token (Step 3) before it expires.
(Your engineer may also supply the box's IP addresses so they can be baked into the certificate — they'll know if that's needed.)
Step 3 — Register it (Admin) and put the token on the box¶
Registering a server is the same admin flow as creating a device — a server is just a device with a service role. There is no separate "servers" page; the Admin creates it under Devices, and because it has a server/gateway platform and an address, the Directory mints its ServerToken automatically alongside the device's identity. (See Onboard a device for the full screen-by-screen walkthrough of this form.)
- An Admin creates the server in the Directory. In the top menu, click Devices, then Create Device, and fill in the details from Step 2:
- Callsign — a name for the box (e.g. RELAY-NORTH).
- Server Address — the box's DNS hostname or IP (e.g.
relay-north.example.mil). This field is required to mint a ServerToken — leave it blank and you only get an identity token, no ServerToken. - Platform Type — pick server (or gateway for an interop bridge). Only these two platform types receive a Directory-signed identity and a ServerToken; the others (drone/sensor/feed) onboard with a one-time registration token instead.
- Role — set to Server (or Gateway).
- Coverage Area — click the cells this relay serves on the map, or type geohash-5 cells. At least one cell is required.
- Classification — the relay's classification ceiling (Unclassified → Top Secret). Traffic above this level is dropped at the gate, so set it to the highest level this relay must carry. Required.
- ServerToken validity (days) — how long the token stays valid before reissue (1–365, default 30).
Click Create Device. The Directory signs the ServerToken from the address, role, coverage cells, classification ceiling, and validity you entered.
-
Save the credentials — they're shown once. The next page (Device Created) shows three secrets: the Signing Key, the Identity Token, and the Server Token. Click Download Bundle (.tar.gz) to grab all three at once (it also includes a
README.txtwith the deploy paths), or download each.binindividually. The signing key cannot be recovered — if you navigate away without saving it, you must Reissue Credentials from the device's page, which mints a fresh keypair. -
The engineer places the token on the box. From the bundle, the three files map to:
signing.key→/etc/waypoint/signing.key(the box's Ed25519 private key)service-identity.token→/etc/waypoint/service-identity.token(its own login to the Directory)server.token→/etc/waypoint/server.token(the ServerToken permit)
On the cloud path these are uploaded into the server's secret slots instead — the VM fetches them on boot.
- Restart the server so it picks up the token. On the cloud path that's a VM reset; on Docker/Linux, restart the container/process.
To rotate later (token expiring, or coverage area changing), open the server's device page and click Reissue Credentials to mint a fresh keypair + tokens, then replace the files on the box and restart. Reissuing keeps the device's stored classification ceiling and validity — to change either, edit the device (which updates the stored values) and then reissue. (Note: reissuing always generates a new signing key — the old one is invalidated, so you must redeploy all three files together.)
How geofencing works¶
Bedrock is split into cells. Every position, heartbeat, and drawing is tagged with the
cell it happened in, and message routing is cell-first — the cell is the first thing in
the address (waypoint/<cell>/...). See the wire protocol.
A cell is a 5-character geohash — a standard way of chopping the world into a grid.
Five characters is roughly a 5 km × 5 km box. Nearby places share a prefix, so cells in
the same region look similar (e.g. gcpuv, gcpuy).
A server's coverage area is the list of cells in its ServerToken. The server only relays and stores traffic for those cells — that's the geofence. So:
- To cover a wider area, list more cells.
- A unit moving into a new patch only appears on a server that covers that patch's cell.
- Two servers covering neighbouring areas hand off cleanly because each owns its own cells.
Picking cells: take the area you need to cover, find the geohash-5 cells that overlap it (any geohash tool will show the grid), and list them as the coverage area in Step 2. If in doubt, start with the cells around your operating area and add neighbours later by reissuing the token.
How to know it worked¶
- The box's health check answers on port
9090. - Clients in the covered area can connect and see each other.
- Position/drawing traffic for the covered cells flows through the new server.
If something goes wrong¶
- The server starts but rejects traffic, or won't carry some messages. Usually the ServerToken is missing or expired — reissue it from the device page and restart. If the cause is classification (traffic above the server's ceiling is being dropped), the relay's Classification is set too low: edit the device, raise the Classification to the level it must carry, then Reissue Credentials and redeploy.
- Clients in an area don't show up. That area's cell probably isn't in the coverage list. Add it, reissue the token, restart.
- It won't start at all. Check the TLS certificates and the data-directory mount first
— those are the common culprits. The
serverrepo's deploy guide has the checks. - Registering a server is one-way — there's no "unregister". To retire one, stop the box and (if needed) revoke its identity.
See also¶
- Operator training index
- Set up the certificate chain (PKI) — where the box's TLS certificates come from.
- The
infrastructurerepo — the full cloud provisioning walkthrough. - The
serverrepo —DOCKER.mdandDEPLOY.mdfor box-level detail. - Wire protocol — the cell-first namespace.
- Glossary: ServerToken & coverage cells.
Verified against directory PRs #63 (merged) + #64 + #65 on 2026-06-07 — registration is the device-creation flow: a server/gateway-platform device with a hostname gets a ServerToken minted in app/domains/admin/devices/devices_service.ts (routes through ServerTokenService.issue(), which also records the server_registrations row clients read at login) and rendered for download in resources/views/domains/admin/devices/device_credentials.edge (Signing Key / Identity Token / Server Token cards + bundle). The Create Device form (resources/views/domains/admin/devices/create_device.edge, createDeviceValidator) now has a Classification dropdown (required, all platforms; SERVER_CLASSIFICATION_OPTIONS slug → level) and a ServerToken validity field (ttl_days, 1–365, required for server/gateway); both are persisted on the devices row (classification_level, server_token_ttl_days) so Reissue Credentials reuses them. Box setup cross-checked against the server repo (README.md, DOCKER.md) and the infrastructure repo (terraform/environments/server-demo/, scripts/upload-server-token.sh).