Skip to main contentSkip to navigation
[email protected]
Client AreaSupport
Hosting Mammoth
HostingMammothYour Data, Our Responsibility
Home
Solutions
Hosting Services
Store
Pricing
About
Blog
API
Contact

Stay Ahead of the Curve

Get the latest insights on cybersecurity, AI innovations, and enterprise data solutions delivered to your inbox.

Hosting Mammoth
HostingMammothEnterprise Solutions

Enterprise-grade data solutions. Hosting, recovery, cybersecurity, and AI-powered services for businesses worldwide.

[email protected]
Sun - Fri, 9:00am - 5:00pm

Services

  • Cloud Hosting
  • Data Recovery
  • Cybersecurity
  • Legal Support
  • MSP Services
  • Web Development
  • AI Services
  • Free Server Migration

Hosting

  • VPS Hosting (NVMe SSD)
  • VDS Hosting (NVMe)
  • Storage VPS (High SSD)
  • GPU Servers
  • Managed Services
  • Cloud Firewall
  • Load Balancer
  • One-Click Apps
  • n8n Hosting
  • Object Storage
  • FAQ

Company

  • Store
  • Pricing
  • About Us
  • Locations
  • Blog
  • Testimonials
  • Contact
  • Affiliate Program
  • White-Label
  • Terms of Service
  • Privacy Policy
  • Browser Cookies
  • SLA

Support

  • Client Area
  • Submit Ticket
  • Knowledge Base
  • Server Status
  • API Documentation

© 2026 Hosting Mammoth. All rights reserved.

Knowledge Base
Getting StartedAccount ManagementVPS HostingGPU ServersStorage VPSCloud FirewallLoad BalancerServer ManagementBilling & PaymentsSupport & TicketsAffiliate ProgramReseller ProgramMarketplace & Appsn8n HostingManaged ServicesServer MigrationAPI & DevelopersSecurityTroubleshootingGlossaryInstall Guides
  1. Home
  2. /
  3. Support
  4. /
  5. Install Guides
  6. /
  7. How To Install Matrix Synapse Ubuntu
GUIDEInstall Guides

How to Install Matrix Synapse + Element on Ubuntu 24.04 — Self-Host Decentralized Chat

24 min read

How to Install Matrix Synapse + Element on Ubuntu 24.04 — Self-Host Decentralized Chat on Your VPS

Centralized chat platforms control your conversations, your data, and increasingly your ability to say things they disagree with. Discord can delete servers overnight. Slack holds historical messages hostage behind a paywall. WhatsApp and Telegram each know exactly who you talk to, when, and from where. Matrix is the decentralized, federated, end-to-end encrypted alternative — and unlike XMPP or IRC, it has a mature ecosystem, modern mobile apps, voice and video calling, and a growing list of governments and Fortune 500 companies running their own homeservers.

This tutorial walks you through deploying a production-ready Matrix Synapse homeserver with the Element web client on an Ubuntu 24.04 VPS. By the end you will have your own federated chat service at @you:yourdomain.com, able to talk to users on matrix.org, Mozilla, KDE, the German Bundeswehr, and anyone else running Matrix — with all traffic end-to-end encrypted and your server in control of the keys.

Skip the manual config? The Professional VPS plan has the exact specs Synapse needs for a 50-200 user deployment — 6 vCPU, 12 GB RAM, 100 GB NVMe — at a flat monthly rate with unmetered bandwidth.

