Deployment guide

Host Matrix Synapse and Element on Your Own VPS

Deploy on a VPS Cloud →

Tutorial

Host Matrix Synapse and Element on Your Own VPS

Self-hosting9 min read7 steps

Matrix is the most complete federated and end-to-end encrypted messaging protocol in open source software. Hosting it on your own VPS gives you a messaging system under your domain name, capable of talking to the entire Matrix network, where neither content nor metadata passes through a third party. Here is a complete Docker deployment — Synapse, PostgreSQL, Element Web and reverse proxy — including the trap you need to know before starting: the domain name is IMMUTABLE.

Contents· Why host your own Matrix server1/12
  1. 01Why host your own Matrix server
  2. 02What you gain with a self-hosted Matrix server
  3. 03Self-hosted Element vs. app.element.io: the concrete difference
  4. 04The point to understand BEFORE installing: the domain name
  5. 05Hardware requirements
  6. 06Deploy Matrix with Docker, PostgreSQL and Element
  7. 07Administering Synapse after installation
  8. 08History purge and disk space management
  9. 09Bridges: connecting Matrix to Telegram, Signal and WhatsApp
  10. 10Matrix / Synapse vs. self-hosted messaging alternatives
  11. 11Close registrations, and keep them closed
  12. 12Official documentation

Why host your own Matrix server

Classic team messaging tools — Slack, Teams, and even self-hosted alternatives — share a limit: you can only talk with members of the same server. Matrix reverses this. It is a FEDERATED protocol: your server talks to all other Matrix servers in the world, exactly like an email address reaches any other domain. Your users keep an identity tied to you (@alice:your-domain.com) while chatting with people hosted elsewhere. Add to this end-to-end encryption, per-room: even you, as server admin, cannot read a message in an encrypted room. That is what sets Matrix apart from simply self-hosted messaging — sovereignty rests not on trust in the host, but on cryptography.

What you gain with a self-hosted Matrix server

  • Federation: your users reach those on any other Matrix server, without extra accounts.
  • End-to-end encryption per room, independent of trust in the host.
  • Identifiers tied to your domain name, becoming a lasting address.
  • Self-hosted Element Web: the interface stays under your control, without depending on app.element.io.
  • Official Element apps on mobile, desktop and web — all pointed at your server.
  • History and files stored on your machine, with no imposed retention limit.
  • Bridges to other networks (Telegram, Signal, IRC, XMPP…) are possible.
  • No advertising collection or profiling: metadata stays within your perimeter.

Self-hosted Element vs. app.element.io: the concrete difference

Element Web is an open source web application — you can host it on your own domain instead of using app.element.io. This choice is often overlooked, but it matters. When your users open app.element.io, their browser loads JavaScript from Element HQ's servers: this does not affect message confidentiality (encryption stays local), but it creates an external dependency.

Hosting Element Web yourself — typically behind chat.your-domain.com — removes this dependency. You control the deployed version, you can customize config.json so the interface is pre-configured to your homeserver, and your users have a single URL to remember.

Important: Element Web reads config.<domain>.json BEFORE config.json. If your configuration is not served correctly, the interface displays perfectly — and connects your users to the public server instead of yours. Verify both files respond with your configuration before inviting users.

The point to understand BEFORE installing: the domain name

This is the peculiarity of Matrix, and the most costly source of error. The server_name of your server — your domain name — is not a display setting: it is written INTO the identity of every object the server produces. Every user identifier (@alice:your-domain.com), every room identifier, every signed event contains it. Changing it after the fact is not possible: you must start from a blank server and recreate accounts. Choose the definitive subdomain at installation time, and attach it when you install the application — not after. On ServOrbit, the installation deliberately refuses to start if no domain is attached: better an immediate, clear failure than a server you will have to redo once accounts are created.

Hardware requirements

The full stack — Synapse, PostgreSQL, Element Web and reverse proxy — consumes around 300 MB at rest, measured on a fresh installation. A VPS with 2 GB RAM and 2 vCPUs is therefore more than adequate for a team, an association or a family.

Consumption depends mostly on PUBLIC rooms you join: Synapse retains the history and state of every federated room, and joining a few large community rooms can grow the database by several gigabytes. For that use case, target 4 GB RAM and monitor disk space.

PostgreSQL is essential — Synapse accepts SQLite, but does not recommend it beyond a test server. Also plan for a valid TLS certificate: without HTTPS, federation and mobile apps refuse to connect.

