Federation Setup
Ferro supports ActivityPub federation, allowing separate Ferro instances to follow each other and share files across the network.
Prerequisites
- Two or more Ferro instances with public URLs
- A shared federation secret (or separate secrets for each server pair)
- HTTPS on both servers (required for HTTP Signatures)
Setting Up Federation
Step 1: Configure the first server
ferro-server \
--external-url "https://ferro-a.example.com" \
--federation-secret "shared-secret-value" \
--data-dir /var/lib/ferro \
--admin-user admin \
--admin-password secure-password
Step 2: Configure the second server
ferro-server \
--external-url "https://ferro-b.example.com" \
--federation-secret "shared-secret-value" \
--data-dir /var/lib/ferro \
--admin-user admin \
--admin-password secure-password
Both servers must use the same federation secret for HMAC-SHA256 signature verification to succeed.
Step 3: Verify federation is enabled
curl https://ferro-a.example.com/fed/nodeinfo
{
"version": "2.1",
"software": {
"name": "ferro",
"version": "2.5.1"
},
"protocols": ["activitypub", "webfinger", "dav"],
"services": {
"inbound": ["activitypub", "webdav", "caldav", "carddav"],
"outbound": ["activitypub"]
}
}
Following Other Servers
Send a Follow activity
To follow another Ferro server, send a Follow activity to its inbox:
# Construct the signing string
METHOD="POST"
PATH="/fed/inbox"
KEY_ID="https://ferro-a.example.com/fed/actor/admin#main-key"
# Create HMAC-SHA256 signature
SIGNING_STRING="(request-target): post /fed/inbox"
SIGNATURE=$(echo -n "$SIGNING_STRING" | openssl dgst -sha256 -hmac "shared-secret-value" -binary | base64)
# Send Follow activity
curl -X POST https://ferro-b.example.com/fed/inbox \
-H "Content-Type: application/json" \
-H "Signature: keyId=\"${KEY_ID}\",algorithm=\"hs2019\",headers=\"(request-target)\",signature=\"${SIGNATURE}\"" \
-d '{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Follow",
"id": "https://ferro-a.example.com/activities/follow-1",
"actor": "https://ferro-a.example.com/fed/actor/admin",
"object": "https://ferro-b.example.com/fed/actor/admin",
"to": ["https://ferro-b.example.com/fed/actor/admin"]
}'
The target server will automatically accept the Follow and add the actor to its followers list.
Check followers
curl https://ferro-b.example.com/fed/actor/admin/followers
Federated Sharing
Share a file with all your followers using an Announce activity:
curl -X POST https://ferro-a.example.com/api/fed/share \
-H "Authorization: Bearer TOKEN" \
-H "Content-Type: application/json" \
-d '{"path": "/documents/report.pdf"}'
This creates an Announce activity and delivers it to all followers' inboxes.
WebFinger Discovery
Other servers can discover your actor via WebFinger:
curl "https://ferro-a.example.com/.well-known/webfinger?resource=acct:admin@ferro-a.example.com"
Security Considerations
- Shared secret -- The federation secret is used for HMAC-SHA256 signature verification. Keep it secure and rotate it periodically.
- HTTPS required -- HTTP Signatures are transmitted over the wire. Use TLS to prevent interception.
- Actor validation -- Ferro validates that the signature
keyIdmatches the activityactorfield to prevent spoofing. - Empty secret = disabled -- If
--federation-secretis not set, the inbox returns 503 and federation is disabled. - Firewall -- Restrict
/fed/inboxaccess if you only want specific servers to federate.
Troubleshooting
Federation returns 503
Set the --federation-secret flag. An empty secret disables federation.
Signature verification failed
Ensure both servers use the same federation secret and the keyId actor matches the activity actor.
Activity not delivered to followers
Check server logs for delivery errors. Delivery happens asynchronously.