DOCS / network & radio

Your own relay and your own mirror

Two different roles, and confusing them is expensive.

what it does what the network knows about it
Relay accepts sealed packets and hands them to whoever comes for theirs an address and a key fingerprint
Mirror keeps a public space available while its owner is offline an ordinary reader-participant

Relays do not form a network among themselves. Clients form the network on top of relays. Relays don’t know about each other, forward nothing to each other and never synchronize. This is not an unfinished feature — it is the design: the less a relay can do, the less you need to know about it.


Relay

What it can and cannot do

A relay is poste restante. It sees encrypted packets and mailbox addresses that rotate every few hours. It is not a participant: it doesn’t read the contents of private spaces, doesn’t sign events, doesn’t decide who is whose friend, and keeps nothing beyond its term (48 hours by default, 7 days at most).

Which yields the main thing for whoever runs one: losing a relay does not lose the conversation. The durable truth lives with the participants; a relay is only a meeting place.

Set it up

Build for the server:

GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -trimpath -ldflags "-s -w" -o terminal-relay ./cmd/terminal-relay

Install the binary, create a service user and a unit:

useradd --system --no-create-home --shell /usr/sbin/nologin quietrelay
install -o root -g root -m 755 terminal-relay /opt/quiet-relay/terminal-relay
[Unit]
Description=Quiet Spaces relay
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=quietrelay
Group=quietrelay
ExecStart=/opt/quiet-relay/terminal-relay --listen :7411 --data /var/lib/quiet-relay
Restart=always
RestartSec=2
StateDirectory=quiet-relay
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/lib/quiet-relay
ProtectKernelTunables=true
ProtectControlGroups=true
RestrictAddressFamilies=AF_INET AF_INET6
MemoryMax=768M

[Install]
WantedBy=multi-user.target

--data is not a cache

The --data directory holds the relay’s permanent identity key. Its fingerprint (SPKI pin) is pinned by every client on first connection. Lose the directory and the relay changes identity — and every client will refuse to connect. That is intentional: a key change must be a refusal, not a silent “we connected to something else”.

Keep it in your backups. Permissions 600, owned by the service user.

The fingerprint

The relay prints it at startup:

identity SPKI pin: gk0X84yjjmahVYaUO7snq/a/BecbtX4deDFp7hGkC/c=

Verify it from another machine over the wire, not only from the log: the log says what the process believes, the handshake says what will actually be offered to a client.

terminal relay show-identity YOUR.ADDRESS:7411

After that the fingerprint is compared by eye exactly once. The client remembers it and, if the key ever changes, refuses with a clear message.

Limits

The defaults are guard rails against abuse, not a bandwidth promise: 64 items per mailbox, 1 MiB per item, TTL ≤ 7 days, 4096 connections. All adjustable by flags (--max-conns, --per-hint-mib, --total-gib, --collect-rate, --write-rate, --fetch-rate).

The default port is 7411/tcp — open it.


Mirror

Why

A public space lives on a relay in windows, refreshed by its owner’s heartbeat. When the owner stays offline longer than the window, the space stops existing for everyone who hasn’t read it before.

A mirror republishes the owner-signed envelope byte for byte and holds the media it references. It adds nothing to anyone’s rights: it has no space key, can change nothing, and touches nobody’s mailboxes. It adds availability — and only that.

Set it up

A mirror is an ordinary node with keys, so it needs a passphrase. Never pass it as a command-line argument: systemctl status prints a service’s command line to anyone, and so does /proc. Only via an EnvironmentFile readable by root alone.

install -m 600 /dev/null /etc/quiet-mirror.env
# one line inside: QP_PASSPHRASE=…
[Service]
User=quietrelay
Group=quietrelay
EnvironmentFile=/etc/quiet-mirror.env
ExecStart=/opt/quiet-relay/terminal-mirror node --data /var/lib/quiet-mirror --no-lan
Restart=always
StateDirectory=quiet-mirror
ReadWritePaths=/var/lib/quiet-mirror

Add a space:

terminal mirror add --link LINK --data /var/lib/quiet-mirror --passphrase --seed
terminal mirror list --data /var/lib/quiet-mirror --passphrase

Run these as the same user as the service. Running them as root re-creates the directory’s files owned by root, and the service stops starting with “permission denied”. If that happened: chown -R quietrelay:quietrelay /var/lib/quiet-mirror.

Without it, the mirror holds the bytes but doesn’t answer anyone’s requests. With it, it answers — thereby announcing that it has this file, i.e. that it reads this. For a public catalog you run yourself, that’s exactly what you want; for someone else’s space, it is a deliberate decision.

A catalog pulls in what it references

If the mirrored space is a catalog (a directory of cards), the mirror will pick up the spaces it lists too: open them, start mirroring them, and inherit seed. A catalog whose entries are unavailable is not a catalog being kept available.

Only spaces the node doesn’t already know are touched. mirror remove clears the flags but keeps the space, so what you removed by hand stays removed — the automation never re-evaluates what is already known.

By mirroring someone else’s catalog you agree to store and serve whatever its owner adds to it. That is a delegation of judgement, and it deserves to be made consciously.

How much disk

As much as the media of the mirrored spaces weighs, plus a little for events. A demo catalog of three spaces is about 100 MB. terminal mirror list reports fact, not intent: media 12/14 means “promised to hold fourteen, holding twelve”.


Worth knowing in advance

Every space has its own meeting place. A public space carries its relay address in a signed policy; the link carries the same. A reader comes exactly there, from whatever relay of their own. Your personal relay and a space’s relay are different things, and that is normal.

A space’s relay is fixed at birth. You can change your personal relay at any moment; the address of an already-created public space is a policy revision, not a setting.

Media does not sit on the relay as files. Events and manifests travel through the relay; bytes are fetched on demand from whoever holds them. That is exactly why a mirror makes sense: it is the one who holds them while the owner sleeps.

Silence is not a diagnosis. A correctly configured relay that nobody has visited looks exactly like a misconfigured one. Verify with the fingerprint and terminal relay show-identity, not with the absence of complaints.