Self-Hosting a Matrix Synapse Chat Server on Raspberry Pi: Encrypted Messaging Without the Cloud
This site covers self-hosting a lot of ground on a Raspberry Pi — photos with Immich, files with Syncthing, passwords with Vaultwarden, voice with Asterisk — but real-time encrypted group chat hasn't come up yet, and it's one of the most commonly requested self-hosted services for shops, families, and small communities who want Signal-style end-to-end encryption without depending on a centralized provider's servers. Matrix is an open, federated chat protocol, and Synapse is its most mature server implementation. Running your own Synapse homeserver on a Raspberry Pi gives you a private chat system that works like Discord or Slack for day-to-day use, supports end-to-end encrypted rooms and direct messages, and can optionally federate with other Matrix servers (or be locked down to stay fully private) — all running on hardware you control.
Is a Raspberry Pi Actually Enough?
Synapse has a reputation for being resource-hungry, and that reputation is earned at scale — a Synapse server participating in large public federation with thousands of rooms and millions of events can need real server-class hardware. For a private homeserver serving a household, shop, or small community (a few to a few dozen regular users, chat history measured in months rather years of a large federated community), a Raspberry Pi 5 with 8GB of RAM handles Synapse comfortably, especially running the database on a fast NVMe SSD via the Pi 5's PCIe interface (see our Pi 5 NVMe boot guide) rather than a microSD card. A Pi 4 can work for very light use but will feel sluggish once more than a couple of people are active simultaneously; budget for a Pi 5 if this is going into regular daily use rather than an experiment.
Installation: Docker Compose Is the Sane Path
Synapse can be installed from distribution packages or Python's pip, but the Matrix.org project's own Docker image is the best-supported and easiest-to-maintain path on a Pi, since it isolates Synapse's dependencies from your base OS and makes upgrades a matter of pulling a new image tag rather than fighting Python package versions. Start from a clean Raspberry Pi OS Lite (64-bit) install per our headless Pi setup guide, then install Docker and Docker Compose.
- Create a project directory and generate the initial Synapse homeserver configuration: mkdir -p ~/synapse/data docker run -it --rm \ -v ~/synapse/data:/data \ -e SYNAPSE_SERVER_NAME=chat.yourdomain.example \ -e SYNAPSE_REPORT_STATS=no \ matrixdotorg/synapse:latest generate This generates a homeserver.yaml and signing keys into the data directory. The server name you choose here becomes part of every user's Matrix ID (@username:chat.yourdomain.example) and is difficult to change later without re-provisioning accounts, so pick it deliberately even if you're not federating publicly.
- Write a docker-compose.yml that mounts the data directory, exposes port 8008 (or 8448 for federation) internally, and sets restart policy to unless-stopped so Synapse comes back up automatically after a Pi reboot or power loss.
- Start the stack with docker compose up -d and check logs with docker compose logs -f synapse for startup errors — the most common first-run failures are database permission issues on the mounted volume and a malformed homeserver.yaml from manual editing.
Database: Use PostgreSQL, Not SQLite
Synapse's default generated config uses SQLite, which works for initial testing but hits real performance limits quickly even on light multi-user load — SQLite's single-writer model becomes a bottleneck once several people are actively chatting. Run PostgreSQL as a separate container in the same Docker Compose stack and point Synapse at it in homeserver.yaml before you have real conversation history to migrate:
- Add a postgres service to the compose file using the official postgres:15 (or current stable) image, with a dedicated volume for its data directory.
- Create the Synapse database and user with CREATE DATABASE synapse ENCODING 'UTF8' LC_COLLATE='C' LC_CTYPE='C' template=template0; — Synapse requires this specific collation setting, and getting it wrong means recreating the database from scratch later.
- Update the database section of homeserver.yaml to use the psycopg2 driver pointing at the Postgres container's service name, user, password, and database name.
Migrating from an existing SQLite database to Postgres later is possible using Synapse's bundled synapse_port_db script, but it's slower and more error-prone than just starting on Postgres from the first real deployment.
Reverse Proxy and TLS
Matrix federation and most clients expect HTTPS, and Synapse itself doesn't terminate TLS by default. Put Nginx (see our Nginx reverse proxy guide) or Caddy in front of Synapse, proxying both the client API port and, if federating, the dedicated federation port, with a Let's Encrypt certificate. If you're not opening this to the public internet at all, running everything over Tailscale (see our Tailscale VPN guide) and skipping public TLS and federation entirely is a simpler, lower-maintenance setup for a private family or shop chat server — you lose the ability for outside Matrix users to join your rooms, but you gain a much smaller attack surface and skip the DNS/certificate/port-forwarding work entirely.
Federation: Decide Early Whether You Want It
Federation is what makes Matrix different from a plain self-hosted chat app — a user on your homeserver can join rooms and message people on completely different Matrix homeservers, the same way email works across different providers. It's also the source of most of Synapse's complexity and resource use, since a federated server has to validate and store events from rooms that include remote participants.
- Federation on: requires a real public domain with correctly configured DNS (either direct chat.yourdomain.example:8448 or a .well-known delegation setup), port forwarding or a reverse proxy reachable from the internet, and ongoing exposure to the broader Matrix federation's traffic and moderation considerations.
- Federation off: set federation_domain_whitelist: [] (or disable the federation listener entirely) and your homeserver becomes an isolated private chat system — still fully functional for everyone with an account on it, encrypted rooms and all, just unable to talk to accounts on other servers. This is the simpler and generally recommended starting point for a shop or family deployment.
Client Setup and User Management
Element is the reference Matrix client and works as a web app, desktop app, or mobile app, all pointed at your homeserver's URL. Create your first admin account from the command line with Synapse's register_new_matrix_user script rather than leaving open registration enabled, since a Synapse server with public registration turned on and exposed to the internet will get discovered and abused for spam within days. For a private family or shop server, leave registration disabled entirely after creating the accounts you need, and re-enable it briefly (with a registration shared secret) only when adding someone new.
Backups
Everything that matters lives in the Postgres database and the Synapse media store (uploaded files and images) under your mounted data directory — back up both together with a consistent snapshot, either with pg_dump for the database plus a file copy of the media store, or by snapshotting the whole data directory with the database container briefly stopped. Our Restic and Borg backup guide covers scheduling this as an automated job rather than a manual task you'll forget to run.
A self-hosted Synapse server is more maintenance than a hosted SaaS chat app, and the official project's own documentation is upfront that it's not the lightest piece of software to run — but on a Pi 5 with Postgres and a reasonable user count, it runs reliably, gives you encrypted messaging history you fully control, and avoids the retention, scanning, and monetization tradeoffs that come with chat on someone else's server.