Deploy Matrix with Docker, PostgreSQL and Element

  1. Choose and point your domain

    Decide on the definitive subdomain (for example matrix.your-domain.com) and point it at your VPS with an A record. This name will become the server's identity. Add a second subdomain for Element Web if you want to host it separately (chat.your-domain.com). Both A records must be active before starting the container.

  2. Generate the configuration and signing key

    The first start of the Synapse image generates homeserver.yaml and most importantly the server's SIGNING KEY, which authenticates its events to other servers. Back it up: losing it is equivalent to losing the server's identity on the federated network. Also keep homeserver.yaml in your backup system — it contains shared secrets between components.

  3. Switch the database to PostgreSQL

    The image can only generate an SQLite configuration. Add a file in conf.d/ that redefines the database block for PostgreSQL — Synapse reads multiple --config-path and repeated keys override earlier ones. Create the database with C collation: Synapse refuses to start on a database with different collation, and this choice cannot be changed after creation.

  4. Place a reverse proxy in front

    Serve Element Web at the root of chat.your-domain.com and the Matrix API under /_matrix and /_synapse/client on matrix.your-domain.com, behind a TLS certificate per domain. Properly relay Upgrade and Connection headers: Matrix maintains long connections (WebSocket), otherwise real-time does not work. Also increase client_max_body_size to at least 50 MB for file transfers.

  5. Publish the .well-known delegation

    Expose /.well-known/matrix/server and /.well-known/matrix/client on your root domain. This allows other servers and mobile apps to find your homeserver without manual configuration. Then verify on federationtester.matrix.org: unverified federation can silently block external invitations.

  6. Configure Element Web on YOUR server

    Create a config.json pointing default_server_config at your homeserver. Element also reads config.<domain>.json first: serve both via your reverse proxy. Test by opening the interface in a private tab — no cookie or session — and verify the login screen offers your domain by default, not matrix.org.

  7. Create the first admin account

    Synapse creates no account on its own and registrations must remain closed. Create the admin account with register_new_matrix_user, then log in at https://chat.your-domain.com. On ServOrbit, this admin account is created automatically on first start and its generated password is readable in your client area.

Administering Synapse after installation

Synapse exposes an administration API at /_synapse/admin/v1 — reserved for accounts marked admin. Via this API, you can deactivate an account, purge room history, force logout of all devices for a user, or consult federation statistics.

Synapse Admin (open source web interface, deployable as a separate container) uses this same API and offers a graphical view: user list, rooms, registered devices and database size per room. Useful for spotting a federated room that is growing the database by several gigabytes.

For updates, Synapse publishes its images on ghcr.io/element-hq/synapse. Check release notes before each major update: some database migrations are irreversible, and Synapse explicitly documents minimum required versions to move between branches.

History purge and disk space management

A federated server accumulates the history of all joined rooms — including large public rooms. Without regular purging, the PostgreSQL database can reach tens of gigabytes within months.

Synapse provides two levers. History purge via the admin API (POST /_synapse/admin/v1/purge_history) deletes events prior to a date in a given room — without affecting other rooms or messages you have not yet read. The synapse_auto_compressor command then compresses state_groups groups in PostgreSQL, which can halve database size on a server active for several months.

Also enable gc_thresholds in homeserver.yaml to control Synapse's Python garbage collector: on an active federated server, the default GC is rarely optimal for resident memory.

Bridges: connecting Matrix to Telegram, Signal and WhatsApp

One of Matrix's distinctive advantages is its ecosystem of bridges — services that link your homeserver to other networks. Matterbridge, Beeper or the Matrix project's official bridges relay messages between a Matrix room and a Telegram group, a Slack channel or a WhatsApp conversation.

Each bridge deploys as an additional service (an extra container in your compose.yml) and registers with Synapse via a registration.yaml file. The bridge receives a portion of the identifier namespace (@telegram_*:your-domain.com) and translates messages in both directions.

For Telegram, mautrix-telegram is the most maintained bridge. For Signal, mautrix-signal. Both bridges require an account on the target network — no reading without an account. WhatsApp and Meta Messenger go through mautrix-meta, which uses the unofficial API: its functioning depends on Meta's decisions and may be interrupted.

Matrix / Synapse vs. self-hosted messaging alternatives

Scroll the table

CriterionMatrix + SynapseMattermostRocket.Chat
Inter-server federationYes, nativeNoNo
End-to-end encryptionYes, per roomOptional (beta)No (plaintext in transit)
Bridges to other networksYes (Telegram, Signal, Slack…)Partial (Slack)Partial
RAM consumption (idle)~300 MB (full stack)~400 MB~500 MB
Self-hostable web clientElement Web (open source)Yes (included)Yes (included)
Mobile clientsElement iOS/AndroidNative iOS/AndroidNative iOS/Android

Close registrations, and keep them closed

A Matrix server with open registrations is quickly discovered and used as a relay by third parties: spam accounts, unwanted rooms, and a database that grows without your doing anything. Keep enable_registration at false and create accounts manually, or use external authentication (SSO, OIDC). If you open registrations, require at minimum an email verification and enable registration_requires_token.

Official documentation

For advanced configuration — workers, bridges, authentication modules, history purge — refer to the official Synapse documentation. This guide covers deployment on VPS; the upstream docs remain the reference for fine-tuned settings and major version upgrades.

Launch your Matrix server on a ServOrbit VPS

A VPS with pre-configured Docker, an attached domain and a TLS certificate set up automatically: Synapse, PostgreSQL and Element Web deploy in one step. Your conversations stay with you.

Need help?

Browse our help center and FAQ, or reach our team — callback, WhatsApp or email. Support in French, English and Arabic.

Message us on WhatsAppopens in a new tab