Serverless Fediverse platform on Cloudflare Workers.
SiliconBeest is a fully-featured Mastodon API-compatible social networking server built entirely on the Cloudflare developer platform. It federates with the wider Fediverse via ActivityPub and can be deployed to a global edge network with zero traditional server infrastructure.
Warning: Do not change your instance domain after federating. ActivityPub actor URIs contain the domain and are permanent identifiers across the Fediverse. Changing the domain after other servers have cached your actors will break all existing federation relationships, followers, and conversations. Choose your domain carefully before launch.
SiliconBeest is a GitHub Template Repository. Deploy your own Fediverse instance in minutes:
- Click "Use this template" on this repository
- Create Cloudflare resources:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/SJang1/siliconbeest/HEAD/scripts/install.sh)" - Set the output values as GitHub Secrets & Variables
- Run the Deploy workflow -- done!
Full deployment guide: English | 한국어
- Full Mastodon API v1/v2 -- works with existing clients (Tusky, Elk, Ice Cubes, Ivory, Mona, etc.)
- Accounts, statuses, timelines, notifications, conversations, lists, filters, polls, tags, bookmarks, favourites, search
- Admin API for moderation (accounts, reports, domain blocks, domain allows, IP blocks, email domain blocks, rules, settings, announcements, custom emojis, relays, measures)
- Fedify v2.3.3 -- TypeScript ActivityPub framework handling the protocol layer (signatures, WebFinger, NodeInfo, delivery)
@fedify/cfworkers-- Cloudflare Workers adapter (KV store + Queue message dispatcher)- ActivityPub server-to-server protocol
- HTTP Signatures (draft-cavage-http-signatures-12) -- RSA-SHA256 signing, handled by Fedify
- RFC 9421 double-knock -- modern HTTP Message Signatures for delivery, handled by Fedify
- Linked Data Signatures -- signing and verification for relay forwarding
- Ed25519 Object Integrity Proofs (FEP-8b32) --
ed25519-jcs-2022cryptosuite - Activity forwarding with original signature preservation
- Collection pagination (OrderedCollection / OrderedCollectionPage)
- Activity idempotency -- deduplication of incoming activities
- Instance actor for relay and instance-level activities
- Misskey extensions -- emoji reactions (
EmojiReact),_misskey_content,_misskey_quote - FEP-8b32 -- Object Integrity Proofs (Ed25519)
- FEP-8fcf -- Followers Collection Synchronization
- FEP-67ff -- FEDERATION.md
- FEP-e232 -- Quote Posts (
quoteUri) - Featured collections (pinned posts) via
Add/Remove - Custom emoji (local and remote)
- Relay support (admin-managed subscriptions)
- OAuth 2.0 + PKCE -- standards-compliant authorization flows with scope enforcement
- TOTP two-factor authentication (RFC 6238)
- WebAuthn / Passkeys -- passwordless authentication
- OAuth scope enforcement -- Mastodon-compatible hierarchical scope checking on all endpoints
- Token hashing -- access tokens stored as SHA-256 hashes, never plaintext
- Domain block enforcement -- blocked domains rejected at federation inbox level
- HTML sanitization -- allowlist-based sanitizer on both local and remote content
- CSP headers -- Content-Security-Policy, X-Content-Type-Options, X-Frame-Options on all responses
- Rate limiting -- KV-backed sliding window on auth, registration, and admin endpoints
- Registration control -- open, approval-required, or closed
- Email domain blocks -- prevent signups from blocked email domains
- WebSocket streaming -- live timeline updates via Cloudflare Durable Objects
- Web Push notifications -- VAPID (RFC 8292) + RFC 8291 encryption
- URL preview cards -- OpenGraph metadata fetching
- Media uploads -- R2 storage with async thumbnail processing
- Polls -- create and vote
- Content warnings and sensitive media flags
- HTML sanitization and content parsing (mentions, hashtags, links)
- Internationalization -- 12 language packs with lazy loading (en, ko, ja, zh-CN, zh-TW, es, fr, de, pt-BR, ru, ar, id)
- Dark mode -- system-aware and manual toggle
- Responsive design -- mobile-first with Tailwind CSS
- Admin dashboard -- accounts, reports, domain blocks, rules, settings, announcements, relays, custom emojis, federation
- Email -- dedicated email-sender worker consuming from a queue, SMTP via worker-mailer (password reset, notifications)
- Sentry integration -- optional error tracking (admin opt-in)
SiliconBeest runs as 3 Cloudflare Workers:
Clients (Mastodon apps, web)
|
v
+---------------------------+
| Cloudflare CDN / Edge |
+---------------------------+
|
v
+---------------------------------------+
| siliconbeest (main) |
| Hono API server + Vue 3 SPA frontend |
| |
| - Mastodon API v1/v2 |
| - OAuth 2.0 + PKCE + WebAuthn |
| - Fedify (ActivityPub federation) |
| - Admin API with rate limiting |
| - WebSocket streaming (Durable Objs) |
| - Vue 3 SPA (Tailwind, Pinia, i18n) |
+---------------------------------------+
| | | |
v v v v
+-----+ +----+ +--------+ +------------------+
| D1 | | R2 | | KV | | Durable Objects |
| SQL | |blob | |cache/ | | (StreamingDO) |
| DB | |store| |session | | WebSocket live |
+-----+ +----+ +--------+ +------------------+
+----------------------------+ +-----------------------------+
| siliconbeest-queue-consumer| | siliconbeest-email-sender |
| | | |
| - Federation delivery | | - SMTP via worker-mailer |
| - Timeline fanout | | - Password reset emails |
| - Notifications | | - Notification emails |
| - Media processing | +-----------------------------+
| - Web Push sending | |
+----------------------------+ +--------+
| | | Queue |
+------+ +------+ | email |
| Queue | | Queue | +--------+
| fed. | | int. |
+------+ +------+
The main worker enqueues email jobs to the email queue via its QUEUE_EMAIL producer binding. The email-sender worker consumes from that queue and sends mail via SMTP using worker-mailer.
A packages/shared/ directory contains code shared between workers:
crypto/-- Consolidated HTTP signature signing/verification and PEM key management (used by both the main worker and queue consumer)types/-- Shared Mastodon API base type definitions (used by both server and frontend)
| Layer | Technology |
|---|---|
| API Server | Hono + Chanfana + Zod on Cloudflare Workers |
| Federation | Fedify v2.3.3 + @fedify/cfworkers |
| Frontend | Vue 3 + Vite + Tailwind CSS + Headless UI |
| Database | Cloudflare D1 (SQLite) |
| Object Store | Cloudflare R2 |
| Cache/Session | Cloudflare KV |
| Job Queues | Cloudflare Queues |
| Streaming | Cloudflare Durable Objects (Hibernatable WS) |
| Auth | bcryptjs, OAuth 2.0, TOTP (RFC 6238) |
| Web Push | VAPID (RFC 8292) + RFC 8291 encryption |
| worker-mailer (SMTP) | |
| IDs | ULID (time-sortable) |
| i18n | vue-i18n (frontend) + custom (API errors) |
| Error Track | Sentry (optional) |
| Testing | Vitest + @cloudflare/vitest-pool-workers |
- Node.js 25+
- Wrangler CLI >= 4.x (
pnpm add -g wrangler) - A Workers Enabled Cloudflare account
- A domain managed by Cloudflare (for custom domain deployment)
git clone https://github.com/SJang1/siliconbeest.git
cd siliconbeest
# Install dependencies for all sub-projects
pnpm installThe setup script creates all Cloudflare resources, generates cryptographic keys, and configures your instance:
./scripts/setup.shIt will prompt for:
| Setting | Description | Example |
|---|---|---|
| Project prefix | Resource naming prefix | myserver (default: siliconbeest) |
| Instance domain | Your Fediverse domain | social.example.com |
| Instance title | Display name | My Fediverse Server |
| Registration mode | open / approval / closed | open |
| Admin email | Administrator email | admin@example.com |
| Admin username | Administrator handle | admin |
| Admin password | Administrator password | (hidden input) |
| Sentry DSN | Error tracking (optional) | https://...@sentry.io/... |
The script automatically:
- Creates D1 database, R2 bucket, KV namespaces (CACHE, SESSIONS, FEDIFY_KV), Queues
- Generates VAPID key pair (ECDSA P-256) for Web Push and stores in D1 settings
- Generates OTP encryption key for 2FA secrets
- Updates all
wrangler.jsoncfiles with resource IDs - Sets secrets via
wrangler secret put - Applies D1 database migrations
- Creates the admin user account
- Writes
siliconbeest/.envwith VAPID public key and optional Sentry DSN
# Deploy with custom domain routing (recommended)
./scripts/deploy.sh --domain social.example.com
# Or deploy to *.workers.dev subdomains (for testing)
./scripts/deploy.shWithout this step, federation is completely broken.
Cloudflare's Bot Fight Mode blocks ActivityPub traffic (403 to /users/*, /inbox). You must create a WAF Skip rule -- see scripts/README.md for full instructions.
# Full update: git pull -> install deps -> type check -> tests -> migrations -> deploy
./scripts/update.sh
# With specific branch
./scripts/update.sh --branch release/v0.2.0
# Preview changes without deploying
./scripts/update.sh --dry-runSee scripts/README.md for all update options and flags.
siliconbeest/
siliconbeest/ # Main app — API server (Hono) + Vue 3 SPA frontend
server/worker/ # Hono API server (Mastodon API, OAuth, ActivityPub)
server/worker/federation/ # Fedify inbox/outbox, dispatchers, helpers
server/worker/middleware/ # Auth, rate limiting, CORS, scope enforcement
server/worker/endpoints/ # All API route handlers
src/ # Vue 3 frontend (components, views, stores, i18n)
migrations/ # D1 database migrations (22 files)
test/worker/ # API server tests (55 files)
test/ # Vue frontend tests (11 files)
siliconbeest-queue-consumer/ # Async job processor (federation + internal queues)
siliconbeest-email-sender/ # Email sender (SMTP via worker-mailer)
scripts/ # Setup, deploy, and maintenance scripts
docs/ # Architecture docs, security audit, migration guides
FEDERATION.md # Federation capabilities (FEP-67ff)
See each sub-project README for details:
- siliconbeest/ -- Main Application: API Worker + Vue Frontend (README)
- siliconbeest-queue-consumer/ -- Queue Consumer (README)
- siliconbeest-email-sender/ -- Email Sender (README)
- scripts/ -- Setup, deploy, update, backup scripts (README)
cd siliconbeest
# API worker tests (55 test files, 805 tests)
pnpm exec vitest run --config vitest.worker.config.ts
# Vue frontend tests (11 test files)
pnpm exec vitest run
# Both suites
pnpm exec vitest run --config vitest.worker.config.ts && pnpm exec vitest run| Suite | Test Files | Coverage Areas |
|---|---|---|
| Worker | 55 | Auth (suspension, scopes), OAuth (PKCE, approval flow, token hashing), accounts, statuses, timelines, notifications, search, lists, markers, media, bookmarks, favourites, blocks/mutes, conversations, filters, tags, polls, reports, admin (accounts, roles, domain blocks, rules, announcements, relays, custom emojis), ActivityPub, federation (Fedify dispatchers, inbox processing, delivery, domain block enforcement), collection pagination, activity idempotency, featured collections, emoji reactions, custom emojis, quote posts, WebFinger, NodeInfo, content parsing, serializers, sanitization, ULID, instance, discovery, passwords, WebAuthn, proxy (SSRF), email verification, email domain blocks, scope enforcement |
| Vue | 11 | Stores (auth, ui, statuses, timelines), components (Avatar, LoadingSpinner, StatusActions, FollowButton), API client, i18n, router guards |
All scripts read resource names from scripts/config.sh. Customize by setting PROJECT_PREFIX or creating scripts/config.env (see scripts/config.env.example).
| Script | What it does |
|---|---|
./scripts/setup.sh |
Interactive first-time setup (creates resources, keys, admin) |
./scripts/deploy.sh --domain social.example.com |
Deploy with custom domain routing |
./scripts/update.sh |
Pull, test, migrate, redeploy (production updates) |
./scripts/backup.sh |
Backup D1 + R2 data |
./scripts/migrate.sh |
Apply D1 database migrations |
./scripts/seed-admin.sh |
Create an admin user account |
./scripts/delete-account.sh |
AP-compliant account deletion (sends Delete to all peers) |
./scripts/generate-vapid-keys.sh |
Generate/rotate VAPID key pair |
./scripts/configure-domain.sh |
Set up Workers Routes for a custom domain |
./scripts/sync-config.sh |
Sync Cloudflare resource IDs → wrangler.jsonc (new machine/recovery) |
See the full scripts documentation for all options and flags.
| Secret | Workers | Set by |
|---|---|---|
OTP_ENCRYPTION_KEY |
worker | setup.sh |
SETUP_SECRET |
worker | setup.sh / install.sh |
SENTRY_DSN (optional) |
worker | manual: wrangler secret put SENTRY_DSN |
VAPID keys are stored in the D1
settingstable (keys:vapid_public_key,vapid_private_key) and managed via the Admin settings page orsetup.sh. They are not set as environment secrets.
| Variable | Description | Default |
|---|---|---|
INSTANCE_DOMAIN |
Your instance domain | siliconbeest.com |
INSTANCE_TITLE |
Instance display name | SiliconBeest |
REGISTRATION_MODE |
open / approval / closed |
open |
SKIP_SIGNATURE_VERIFICATION |
Explicit true / false override for inbound HTTP signature verification; GitHub Actions reads this from GitHub Environment Variables during deploy |
false |
Observability drains (optional): to forward the main worker's logs/traces to an OTLP backend such as Sentry, first create Logs/Traces destinations under Workers & Pages → Observability in the Cloudflare dashboard — each destination holds the OTLP endpoint URL and any auth headers (for Sentry: header
x-sentry-authwith valuesentry sentry_key=<public key>; copy both from Sentry's Client Keys (DSN) → OpenTelemetry (OTLP) page). Then setOBSERVABILITY_LOGS_DESTINATIONS/OBSERVABILITY_TRACES_DESTINATIONS(comma-separated destination names) as GitHub Environment Variables — or inscripts/config.envfor manual deploys.sync-config.shwrites them into theobservability.logs/observability.tracesblocks of the main worker'swrangler.jsonc.
| Variable | Description | Required |
|---|---|---|
VITE_INSTANCE_DOMAIN |
Instance domain (for meta tags) | Yes |
VITE_VAPID_PUBLIC_KEY |
VAPID public key (for Web Push) | Yes |
VITE_SENTRY_DSN |
Sentry DSN for error tracking (CI deploys read the SENTRY_CLIENT_DSN GitHub Variable instead) |
No |
VITE_SENTRY_FEEDBACK |
true shows the Sentry user-feedback widget (requires VITE_SENTRY_DSN; CI deploys read the SENTRY_FEEDBACK_ENABLED GitHub Variable) |
No |
# Terminal 1 -- Main app: API worker + Vue frontend (port 8787)
cd siliconbeest && pnpm exec wrangler dev
# Terminal 2 -- Queue consumer
cd siliconbeest-queue-consumer && pnpm exec wrangler dev
# Terminal 3 -- Email sender
cd siliconbeest-email-sender && pnpm exec wrangler dev
# Terminal 4 -- Vue frontend dev server with HMR (port 5173, optional)
cd siliconbeest && pnpm run devFor local D1, apply migrations first:
cd siliconbeest && pnpm exec wrangler d1 migrations apply siliconbeest-db --localEstimated cost with a Workers Enabled account:
| Resource | 100 users/mo | 1000 users/mo |
|---|---|---|
| Workers requests | ~1.5M (incl.) | ~15M ($1.50) |
| D1 reads | ~300K (incl.) | ~3M (incl.) |
| D1 writes | ~30K (incl.) | ~300K (incl.) |
| R2 storage | ~1 GB ($0.02) | ~10 GB ($0.15) |
| KV operations | ~500K (incl.) | ~5M (incl.) |
| DO requests | ~300K (incl.) | ~3M ($0.30) |
| Queues | ~100K (incl.) | ~1M (incl.) |
| Total | ~$5/mo | ~$7/mo |
See the contributing guide for development setup, coding guidelines, test commands, database migration rules, and the pull request checklist: English | 한국어.
GNU Affero General Public License v3.0 (AGPL-3.0)
This is the standard license for Fediverse server software. Any modified version deployed as a network service must make its source code available.