Federation
Delivery and queues
How outbound activities are queued, retried, and made durable with Redis.
Outbound federation never happens inside a user’s request. Publishing a post enqueues a job; the request returns immediately.
The queue abstraction
Application code calls one thing:
queue.add("federate_post", { postId });
Two backends sit behind that call:
| Backend | When | Behaviour |
|---|---|---|
| In-process | No REDIS_URL |
Jobs live in memory; lost on restart |
| Redis | REDIS_URL set (the Compose default) |
Jobs persist; survives restarts; shared across processes |
The call sites and signatures are identical either way, so switching is a matter of setting one environment variable.
What Redis backs
When REDIS_URL is set, three things move out of process memory:
- The application job queue (federation deliveries and other background work).
- Fedify’s key-value store and message queue — its own delivery retry state.
- The rate limiter, so counters are shared across backend processes rather than per-process.
Delivery mechanics
For each recipient inbox, Fedify signs the request with the actor’s private key and POSTs the activity. It handles:
- HTTP signatures on every outbound request.
- Retries with backoff for transient failures.
- Shared-inbox optimisation — one delivery to a remote server serving many of your followers, instead of one per follower.
Failure modes
| Symptom | Cause | Action |
|---|---|---|
| One remote server never receives anything | It has defederated your domain | Nothing to fix on your side |
| Deliveries stall after a restart | In-process queue, jobs lost | Set REDIS_URL |
| Persistent signature errors | Domain or scheme mismatch in generated URIs | Check the public domain setting and that Caddy sets x-forwarded-proto |
| Everything is slow to arrive | Large follower set, normal backoff | Watch the backend logs; this is usually just retry pacing |
Federated reach
The writer dashboard’s “reach” figure counts successful deliveries to remote inboxes. It measures your instance’s sending, not anyone’s reading — there is no mechanism, and no intention, to observe reads on other servers. See Writer dashboard.
Inbound throttling
The receiving side is throttled too, so a hostile peer cannot flood you:
| Variable | Default | Meaning |
|---|---|---|
RL_INBOX_MAX |
300 | inbox POSTs per minute per source IP |
INBOX_MAX_BODY_BYTES |
1000000 | maximum accepted payload (bytes) |
Both are generous on purpose — a busy instance legitimately delivers many activities in a burst.
The redis_data volume
It holds only transient queue state and is deliberately excluded from backups — Redis re-drains it after a restart, and no durable content lives there. See Backups and restore.
Found a mistake?Edit this page on GitHub.