Sync Server is the backend component of the open-source, privacy-focused Sync chat application. It provides a decentralized, federated messaging platform inspired by Mastodon and Matrix, using ActivityPub for interoperability between servers (called "planets"). The server handles secure API endpoints for message sending, user management, and optional encrypted data backups. Emphasizing security and user control, chat data is primarily stored locally on client devices, with server-side storage only for opted-in, encrypted backups (similar to Signal).
This repo focuses on the server-side: Rust-based API, Next.js dashboard for administration, and easy deployment via Docker Compose. For the mobile client, see the companion repo: sync-mobile.
- Docker Engine + Docker Compose plugin
- Git
- (Production) A public domain pointing to your server
git clone https://github.com/OpenTech-Lab/sync-server.git
cd sync-server
cp .env.example .envEdit .env at minimum:
POSTGRES_PASSWORD(any strong value)JWT_SECRET(generate:openssl rand -hex 32)INSTANCE_NAMEADMIN_EMAILINSTANCE_DOMAIN- local/dev HTTP: set to
localhost - production HTTPS/federation: set to your real public domain
- local/dev HTTP: set to
Optional:
RESEND_API_KEY,RESEND_FROM_EMAIL(leave empty in local dev; password-reset emails are skipped)- Push delivery mode:
PUSH_DELIVERY_MODE=relay(default, recommended for open/public servers)- all push events are forwarded to
notification_webhook_url(hosted relay) - this stack now exposes a built-in relay endpoint at
/v1/push/webhook - if
notification_webhook_urlis empty, server auto-useshttps://push.{INSTANCE_DOMAIN}/v1/push/webhook(not applied for localhost/IP instance domains)
- all push events are forwarded to
PUSH_DELIVERY_MODE=direct- iOS is sent directly to APNs from this server
PUSH_DELIVERY_MODE=hybrid- iOS tries direct APNs first, then falls back to webhook relay
- APNs direct push credentials (only needed for
direct/hybrid):APNS_TEAM_IDAPNS_KEY_IDAPNS_BUNDLE_ID(must match iOS app bundle id)APNS_PRIVATE_KEY_P8(raw PEM with\nescapes or base64-encoded PEM)APNS_USE_SANDBOX=truefor dev builds,falsefor production/TestFlight
- Webhook host restriction (security default):
- by default,
notification_webhook_urlhost must equalpush.{INSTANCE_DOMAIN} - external relay hosts are not allowed
- by default,
- Relay webhook auth (recommended):
- set
PUSH_RELAY_SHARED_SECRETto requirex-sync-push-secreton webhook requests - set the same value on sender servers and relay server
- set
docker compose up -d
docker compose psHealth checks:
curl http://localhost/health
curl http://localhost/readyAccess:
- API via nginx:
http://localhost/api/... - Dashboard/Auth:
http://localhost/login(after login:/dashboard)
Set INSTANCE_DOMAIN=localhost in .env, then run:
bash scripts/init-ssl-dev.shOpen:
https://localhosthttps://localhost/login
When INSTANCE_DOMAIN is a real domain with DNS A/AAAA pointing to this host:
- Ensure both DNS records point to this server:
INSTANCE_DOMAINpush.INSTANCE_DOMAIN
- For reliable mobile-carrier access, publish both IPv4 (
A) and IPv6 (AAAA) records when your host supports IPv6. - Open TCP
80and443for both IPv4 and IPv6 in the host firewall / cloud security rules.
bash scripts/init-ssl.shThen access:
https://<INSTANCE_DOMAIN>https://<INSTANCE_DOMAIN>/login
The public-facing website (/) is served by a separate Next.js app living in web/, which is tracked as a git submodule pointing to Sync-web. It is excluded from the default stack — the core API, dashboard, and nginx all start without it.
If you cloned the repo without submodules, initialise it first:
git submodule update --init webTo update to the latest web release later:
git submodule update --remote web
git add web && git commit -m "chore: bump web submodule"docker compose --profile web build web
docker compose --profile web up -dThe web container starts on port 3000 internally. Nginx automatically routes all traffic at / to it — no config change needed.
To stop the web service without affecting the rest of the stack:
docker compose --profile web stop webcd web && git pull && cd ..
docker compose --profile web build web
docker compose --profile web up -d web# View logs
docker compose logs -f api
docker compose logs -f dashboard
docker compose logs -f nginx
# Restart services
docker compose restart api dashboard nginx
# Stop stack
docker compose downscripts/init-ssl-dev.shis for local dev (INSTANCE_DOMAIN=localhost).scripts/init-ssl.shis for real domains with Let's Encrypt.- If
mkcertis unavailable,init-ssl-dev.shfalls back to self-signedopensslcerts (browser warning expected). - If HTTPS works on Wi-Fi but fails on cellular, check whether the domain only has an
Arecord. Many mobile networks are IPv6-first, so you should provision anAAAArecord and allow IPv6 traffic on80/443. - For OSS/public infra, keep
PUSH_DELIVERY_MODE=relayand configurenotification_webhook_urlto your hosted push relay. - Direct APNs modes (
direct,hybrid) require APNs credentials and iOS Push Notifications capability enabled for the app id/profile.
Contributions welcome! See CONTRIBUTING.md for details.
- Focus on security: Include tests for JWT, encryption, and API.
- Report issues on GitHub.
- PRs for Rust crates, Next.js features, or Docker improvements.
MIT License - see LICENSE.
- Built on open-source tools: Rust ecosystem, ActivityPub spec, PostgreSQL/Redis.
- Inspired by Mastodon, Matrix, and Signal for federation and security.
For support, open an issue or join a community planet! 🚀
We welcome public participation in the direction of this project.
Use the Feature Request form in Issues.
Use the Community Survey form.
Use GitHub Discussions polls to vote on roadmap direction and upcoming features.
See the public roadmap here:
We consider:
- Community demand
- Security and stability
- Technical complexity
- Maintainer capacity
- Long-term product direction
