Talx's federation layer turns every independently-hosted server into a node in a cryptographically trusted global network. Servers gossip a shared directory, deliver cross-instance DMs via signed HTTP push, and elect a new master automatically if the current one goes offline, all without any central coordinator.
Each Talx binary is a fully self-contained node. One operator's deployment hosts the CA and directory bootstrap node on reserved subdomains. Every other instance auto-enrolls and joins the gossip ring.
The network root of trust. Issues 26-year Ed25519 leaf certificates to enrolling instances. Runs in the same Go binary, activated by PALACE_CA_ENABLED=1. Enrollment works over plain HTTP (trust is signature-based, not TLS-based).
Bootstrap gossip seed and space aggregator. Enrolled instances announce here; the directory fans out to all peers. Powers the "Network" tab in the Connect dialog so every client sees all spaces across all servers.
Every instance exposes /api/v1/federation/inbox. Activities (DMs, friend requests, presence, directory updates) arrive here as signed JSON payloads. The inbox validates the sender's cert chain before dispatching.
A background goroutine drains federation_outbox with exponential backoff. Delivery is fire-and-forget with retry; after 10 failed attempts the row is marked terminal so it never re-queues.
Watches master heartbeats. If the master is silent for 24 hours, triggers a weighted score election. The winner promotes itself, broadcasts the new CA/directory URLs, and all peers update their config at runtime.
Real-time network operations dashboard at /admin/noc. Shows per-peer health, trust state, space counts, reliability graphs, and lets admins revoke or restore trust for any peer.
Trust in Talx is signature-based, not TLS-based. Every server-to-server call is signed with the sender's Ed25519 instance key and verified against a certificate that chains to the CA root. This means federation works equally well over plain HTTP (port 80) before TLS is configured.
| Component | Key Type | Validity | Storage | Notes |
|---|---|---|---|---|
| CA root keypair | Ed25519 | 26 years | psdata/federation/ca/ | Self-signed; baked into binary as default trust anchor. Operator can add extra anchors via PALACE_TRUST_ANCHORS. |
| Instance keypair | Ed25519 | Permanent | psdata/federation/instance.key | Generated once on first boot. Signs all outbound S2S requests. |
| Instance leaf cert | Ed25519 | 26 years | psdata/federation/instance.crt | Issued by CA at enrollment. Auto-renewed 90 days before expiry. Binds domain → pubkey. |
| Peer cert cache | Ed25519 | Per-peer | federation_peers table | Cached after first verified contact. Re-verified on every inbound message. |
New instances join via auto-enrollment (one HTTP call) or peer-vouching (a DM to certificates@talx.fyi). Both paths end in the same signed certificate.
On first boot with PALACE_FEDERATION_ENABLED=1, the server generates a persistent Ed25519 instance keypair under psdata/federation/instance.key. This never changes.
Sends a signed Certificate Signing Request to https://ca.talx.fyi/federation/enroll. The CSR includes the instance domain and public key, signed as proof-of-possession. Falls back to http:// if HTTPS fails.
CA verifies proof-of-possession, issues a 26-year leaf certificate chaining to the CA root, and returns it. The instance persists it as instance.crt.
Signed announce to https://peer.talx.fyi/federation/directory/announce. Directory verifies the cert chain, upserts the peer into federation_peers, and returns a seed peer set for gossip bootstrap.
A new instance operator sends a DM to certificates@talx.fyi, a reserved bot account (similar to the loopback bot). The DM body contains the CSR payload.
The existing trusted peer (talx.fyi) forwards the CSR with its own signed vouch to ca.talx.fyi/federation/vouch. The CA verifies the voucher is itself a trusted peer before signing.
CA issues the same 26-year leaf cert as Path A. The vouching peer receives it and forwards via DM reply to the new instance operator.
On join (and on cert renewal/failure), the certificates@ bot DMs every server admin: the union of ListInstanceHosts() and PALACE_ADMIN_USERNAME entries, deduped.
Each enrolled instance runs a background gossip loop. It pulls
/.well-known/talx-federation and
/api/v1/federation/directory from the bootstrap node
and from every known trusted peer. New peers discovered transitively are added
and their spaces merged into federation_directory.
The aggregated directory is exposed as /serverlist/network.json
and rendered in the Connect dialog's Network tab.
| Table | Purpose |
|---|---|
| federation_peers | Known instances: domain, pubkey, cert, trust state, last_seen, first_seen, software_version |
| federation_directory | Cached remote spaces: peer_domain, tenant_id, display_name, sysop, users, rooms, url, updated_at |
| federation_remote_accounts | Resolved user@domain handles, cached with 1h staleness window |
| federation_outbox | Queued signed S2S deliveries with retry state and exponential backoff |
Accounts are globally addressable as user@instance-domain. Cross-instance DMs travel as signed JSON activities via HTTP push, using a shadow-user pattern so the entire local DM pipeline works unchanged.
Remote senders are provisioned as local users rows with a user@domain username. This means friendships, DM threads, mailbox UI, and even user: bans all work unchanged, with no special-casing in the local stack.
Before sending, the outbox resolves user@domain via GET /.well-known/talx-federation/resolve?acct=user@domain on the remote server. Results are cached in federation_remote_accounts with a 1-hour staleness window.
The inbox validates that activity.From's domain matches the HTTP-signature-verified sender domain. A trusted peer cannot send activities claiming to originate from a third instance.
Inbox handles: dm.message, friend.request, presence, directory.update. Unknown types are acknowledged and silently ignored so new activity types from newer peers never break older ones.
If the master node is silent for 24 hours, every peer independently computes a weighted score for all known peers. The highest scorer promotes itself, broadcasts the election result, and peers verify the claim by recalculating independently before accepting.
Master broadcasts heartbeat every 30s. All peers record receipt with timestamp.
Missing heartbeat for 2 min = blip. Missing for 24 hours = election triggered.
Each peer computes weighted scores for all known peers independently using the formula below.
Highest scorer announces itself as new master, broadcasts new CA/directory URLs.
All peers recalculate the winner's score independently. Only if valid does the network update CA/directory URLs at runtime.
Each peer independently monitors every other peer's heartbeat. Downtime events are aggregated into daily summaries, and multi-peer consensus is required before a blip is accepted, preventing a single noisy peer from tanking another's reliability score.
Raw heartbeat gaps → federation_peer_uptime_events → daily aggregator → federation_peer_downtime_summary → reliability calculator → federation_peer_reliability_score (360-day rolling window, pruned daily)
Downtime summaries are gossiped between peers. A blip is only counted if multiple peers independently agree on the downtime window. Single-observer events are discarded. The detection_count field tracks how many peers observed the same window.
Real-time visual dashboard at /admin/noc. Superadmin-only. Shows the health of the entire federation at a glance.
HTML dashboard with live auto-refresh (30s). Overall network health score (0–100%), per-peer status, Chart.js downtime graphs, trust state badges, space counts, and last-seen timestamps.
JSON API returning { joined, certNotAfter, lastRenewed, peerCount, health, peers[] }. Used by the dashboard and available for external monitoring integrations.
POST /admin/noc/peers/<domain>/trust revokes or restores trust for any peer. Revoked peers can no longer deliver to the inbox or receive from the outbox. Requires active superadmin session.
Per-peer Chart.js downtime visualization from the 360-day history. REST endpoints serve pre-computed graph JSON. Reliability scores and blip counts are visualized alongside the election weight they would generate.
?acct=user@domain resolves a local handle. Returns {handle, displayName, avatarUrl, exists}. Used for pre-send validation of cross-instance DMs.dm.message, friend.request, presence, directory.update). Validates HTTP signature + cert chain. Rejects spoofed From domains.{domain, publicKey} signed by the CSR key. Returns a PEM leaf cert on success. Idempotent re-enrollment supported.| Variable | Default | Description |
|---|---|---|
| PALACE_FEDERATION_ENABLED | false | Master on/off. Safe to leave unset for self-hosted instances that don't want to federate. |
| PALACE_INSTANCE_DOMAIN | BASE_DOMAIN | Canonical federation identity domain. Becomes the @suffix for all accounts on this server. |
| PALACE_CA_URL | https://ca.talx.fyi | CA enrollment endpoint. Override to run a private network with your own CA. |
| PALACE_NODES_URL | https://peer.talx.fyi | Directory bootstrap peer. 443→80 fallback automatic. |
| PALACE_CA_ENABLED | false | Host the CA service on ca.<base>. Generates/loads root keypair under psdata/federation/ca/. |
| PALACE_DIRECTORY_ENABLED | false | Host the directory node on peer.<base>. |
| PALACE_ADMIN_USERNAME | jonk | Superadmin username(s). DMs sent here on join/renewal/failure. Comma-separated for multiple. |
| PALACE_TRUST_ANCHORS | (CA root) | Additional CA pubkeys to trust. Use for private networks or adding extra anchors. |
| PALACE_FEDERATION_ALLOW_PRIVATE_CHALLENGE | false | Allow challenge fetches to loopback/private IPs. LAN testing only. |