Rustodon
A Mastodon-compatible ActivityPub server written in Rust, targeting full feature parity with Mastodon.
Rustodon replaces Mastodon's three separate processes (Ruby on Rails, Node.js streaming, Sidekiq workers) with a single compiled binary, resulting in dramatically lower memory usage, faster response times, and simpler deployment.
Status: Scaffold complete — all API routes, database schema, and core systems are implemented. Database query wiring is in progress. Not yet ready for production use.
Why Rustodon?
|
Mastodon |
Rustodon |
| Language |
Ruby (Rails) + Node.js + Redis/Sidekiq |
Rust + Valkey |
| Processes |
3 (web, streaming, worker) |
1 binary, 4 subcommands |
| Memory (idle) |
~800 MB+ |
Target: <100 MB |
| Startup time |
10–30s |
<1s |
| Dependencies |
Ruby, Node.js, Yarn, Bundler, libicu, libidn, ImageMagick |
Single static binary |
| Deployment |
Complex (multiple services, build tools) |
Single Docker image or binary |
| Database |
PostgreSQL (ActiveRecord) |
PostgreSQL (SQLx, compile-time checked) |
| API compat |
— |
Mastodon client API compatible |
Feature Comparison
Legend
| Symbol |
Meaning |
| ✅ |
Fully implemented and working |
| 🚧 |
Scaffolded — API routes and types exist, DB wiring in progress |
| 📋 |
Planned |
| ❌ |
Not planned / not applicable |
Core Features
| Feature |
Mastodon |
Rustodon |
Notes |
| Statuses (toots) |
✅ |
🚧 |
Create, edit, delete, reply, thread views |
| Character limit |
✅ 500 |
🚧 500 (configurable) |
MAX_TOOT_CHARS env var |
| Content warnings |
✅ |
🚧 |
Spoiler text / CW support |
| Polls |
✅ |
🚧 |
Create, vote, multiple choice |
| Favourites |
✅ |
🚧 |
Like / favourite statuses |
| Boosts (reblogs) |
✅ |
🚧 |
Reblog with optional visibility |
| Bookmarks |
✅ |
🚧 |
Private bookmarks |
| Quotes |
✅ |
🚧 |
Quote posts (Mastodon 4.4+) |
| Scheduled statuses |
✅ |
🚧 |
Post at a future time |
| Status editing |
✅ |
🚧 |
Edit history preserved |
Timelines
| Feature |
Mastodon |
Rustodon |
Notes |
| Home timeline |
✅ |
🚧 |
Followed accounts + boosts |
| Local timeline |
✅ |
🚧 |
All local public posts |
| Federated timeline |
✅ |
🚧 |
All known public posts |
| Hashtag timeline |
✅ |
🚧 |
Posts with a specific tag |
| List timelines |
✅ |
🚧 |
Custom account lists |
| Link timeline |
✅ |
🚧 |
Posts sharing the same link |
| Conversations |
✅ |
🚧 |
Direct message threads |
Accounts & Social
| Feature |
Mastodon |
Rustodon |
Notes |
| Registration |
✅ |
🚧 |
Open, approval, or invite-only |
| Profiles |
✅ |
🚧 |
Display name, bio, avatar, header, fields |
| Follow / unfollow |
✅ |
🚧 |
With follow request for locked accounts |
| Block / mute |
✅ |
🚧 |
Account and conversation muting |
| Domain blocks |
✅ |
🚧 |
Hide entire instances |
| Endorsements |
✅ |
🚧 |
Pin accounts to profile |
| Account notes |
✅ |
🚧 |
Private notes on other accounts |
| Familiar followers |
✅ |
🚧 |
"Followed by X" indicators |
| Follow suggestions |
✅ |
🚧 |
Algorithm-free suggestions |
| Account migration |
✅ |
🚧 |
Move followers between instances |
| Featured tags |
✅ |
🚧 |
Pin hashtags to profile |
Authentication & Security
| Feature |
Mastodon |
Rustodon |
Notes |
| OAuth 2.0 |
✅ |
🚧 |
Full OAuth provider (47 scopes) |
| App registration |
✅ |
🚧 |
Third-party app support |
| Two-factor auth |
✅ |
🚧 |
TOTP-based 2FA |
| WebAuthn |
✅ |
🚧 |
Hardware security keys |
| Password hashing |
✅ bcrypt |
✅ bcrypt |
Mastodon-compatible (cost 10) |
| Token generation |
✅ |
✅ |
Doorkeeper-compatible 64-char hex |
| Scope hierarchy |
✅ |
✅ |
read implies read:accounts, etc. |
Federation (ActivityPub)
| Feature |
Mastodon |
Rustodon |
Notes |
| ActivityPub protocol |
✅ |
🚧 |
Full AS2/AP type system implemented |
| HTTP Signatures |
✅ |
✅ |
RSA-SHA256 sign + verify |
| WebFinger |
✅ |
🚧 |
acct: URI resolution |
| NodeInfo |
✅ |
✅ |
Instance metadata endpoint |
| Activity delivery |
✅ |
🚧 |
Signed POST to remote inboxes |
| Shared inbox |
✅ |
🚧 |
Deduplicated delivery |
| Inbox processing |
✅ |
🚧 |
16 activity type handlers |
| Remote account resolution |
✅ |
🚧 |
Fetch + cache remote actors |
| Signature verification |
✅ |
✅ |
Verify inbound signatures |
| Authorized fetch |
✅ |
📋 |
Require signed GET for AP objects |
Notifications
| Feature |
Mastodon |
Rustodon |
Notes |
| Notification types |
✅ |
🚧 |
mention, favourite, reblog, follow, poll, update, admin |
| Grouped notifications |
✅ |
🚧 |
v2 notification groups |
| Notification policies |
✅ |
🚧 |
Filter by relationship type |
| Notification requests |
✅ |
🚧 |
Accept/reject from unknown accounts |
| Web Push |
✅ |
🚧 |
VAPID-based push notifications |
Media
| Feature |
Mastodon |
Rustodon |
Notes |
| Image upload |
✅ |
🚧 |
JPEG, PNG, GIF, WebP, AVIF, HEIC |
| Video upload |
✅ |
🚧 |
MP4, WebM, MOV |
| Audio upload |
✅ |
🚧 |
MP3, OGG, FLAC, WAV, AAC |
| Thumbnails |
✅ |
🚧 |
Auto-generated previews |
| Blurhash |
✅ |
🚧 |
Placeholder hashes for lazy loading |
| Alt text |
✅ |
🚧 |
Image descriptions for accessibility |
| Focal points |
✅ |
🚧 |
Smart cropping hints |
| S3 storage |
✅ |
🚧 |
S3-compatible object storage |
| Local storage |
✅ |
✅ |
Filesystem storage backend |
Search
| Feature |
Mastodon |
Rustodon |
Notes |
| Full-text search |
✅ Elasticsearch/OpenSearch |
🚧 OpenSearch + PG fallback |
Both backends implemented |
| Account search |
✅ |
🚧 |
By username, display name |
| Hashtag search |
✅ |
🚧 |
Autocomplete and trending |
| Status search |
✅ |
🚧 |
Own posts always; others if opted in |
| PostgreSQL fallback |
❌ |
🚧 |
tsvector search when no ES/OS |
Streaming
| Feature |
Mastodon |
Rustodon |
Notes |
| WebSocket API |
✅ Node.js |
✅ Axum |
Native Rust — no separate process |
| User stream |
✅ |
🚧 |
Home timeline + notifications |
| Public stream |
✅ |
🚧 |
Local and federated |
| Hashtag stream |
✅ |
🚧 |
Real-time hashtag feed |
| List stream |
✅ |
🚧 |
Per-list streaming |
| Direct stream |
✅ |
🚧 |
Direct messages |
| Valkey pub/sub |
✅ |
✅ |
Event distribution backbone (Redis-compatible) |
Administration & Moderation
| Feature |
Mastodon |
Rustodon |
Notes |
| Admin API |
✅ |
🚧 |
Full admin REST API |
| Reports |
✅ |
🚧 |
Report, review, resolve |
| Account actions |
✅ |
🚧 |
Warn, silence, suspend, freeze |
| Domain blocks |
✅ |
🚧 |
Silence, suspend, reject media |
| IP blocks |
✅ |
🚧 |
Block by IP/range |
| Email domain blocks |
✅ |
🚧 |
Block registration by email domain |
| Server rules |
✅ |
🚧 |
Instance rules display |
| Announcements |
✅ |
🚧 |
Instance-wide announcements |
| Audit log |
✅ |
🚧 |
Admin action history |
| Trends |
✅ |
🚧 |
Trending tags, statuses, links |
| Webhooks |
✅ |
🚧 |
Outgoing event webhooks |
Content Filtering
| Feature |
Mastodon |
Rustodon |
Notes |
| Keyword filters (v2) |
✅ |
🚧 |
Filter by keyword with regex |
| Status filters |
✅ |
🚧 |
Filter specific statuses |
| Filter contexts |
✅ |
🚧 |
Home, notifications, public, thread, account |
| Filter actions |
✅ |
🚧 |
Warn or hide |
| Filter expiration |
✅ |
🚧 |
Auto-expiring filters |
Email
| Feature |
Mastodon |
Rustodon |
Notes |
| Confirmation emails |
✅ |
🚧 |
Account verification |
| Password reset |
✅ |
🚧 |
Forgot password flow |
| Notification emails |
✅ |
🚧 |
Digest and individual |
| Welcome email |
✅ |
🚧 |
New user onboarding |
| SMTP transports |
✅ |
✅ |
SMTP, SMTPS, STARTTLS |
Translation
| Feature |
Mastodon |
Rustodon |
Notes |
| Post translation |
✅ DeepL/LibreTranslate |
🚧 LibreTranslate |
Self-hosted translation |
Third-Party App Compatibility
| App |
Mastodon |
Rustodon |
Notes |
| Mastodon Web UI |
✅ |
📋 |
Serve React frontend as static assets |
| Tusky (Android) |
✅ |
🚧 |
API-compatible |
| Ivory (iOS) |
✅ |
🚧 |
API-compatible |
| Ice Cubes (iOS) |
✅ |
🚧 |
API-compatible |
| Elk (Web) |
✅ |
🚧 |
API-compatible |
| Megalodon |
✅ |
🚧 |
API-compatible |
| Mona (macOS/iOS) |
✅ |
🚧 |
API-compatible |
Architecture
Rustodon is a Cargo workspace with 13 crates:
rustodon # CLI binary: serve | worker | streaming | all
rustodon-core # Config, Snowflake IDs, errors, tracing
rustodon-db # SQLx models (17 modules), migrations
rustodon-activitypub # ActivityPub/ActivityStreams type system
rustodon-federation # HTTP Signatures, delivery, inbox processing
rustodon-api # Mastodon-compatible REST API (Axum)
rustodon-streaming # WebSocket streaming (Axum + Valkey pub/sub)
rustodon-workers # Valkey-backed job queue + scheduler
rustodon-search # OpenSearch + PostgreSQL tsvector fallback
rustodon-media # Upload, processing, local/S3 storage
rustodon-auth # OAuth 2.0, bcrypt, bearer token middleware
rustodon-email # SMTP mailer (lettre) + templates
rustodon-admin # Admin API routes
Technology Stack
Quick Start
Using the setup script (recommended)
git clone https://codeberg.org/ric_harvey/rustodon.git
cd rustodon
./setup.sh
The interactive script will ask for your domain, admin credentials, and optional services (OpenSearch, LibreTranslate), then generate secrets, build, and launch everything.
Manual setup
# 1. Copy and edit configuration
cp .env.example .env
# Edit .env — set LOCAL_DOMAIN, SECRET_KEY_BASE (openssl rand -hex 64)
# 2. Start with Docker Compose
docker compose up -d
# With optional search and translation:
docker compose --profile search --profile translate up -d
Development (without Docker)
# Prerequisites: Rust 1.86+, PostgreSQL, Valkey (or Redis)
# Build
cargo build
# Run tests (213 tests)
cargo test
# Run the server
export DATABASE_URL=postgres://user:pass@localhost/rustodon
export LOCAL_DOMAIN=localhost
export SECRET_KEY_BASE=$(openssl rand -hex 64)
cargo run -- serve
Deployment
Single binary
cargo build --release
# Binary at: target/release/rustodon
# Run all services in one process (small instances)
./rustodon all
# Or run separately (larger instances)
./rustodon serve # Web server on :3000
./rustodon streaming # WebSocket on :4000
./rustodon worker # Background jobs
Docker
docker build -t rustodon .
docker run -p 3000:3000 --env-file .env rustodon serve
Docker Compose (full stack)
docker compose up -d # Core services
docker compose --profile search up -d # + OpenSearch
docker compose --profile translate up -d # + LibreTranslate
API Compatibility
Rustodon implements the Mastodon API at these endpoints:
| Endpoint group |
Path |
Status |
| Instance |
GET /api/v1/instance, GET /api/v2/instance |
🚧 |
| Apps |
POST /api/v1/apps |
🚧 |
| OAuth |
POST /oauth/token |
🚧 |
| Accounts |
/api/v1/accounts/* |
🚧 |
| Statuses |
/api/v1/statuses/* |
🚧 |
| Timelines |
/api/v1/timelines/* |
🚧 |
| Notifications |
/api/v1/notifications/*, /api/v2/notifications/* |
🚧 |
| Search |
/api/v2/search |
🚧 |
| Streaming |
GET /api/v1/streaming (WebSocket) |
🚧 |
| Filters |
/api/v1/filters/*, /api/v2/filters/* |
🚧 |
| Lists |
/api/v1/lists/* |
🚧 |
| Media |
/api/v1/media/*, /api/v2/media/* |
🚧 |
| Polls |
/api/v1/polls/* |
🚧 |
| Trends |
/api/v1/trends/* |
🚧 |
| Admin |
/api/v1/admin/* |
🚧 |
| WebFinger |
GET /.well-known/webfinger |
🚧 |
| NodeInfo |
GET /.well-known/nodeinfo, GET /nodeinfo/2.0 |
✅ |
| Host-Meta |
GET /.well-known/host-meta |
✅ |
Database
Rustodon uses the same PostgreSQL schema as Mastodon for drop-in migration compatibility:
- 113 tables + 4 materialised views
- Snowflake IDs for statuses, media attachments, notifications, quotes, collections
- 2 migration files (~3,100 lines of SQL)
Testing
cargo test # 213 tests across all crates
cargo test -p rustodon-auth # 35 tests (OAuth, password, middleware)
cargo test -p rustodon-activitypub # 37 tests (AP types, signatures)
cargo test -p rustodon-streaming # 35 tests (WebSocket, channels)
cargo test -p rustodon-federation # 28 tests (HTTP signatures, inbox)
Contributing
Contributions are welcome. The main areas that need work:
- Wiring DB queries — replacing stub API responses with real SQLx queries
- Federation testing — interop testing with Mastodon, Pleroma, Akkoma, Misskey
- Media processing — integrating libvips for image/video transcoding
- Web UI — serving the Mastodon React frontend or building a native one
- Performance testing — benchmarking against Mastodon
License
AGPL-3.0-or-later — same as Mastodon.