Table of Contents

  • Why Self-Host Matrix Instead of Using Discord or Slack?
  • Architecture Overview
  • Prerequisites
  • Step 1: Prepare DNS and the Server
  • Step 2: Install PostgreSQL 16
  • Step 3: Install Synapse from the Matrix.org Debian Repo
  • Step 4: Configure homeserver.yaml
  • Step 5: Register the First Admin User
  • Step 6: Nginx Reverse Proxy and TLS
  • Step 7: Publish .well-known Delegation Files
  • Step 8: Deploy the Element Web Client
  • Step 9: Verify Federation
  • Step 10: Install Appservice Bridges
  • Hardening and Maintenance
  • Troubleshooting
  • FAQ
  • Next Steps
  • Why Self-Host Matrix Instead of Using Discord or Slack?

    Matrix is an open protocol, not a product. That single fact drives every other advantage:

    • No vendor can delete your community. Your rooms live on your server. Even if matrix.org itself disappeared tomorrow, your homeserver would continue operating and federating with thousands of others.
    • End-to-end encryption by default. All direct messages and private rooms are E2EE with the Olm/Megolm double ratchet. Your server stores ciphertext; not even you as the admin can read user messages. Contrast this with Slack, where workspace admins can export everything in plaintext.
    • You own the data. Full SQL access to every message, every media file, every reaction. Export, back up, or migrate on your terms — no "Enterprise plan" upsell to access your own history.
    • Federation, not islands. A @alice:yourcompany.com user can DM @bob:mozilla.org without either of them creating an account on the other's server. It works exactly like email, and it is the feature that kills the network-effect moat of Discord and Slack.
    • Bridges to everything else. Matrix has mature bridges to Discord, Slack, Telegram, WhatsApp, Signal, IRC, XMPP, SMS, and more. You can run Matrix as the single pane of glass for every chat network your team is already in, and migrate gradually.
    • Voice, video, and VoIP. Element supports 1:1 and group audio/video calls, screen sharing, and (with Element Call / LiveKit) scalable group video for dozens of participants — all self-hosted, no Zoom or Google Meet account required.
    • Flat cost. A 12 GB VPS costs the same whether 5 or 500 people chat on it. Slack charges per seat, per month, forever.
    • Regulatory and sovereignty-friendly. GDPR, HIPAA, and government data-residency requirements are trivially satisfied when the server is in a datacenter you chose, running software you can audit.
    If chat is critical infrastructure for your team, outsourcing it to a single company that can pull the plug, raise prices, or suffer an outage is a strategic risk. Matrix removes that risk.

    If federation turns out to be more than you need, take a look at our guides on installing Mattermost on Ubuntu 24.04 (Slack-style closed team chat) and installing Rocket.Chat on Ubuntu 24.04 (omnichannel customer support focus) — both are excellent alternatives for teams that do not need cross-organization federation.

    Architecture Overview

    A typical production Matrix deployment on a single VPS looks like this:

    text
    ┌──────────────────────────────────┐
      user @alice:example.com           │  VPS (Ubuntu 24.04)              │
        │                               │                                  │
        │  https://element.example.com  │   Nginx ──► Element (static)     │
        ├──────────────────────────────►│                                  │
        │                               │   Nginx ──► Synapse :8008        │
        │  https://matrix.example.com   │             (client + federation)│
        ├──────────────────────────────►│                 │                │
        │                               │                 ▼                │
        │  https://example.com/.well-   │            PostgreSQL 16         │
        │        known/matrix/{server,  │                                  │
        │        client}                │   Bridges (systemd):             │
        ├──────────────────────────────►│   - mautrix-telegram             │
                                        │   - mautrix-discord              │
      federating homeserver (e.g.       │   - heisenbridge (IRC)           │
      matrix.org) hits                  └──────────────────────────────────┘
      https://matrix.example.com:443
      after resolving .well-known/matrix/server

    Three DNS names, one VPS:

    • example.com — your apex domain, serves two tiny .well-known JSON files. This is what appears in user IDs (@alice:example.com).
    • matrix.example.com — the Synapse homeserver. Client API (/_matrix/client) and federation API (/_matrix/federation) both live here on 443.
    • element.example.com — the Element web client (static HTML/JS files served by Nginx).
    Keeping Synapse on its own subdomain means example.com stays free for your marketing site, and you can redeploy Element independently.

    Prerequisites

    Before you begin, make sure you have:

    • A VPS running Ubuntu 24.04 LTS with root or sudo access
    • A domain name you control, with the ability to create A / AAAA records
    • Ports 80, 443, and 8448 open in your firewall and provider console (8448 is only required if you do not use .well-known delegation; we will use .well-known in this guide, so 443 is enough for federation)
    • At least 4 GB of RAM for a small server; 12 GB recommended for any real federated use
    • At least 40 GB of disk space, 100 GB recommended (federated rooms accumulate media fast)
    Recommended Plan: Professional
    >
    For 50-200 active Matrix users with federation to major homeservers and a couple of bridges, we recommend the Professional VPS plan:
    >
    - 6 vCPU cores
    - 12 GB RAM
    - 100 GB NVMe SSD
    - Unmetered bandwidth, 1 Gbps port
    >
    Synapse is memory-hungry once it joins popular federated rooms — plan RAM first, CPU second.

    Connect to your server:

    bash
    ssh root@your-server-ip

    Step 1: Prepare DNS and the Server

    In your DNS provider (Cloudflare, Route 53, etc.), create these records — replace example.com with your domain and 203.0.113.10 with your server's IP:

    TypeNameValue
    Aexample.com203.0.113.10
    Amatrix.example.com203.0.113.10
    Aelement.example.com203.0.113.10
    If you use Cloudflare, set the matrix subdomain to DNS-only (grey cloud). Cloudflare's proxy does not pass through the non-HTTP Matrix federation paths reliably, and it interferes with Let's Encrypt's HTTP-01 challenge in default configurations.

    Update the system and open the firewall:

    bash
    sudo apt update && sudo apt upgrade -y
    sudo apt install -y curl wget gnupg lsb-release ca-certificates ufw
    bash
    sudo ufw allow OpenSSH
    sudo ufw allow 80/tcp
    sudo ufw allow 443/tcp
    sudo ufw --force enable

    Step 2: Install PostgreSQL 16

    Synapse supports SQLite for tiny deployments, but PostgreSQL is mandatory for anything touching federation. SQLite will collapse under load the first time you join a busy room.

    bash
    sudo apt install -y postgresql postgresql-contrib
    sudo systemctl enable --now postgresql

    Verify it is running:

    bash
    sudo systemctl status postgresql

    Create the Synapse database and user. The LC_COLLATE and LC_CTYPE must be set to C — Synapse rejects any other collation on startup.

    bash
    sudo -u postgres psql <<'EOF'
    CREATE USER synapse_user WITH PASSWORD 'change-this-strong-password';
    CREATE DATABASE synapse
      ENCODING 'UTF8'
      LC_COLLATE='C'
      LC_CTYPE='C'
      TEMPLATE=template0
      OWNER synapse_user;
    EOF

    Expected output:

    text
    CREATE ROLE
    CREATE DATABASE

    Edit /etc/postgresql/16/main/pg_hba.conf and ensure there is a line for local password auth for the synapse database:

    text
    local   synapse   synapse_user                                md5
    host    synapse   synapse_user   127.0.0.1/32                 md5

    Reload PostgreSQL:

    bash
    sudo systemctl reload postgresql

    Step 3: Install Synapse from the Matrix.org Debian Repo

    The Matrix.org team maintains an official Debian repository with up-to-date matrix-synapse-py3 packages for Ubuntu 24.04. This is the recommended install path — do not use pip or the old Ubuntu universe package.

    bash
    sudo wget -O /usr/share/keyrings/matrix-org-archive-keyring.gpg \
      https://packages.matrix.org/debian/matrix-org-archive-keyring.gpg

    echo "deb [signed-by=/usr/share/keyrings/matrix-org-archive-keyring.gpg] https://packages.matrix.org/debian/ $(lsb_release -cs) main" \ | sudo tee /etc/apt/sources.list.d/matrix-org.list

    sudo apt update sudo apt install -y matrix-synapse-py3

    During install, dpkg will prompt for a server name. Enter your apex domain (e.g. example.com) — NOT matrix.example.com. The server name becomes the domain part of every user ID (@alice:example.com) and cannot be changed later without rebuilding the server.

    If you missed the prompt, re-run:

    bash
    sudo dpkg-reconfigure matrix-synapse-py3

    Confirm the service installed and started:

    bash
    sudo systemctl status matrix-synapse

    Synapse listens on 127.0.0.1:8008 by default.

    Step 4: Configure homeserver.yaml

    The main config lives at /etc/matrix-synapse/homeserver.yaml. Open it:

    bash
    sudo nano /etc/matrix-synapse/homeserver.yaml

    Make these changes:

    Server name (should already be set from the install prompt):

    yaml
    server_name: "example.com"
    public_baseurl: "https://matrix.example.com/"

    Switch the database from SQLite to PostgreSQL. Find the database: block and replace it with:

    yaml
    database:
      name: psycopg2
      args:
        user: synapse_user
        password: change-this-strong-password
        database: synapse
        host: 127.0.0.1
        cp_min: 5
        cp_max: 10

    Registration settings. Keep open signups disabled and generate a shared secret you will use to create admin users from the command line:

    yaml
    enable_registration: false
    registration_shared_secret: "PASTE-64-HEX-CHARS-HERE"

    Generate the secret with:

    bash
    openssl rand -hex 32

    Paste the resulting 64-character string into the YAML.

    Media and upload limits:

    yaml
    max_upload_size: 50M
    media_store_path: "/var/lib/matrix-synapse/media"
    url_preview_enabled: true
    url_preview_ip_range_blacklist:
      - '127.0.0.0/8'
      - '10.0.0.0/8'
      - '172.16.0.0/12'
      - '192.168.0.0/16'
      - '100.64.0.0/10'
      - '169.254.0.0/16'

    Federation — leave the defaults (federation is enabled). If you want a closed server, add:

    yaml
    federation_domain_whitelist: []

    Save and exit. Restart Synapse and inspect the logs:

    bash
    sudo systemctl restart matrix-synapse
    sudo journalctl -u matrix-synapse -n 50 --no-pager

    You should see Synapse now listening on TCP port 8008 with no Python tracebacks.

    Step 5: Register the First Admin User

    Open registration is disabled, but with the registration_shared_secret you can create users (including admins) from the CLI.

    bash
    register_new_matrix_user -c /etc/matrix-synapse/homeserver.yaml http://localhost:8008

    Example session:

    text
    New user localpart [root]: alice
    Password:
    Confirm password:
    Make admin [no]: yes
    Sending registration request...
    Success.

    The user ID will be @alice:example.com once .well-known delegation is in place (Step 7). Before that, it is @alice:<whatever-server_name-is>.

    Step 6: Nginx Reverse Proxy and TLS

    Install Nginx and Certbot:

    bash
    sudo apt install -y nginx certbot python3-certbot-nginx

    Vhost for the Matrix server (matrix.example.com)

    bash
    sudo tee /etc/nginx/sites-available/matrix > /dev/null <<'EOF'
    server {
        listen 80;
        listen [::]:80;
        server_name matrix.example.com;
        return 301 https://$host$request_uri;
    }

    server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name matrix.example.com;

    ssl_certificate /etc/letsencrypt/live/matrix.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/matrix.example.com/privkey.pem;

    # Federation uploads can be large client_max_body_size 50M;

    # Matrix client + federation API location ~ ^(/_matrix|/_synapse/client) { proxy_pass http://127.0.0.1:8008; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Host $host; proxy_http_version 1.1; proxy_read_timeout 600s; }

    location / { return 404; } } EOF

    Vhost for the Element web client (element.example.com)

    bash
    sudo tee /etc/nginx/sites-available/element > /dev/null <<'EOF'
    server {
        listen 80;
        listen [::]:80;
        server_name element.example.com;
        return 301 https://$host$request_uri;
    }

    server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name element.example.com;

    ssl_certificate /etc/letsencrypt/live/element.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/element.example.com/privkey.pem;

    root /var/www/element; index index.html;

    # Long cache for versioned assets, no cache for config location ~* \.(js|css|woff2|png|svg|jpg)$ { expires 1y; add_header Cache-Control "public, immutable"; }

    location = /config.json { add_header Cache-Control "no-store"; }

    location / { try_files $uri $uri/ /index.html; } } EOF

    Vhost for the apex domain (serves .well-known)

    bash
    sudo tee /etc/nginx/sites-available/apex > /dev/null <<'EOF'
    server {
        listen 80;
        listen [::]:80;
        server_name example.com;
        return 301 https://$host$request_uri;
    }

    server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    root /var/www/apex;

    location /.well-known/matrix/ { default_type application/json; add_header Access-Control-Allow-Origin *; }

    location / { try_files $uri $uri/ =404; } } EOF

    Enable the sites and issue certificates:

    bash
    sudo ln -sf /etc/nginx/sites-available/matrix /etc/nginx/sites-enabled/
    sudo ln -sf /etc/nginx/sites-available/element /etc/nginx/sites-enabled/
    sudo ln -sf /etc/nginx/sites-available/apex /etc/nginx/sites-enabled/
    sudo mkdir -p /var/www/apex /var/www/element
    sudo rm -f /etc/nginx/sites-enabled/default

    sudo certbot certonly --nginx -d example.com -d matrix.example.com -d element.example.com \ --non-interactive --agree-tos --email [email protected]

    sudo nginx -t && sudo systemctl reload nginx

    Certbot installs a daily systemd timer that auto-renews.

    Step 7: Publish .well-known Delegation Files

    Without delegation, other Matrix servers try to federate with you on port 8448 of your apex domain — which would require running Synapse there and breaks your marketing site. The .well-known mechanism lets you tell the world "reach example.com user accounts via matrix.example.com:443."

    Server delegation (for other homeservers):

    bash
    sudo mkdir -p /var/www/apex/.well-known/matrix
    sudo tee /var/www/apex/.well-known/matrix/server > /dev/null <<'EOF'
    {"m.server": "matrix.example.com:443"}
    EOF

    Client discovery (so Element auto-detects the homeserver when a user logs in with @alice:example.com):

    bash
    sudo tee /var/www/apex/.well-known/matrix/client > /dev/null <<'EOF'
    {
      "m.homeserver": {"base_url": "https://matrix.example.com"},
      "m.identity_server": {"base_url": "https://vector.im"}
    }
    EOF

    Test both:

    bash
    curl https://example.com/.well-known/matrix/server
    curl https://example.com/.well-known/matrix/client

    Both must return valid JSON with Content-Type: application/json and CORS headers.

    Step 8: Deploy the Element Web Client

    Element is a static single-page application. Download the latest release tarball from GitHub and serve it with Nginx.

    bash
    ELEMENT_VERSION=$(curl -s https://api.github.com/repos/element-hq/element-web/releases/latest | grep tag_name | cut -d '"' -f 4)
    cd /tmp
    wget "https://github.com/element-hq/element-web/releases/download/${ELEMENT_VERSION}/element-${ELEMENT_VERSION}.tar.gz"
    tar -xzf "element-${ELEMENT_VERSION}.tar.gz"
    sudo rm -rf /var/www/element/*
    sudo cp -r element-/ /var/www/element/
    sudo chown -R www-data:www-data /var/www/element

    Create /var/www/element/config.json to pin it to your homeserver:

    bash
    sudo tee /var/www/element/config.json > /dev/null <<'EOF'
    {
      "default_server_config": {
        "m.homeserver": {
          "base_url": "https://matrix.example.com",
          "server_name": "example.com"
        },
        "m.identity_server": {
          "base_url": "https://vector.im"
        }
      },
      "brand": "Example Chat",
      "default_country_code": "US",
      "disable_custom_urls": true,
      "disable_guests": true,
      "integrations_ui_url": "https://scalar.vector.im/",
      "integrations_rest_url": "https://scalar.vector.im/api",
      "features": {
        "feature_pinning": true,
        "feature_custom_status": true
      },
      "showLabsSettings": false,
      "room_directory": {
        "servers": ["example.com", "matrix.org"]
      }
    }
    EOF

    Setting disable_custom_urls: true locks users into your homeserver — they cannot accidentally log into matrix.org through your Element install.

    Reload Nginx:

    bash
    sudo systemctl reload nginx

    Visit https://element.example.com in a browser. You should see the Element login screen branded for your server. Log in with the admin account you created in Step 5.

    Step 9: Verify Federation

    Point a browser at the official Matrix Federation Tester and enter example.com. Every check should pass:

    • WellKnown — valid JSON at /.well-known/matrix/server
    • DNS — A record for matrix.example.com resolves
    • ConnectionReports — TLS handshake, certificate chain, version negotiation all green
    From the command line you can fetch Synapse's own self-report:

    bash
    curl https://matrix.example.com/_matrix/federation/v1/version

    Expected:

    json
    {"server":{"name":"Synapse","version":"1.115.0"}}

    Now test an actual federation round-trip. From Element, click "Explore rooms," switch the directory to matrix.org, and join #matrix:matrix.org. Messages should appear within a few seconds. If you see the spinner forever, skip to Troubleshooting.

    Step 10: Install Appservice Bridges

    Bridges are separate processes that connect Matrix to another network via Synapse's appservice API. Each one registers an application_service.yaml file that Synapse loads on startup.

    Telegram Bridge (mautrix-telegram)

    Mautrix-telegram is the most polished Telegram bridge and supports puppeting (your Matrix messages appear from your real Telegram account).

    bash
    sudo useradd -r -s /bin/false -d /opt/mautrix-telegram mautrix-telegram
    sudo mkdir -p /opt/mautrix-telegram
    sudo chown mautrix-telegram:mautrix-telegram /opt/mautrix-telegram
    sudo -u mautrix-telegram python3 -m venv /opt/mautrix-telegram/venv
    sudo -u mautrix-telegram /opt/mautrix-telegram/venv/bin/pip install mautrix-telegram[all]
    sudo -u mautrix-telegram /opt/mautrix-telegram/venv/bin/python -m mautrix_telegram -g -c /opt/mautrix-telegram/config.yaml

    Edit /opt/mautrix-telegram/config.yaml:

    • Set homeserver.address: https://matrix.example.com and domain: example.com
    • Get an API ID + hash from my.telegram.org/apps and paste into the telegram: section
    • Set bridge.permissions with your Matrix user ID as admin
    Generate the registration file and hand it to Synapse:

    bash
    sudo -u mautrix-telegram /opt/mautrix-telegram/venv/bin/python -m mautrix_telegram \
      -g -c /opt/mautrix-telegram/config.yaml -r /opt/mautrix-telegram/registration.yaml
    sudo cp /opt/mautrix-telegram/registration.yaml /etc/matrix-synapse/mautrix-telegram.yaml

    Add to /etc/matrix-synapse/homeserver.yaml:

    yaml
    app_service_config_files:
      - /etc/matrix-synapse/mautrix-telegram.yaml

    Create a systemd unit for the bridge and restart Synapse:

    bash
    sudo tee /etc/systemd/system/mautrix-telegram.service > /dev/null <<'EOF'
    [Unit]
    Description=mautrix-telegram bridge
    After=matrix-synapse.service

    [Service] Type=simple User=mautrix-telegram WorkingDirectory=/opt/mautrix-telegram ExecStart=/opt/mautrix-telegram/venv/bin/python -m mautrix_telegram -c /opt/mautrix-telegram/config.yaml Restart=on-failure

    [Install] WantedBy=multi-user.target EOF

    sudo systemctl daemon-reload sudo systemctl enable --now mautrix-telegram sudo systemctl restart matrix-synapse

    Start a DM with @telegrambot:example.com in Element and follow the login instructions to link your Telegram account.

    Discord Bridge (mautrix-discord)

    Follow the same pattern — install mautrix-discord into its own directory, generate registration, add to app_service_config_files, restart Synapse. Full instructions live at docs.mau.fi/bridges/go/discord/setup.html. Mautrix-discord supports portal rooms (a whole Discord server mirrored into Matrix), DMs, threads, reactions, stickers, and voice channel presence.

    IRC Bridge (Heisenbridge)

    Heisenbridge is a single-file "bouncer style" IRC bridge — each Matrix user connects to IRC with their own credentials. It is far simpler to deploy than the legacy matrix-appservice-irc for personal or small-team use.

    bash
    sudo pip3 install heisenbridge --break-system-packages
    heisenbridge -c /etc/matrix-synapse/heisenbridge.yaml --generate

    Add to app_service_config_files, create a systemd unit analogous to the Telegram one, and restart Synapse. Then invite @heisenbridge:example.com to a new DM for the setup wizard — you can connect to Libera.Chat, OFTC, and any other IRC network from there.

    Hardening and Maintenance

    Automatic media retention. Federated media piles up fast. Add to homeserver.yaml:

    yaml
    retention:
      enabled: true
      default_policy:
        min_lifetime: 1d
        max_lifetime: 365d

    PostgreSQL backups. Nightly dump via cron:

    bash
    0 3   * postgres pg_dump synapse | gzip > /var/backups/synapse-$(date +\%F).sql.gz

    Keep Synapse updated. sudo apt upgrade pulls the latest release. Subscribe to the Matrix security disclosure list — Synapse issues CVEs several times a year.

    Monitor with Prometheus. Synapse exposes /metrics on port 9000 when you set enable_metrics: true. Point a Prometheus + Grafana stack at it for room counts, federation lag, and memory usage.

    Troubleshooting

    ProblemCauseSolution
    Federation tester fails with "no route to homeserver".well-known/matrix/server missing, wrong Content-Type, or Cloudflare proxy rewriting responsecurl -I https://example.com/.well-known/matrix/server — must be 200, application/json, CORS . Turn off Cloudflare proxy for the apex.
    Synapse eats 8+ GB RAM and OOMsJoined #matrix:matrix.org or another huge roomLeave massive rooms, add swap, set caches: global_factor: 0.5 in homeserver.yaml, or upgrade RAM.
    register_new_matrix_user fails with 403registration_shared_secret unset or mismatchedRegenerate with openssl rand -hex 32, paste into homeserver.yaml, restart Synapse.
    Element shows "Can't connect to homeserver"CORS on .well-known/matrix/client missing or wrong base_urlVerify response includes Access-Control-Allow-Origin: and "base_url": "https://matrix.example.com" with no trailing slash.
    Bridges send messages but Matrix users can't replyAppservice sender_localpart collides with an existing user, or registration file not in app_service_config_filesCheck journalctl -u matrix-synapse for appservice load errors on startup.
    TLS chain incomplete (federation only)Nginx configured with cert.pem instead of fullchain.pemPoint ssl_certificate at fullchain.pem — it contains the intermediate.
    Viewing logs:

    bash
    sudo journalctl -u matrix-synapse -f
    sudo tail -f /var/log/matrix-synapse/homeserver.log

    FAQ

    Do I have to federate, or can I run a closed Matrix server?

    Federation is optional. Set federation_domain_whitelist: [] in homeserver.yaml or block outbound 443 from the server — Synapse will only talk to its own users. You keep end-to-end encrypted chat, voice, video, and bridges to other networks, but your users cannot join rooms on matrix.org or DM external accounts. This is a legitimate deployment for regulated industries or internal-only corporate chat.

    How much RAM does Synapse actually need?

    A 5-person private server runs happily on 2 GB. The moment anyone joins #matrix:matrix.org, #rust-lang:matrix.org, or any other popular federated room, working memory jumps to 4-6 GB as Synapse caches thousands of member events. Plan for 8-12 GB for 50-200 active users, with PostgreSQL wanting another 2-4 GB on top. The Professional 6 vCPU / 12 GB plan is the practical minimum for a federated deployment; anything smaller will swap under real load.

    Why do I need two subdomains plus a .well-known file?

    The server_name in user IDs (@alice:example.com) is semantically separate from the HTTP endpoint where Synapse actually runs. Keeping Synapse on matrix.example.com frees port 443 on the apex for your website. The .well-known/matrix/server file tells federating servers "reach example.com users at matrix.example.com:443," and .well-known/matrix/client does the same for Element and mobile apps during login auto-discovery. Without these files, other homeservers would expect Synapse on example.com:8448, which would conflict with any normal web presence.

    Can I migrate from Discord or Slack?

    Yes. mautrix-discord and mautrix-slack puppet bridges mirror channels, DMs, threads, reactions, and file uploads bidirectionally. You can run Matrix alongside Discord/Slack while users migrate, then retire the old platform. Historical message import is a manual export/replay (the bridges ship scripts for it), but day-forward mirroring is out-of-the-box. Many open source projects have used this approach to move communities without losing anyone.

    Is Synapse the only Matrix homeserver?

    No. Dendrite (Go, from the core Matrix team) and Conduit (Rust, community) are lighter-weight alternatives. Synapse is the reference implementation with the most features, the best docs, and the biggest community — which is why this guide uses it and why it is right for production. Dendrite is a strong choice if you need a smaller memory footprint; Conduit is excellent for a 1-10 user personal server and can run in under 200 MB RAM.

    How do I enable end-to-end encryption?

    You do not — it is client-side and is on by default for new direct messages and private rooms in Element. Synapse stores and relays ciphertext; it never sees plaintext. What you should do is enable cross-signing and secure key backup in Element (Settings > Security & Privacy), which lets users recover their message history on new devices. Without key backup, a user who reinstalls Element loses access to all their encrypted messages — this is the single most common self-host support ticket.

    Should I allow open registration?

    Almost never. Public Matrix servers with open signup get overrun by spam bots that join federated rooms and cause your domain to get blocked across the network. Keep enable_registration: false and create accounts with register_new_matrix_user, or add registration tokens (registrations_require_token: true), or wire up SSO via Keycloak, Authentik, or GitHub OAuth for self-service signup with guardrails.

    Next Steps

    Now that your Matrix stack is running, here is where to go next:

    • Enable Element Call for group video. Element Call uses LiveKit for scalable SFU-based video conferencing — deploy the LiveKit server, wire it into homeserver.yaml, and replace Zoom for internal meetings.
    • Explore the other self-hosted chat options. If federation is more than you need, see our guides on installing Mattermost on Ubuntu 24.04 (Slack-style team chat, no federation) and installing Rocket.Chat on Ubuntu 24.04 (omnichannel customer support with WhatsApp/Facebook integration).
    • Add identity providers. Wire Synapse into Keycloak, Authentik, or your corporate SAML IdP so staff log in with SSO instead of managing a separate Matrix password.
    • Set up automatic purges. Configure retention in homeserver.yaml and run the admin API POST /_synapse/admin/v1/media/<server_name>/delete monthly to reclaim disk.
    • Read the official Synapse docs. The matrix-org.github.io/synapse site is the canonical reference for every config option, admin API, and upgrade path — bookmark it.

    Skip the Manual Install — Deploy Matrix on a Professional VPS
    >
    Run Synapse + Element for a 50-200 user team on our Professional plan — 6 vCPU, 12 GB RAM, 100 GB NVMe, unmetered 1 Gbps, at a flat monthly rate. Full root access, snapshots, and DDoS protection included.
    >
    Launch a Professional VPS and start self-hosting decentralized chat in under an hour.

    Was this article helpful?

    ← Back to Install GuidesBrowse all categories →

    Still have questions?

    Contact Support →Submit a Ticket