@msonnb/fedisky
v0.0.2
Published
ActivityPub federation sidecar for ATProto PDS
Maintainers
Readme
Fedisky
An ActivityPub federation sidecar for ATProto PDS. Fedisky bridges Bluesky with the Fediverse, allowing ATProto users to be followed by and interact with users on Mastodon and other ActivityPub-compatible platforms.
Features
Outbound Federation (Bluesky → Fediverse)
- Posts: Bluesky posts are converted to ActivityPub
Noteobjects and delivered to followers - Replies: Reply threading is preserved with proper
inReplyToreferences - Likes: Likes on local posts generate ActivityPub
Likeactivities - Reposts: Reposts of local posts generate ActivityPub
Announceactivities - Deletions: Post deletions and undo operations are federated
Inbound Federation (Fediverse → Bluesky)
- Follows: ActivityPub users can follow Bluesky accounts
- Replies: Replies to Bluesky posts are bridged back via a dedicated bridge account with author attribution
Media Support
- Images (up to 4 per post) with alt text
- Videos (1 per post)
- Remote media is downloaded and re-uploaded to the PDS (max 10MB)
Rich Text
- Mentions are converted between formats (only local PDS users)
- Links are preserved as proper HTML anchors
- Language tags are carried through federation
Requirements
- An existing Bluesky PDS installation (via the official installer)
- Docker
Installation
Quick Install (Recommended)
If you have a PDS installed via the official Bluesky installer, run:
curl -fsSL https://raw.githubusercontent.com/msonnb/fedisky/main/fedisky-installer.sh | sudo bashThe installer will:
- Detect your existing PDS configuration
- Prompt for ActivityPub-specific settings (hostname, bridge account, etc.)
- Create the ActivityPub sidecar configuration
- Update Caddy to route ActivityPub traffic
- Add the sidecar to your Docker Compose setup
- Restart services
After installation, Mastodon users can find your PDS users by searching for @username@your-pds-hostname.
Manual Installation
For development or custom setups:
Requirements: Node.js >= 22.0.0, pnpm
pnpm install
pnpm buildConfiguration
| Variable | Required | Default | Description |
| ------------------------ | -------- | ----------------------- | ---------------------------------------------------- |
| PDS_URL | Yes | - | URL of the ATProto PDS |
| PDS_ADMIN_TOKEN | Yes | - | Admin token for PDS |
| AP_PORT | No | 2588 | Port for the service |
| AP_HOSTNAME | No | localhost | Public hostname for ActivityPub URLs |
| AP_PUBLIC_URL | No | Derived from hostname | Explicit public URL override (useful behind proxies) |
| AP_VERSION | No | 0.0.0 | Version reported in NodeInfo |
| AP_DB_LOCATION | No | :memory: | SQLite database path |
| AP_FIREHOSE_ENABLED | No | true | Enable firehose processing |
| AP_FIREHOSE_CURSOR | No | - | Cursor position to resume firehose from |
| AP_BRIDGE_HANDLE | No | mastodon.{hostname} | Handle for the bridge account |
| AP_BRIDGE_DISPLAY_NAME | No | Mastodon Bridge | Display name for the bridge account |
| AP_BRIDGE_DESCRIPTION | No | (default description) | Description for the bridge account profile |
Usage
Docker (via installer)
After running the installer, services are managed via systemd:
# Check status
sudo systemctl status pds
# View logs
sudo docker logs -f activitypub
# Restart
sudo systemctl restart pdsManual / Programmatic
Fedisky is a library - you need to create a script to start it:
import { APFederationService, readEnv, envToConfig } from '@msonnb/fedisky'
const config = envToConfig(readEnv())
const service = await APFederationService.create(config)
await service.start()
// Handle shutdown
process.on('SIGTERM', async () => {
await service.destroy()
process.exit(0)
})Endpoints
Application
| Endpoint | Method | Description |
| --------- | ------ | ------------ |
| /health | GET | Health check |
ActivityPub / Federation
| Endpoint | Description |
| ------------------------ | -------------------------------- |
| /.well-known/webfinger | WebFinger discovery |
| /.well-known/nodeinfo | NodeInfo discovery |
| /nodeinfo/2.1 | NodeInfo document |
| /users/{did} | Actor profile |
| /users/{did}/inbox | Per-user inbox |
| /users/{did}/outbox | Outbox collection (paginated) |
| /users/{did}/followers | Followers collection (paginated) |
| /users/{did}/following | Following collection (paginated) |
| /inbox | Shared inbox |
| /posts/{uri} | Individual Note object |
How It Works
Fedisky runs alongside your ATProto PDS and:
- Actor Discovery: Exposes ATProto users as ActivityPub actors via WebFinger (
@handle@hostname) - Firehose Processing: Subscribes to the PDS event stream and converts records to ActivityPub activities
- Activity Delivery: Delivers Create, Like, Announce, Delete, and Undo activities to followers' inboxes
- Inbox Handling: Accepts Follow requests and bridges replies back to Bluesky
- Bridge Account: A dedicated ATProto account posts Fediverse replies with attribution back into Bluesky threads
Bridge Account
The bridge account is automatically created on startup and handles inbound content from the Fediverse. When a Mastodon user replies to a bridged Bluesky post, the bridge account creates a new post with:
- Attribution prefix linking to the original author's profile
- Content converted from HTML to plain text
- Proper reply threading
- Re-uploaded media attachments
Uninstalling
To remove the ActivityPub sidecar while keeping your PDS:
- Stop services:
sudo systemctl stop pds - Remove the activitypub service from
/pds/compose.yaml - Restore the original Caddyfile (backups are in
/pds/caddy/etc/caddy/) - Remove ActivityPub data:
sudo rm -rf /pds/activitypub - Restart PDS:
sudo systemctl start pds
License
MIT
