Mastodon rewritten in Rust - a high-performance ActivityPub social media server
  • Rust 92.8%
  • PLpgSQL 4%
  • Shell 2.6%
  • Dockerfile 0.6%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Ric Harvey ab09cec764
Replace Elasticsearch with OpenSearch across search crate and docs
- Rename elasticsearch.rs to opensearch.rs, struct ElasticSearchEngine
  to OpenSearchEngine
- Update lib.rs module declaration and re-exports
- Update PLAN.md stack decisions and phase 8 description
- Add doc/ to .gitignore (generated Rust docs)

OpenSearch is the open-source fork of Elasticsearch. The HTTP API is
compatible so no query logic changes were needed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 19:28:51 +01:00
crates Replace Elasticsearch with OpenSearch across search crate and docs 2026-04-16 19:28:51 +01:00
.dockerignore Add Docker setup, compose stack, and interactive setup script 2026-04-16 19:12:18 +01:00
.env.example Replace Redis with Valkey across Docker, docs, and config 2026-04-16 19:20:11 +01:00
.gitignore Replace Elasticsearch with OpenSearch across search crate and docs 2026-04-16 19:28:51 +01:00
Cargo.lock Implement full Rustodon scaffold: all 13 phases of Mastodon rewrite in Rust 2026-04-16 18:58:21 +01:00
Cargo.toml Implement full Rustodon scaffold: all 13 phases of Mastodon rewrite in Rust 2026-04-16 18:58:21 +01:00
docker-compose.yml Replace Redis with Valkey across Docker, docs, and config 2026-04-16 19:20:11 +01:00
Dockerfile Add Docker setup, compose stack, and interactive setup script 2026-04-16 19:12:18 +01:00
PLAN.md Replace Elasticsearch with OpenSearch across search crate and docs 2026-04-16 19:28:51 +01:00
README.md Replace Redis with Valkey across Docker, docs, and config 2026-04-16 19:20:11 +01:00
setup.sh Replace Redis with Valkey across Docker, docs, and config 2026-04-16 19:20:11 +01:00

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 1030s <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
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

Component Technology
Web framework Axum
Database PostgreSQL via SQLx (compile-time checked)
Cache & pub/sub Valkey (Redis-compatible) via fred
HTTP client reqwest
Auth bcrypt, custom OAuth 2.0
Email lettre
Crypto rsa, sha2
HTML sanitisation ammonia
Async runtime Tokio

Quick Start

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:

  1. Wiring DB queries — replacing stub API responses with real SQLx queries
  2. Federation testing — interop testing with Mastodon, Pleroma, Akkoma, Misskey
  3. Media processing — integrating libvips for image/video transcoding
  4. Web UI — serving the Mastodon React frontend or building a native one
  5. Performance testing — benchmarking against Mastodon

License

AGPL-3.0-or-later — same as Mastodon.