How to Install a Synapse Matrix Server on Your Synology NAS (Docker)

Introduction

If you want to host your own secure, decentralized chat server using the Matrix protocol, this guide will help you get started. We’ll walk through setting up a Synapse server on a Synology NAS using Docker or Container Manager (DSM 7.2+). This tutorial is written for technically interested beginners with some experience using terminals and configuring home networks.

Requirements

You’ll need a Synology NAS with an x86 CPU (Intel or AMD). ARM-based NAS models, often found in J-series devices, are not supported. Your system should be running DSM 7.2 or newer with Container Manager installed. Make sure you know how to forward ports on your router and access your NAS terminal. You’ll also need a (sub-)domain and access to your DNS settings for routing and SSL configuration.

Preparing the Installation

First, install Container Manager from the Synology Package Center. Open File Station and go to the docker folder. Inside this folder, create a new directory named synapse. Within the synapse directory, create two subfolders: data and db. These folders will be used for volume mounting during container creation.

Server Name and Delegation

Before proceeding to generate the Synapse configuration files, it’s crucial to understand the concept of delegation in Matrix and how it affects the server name you choose. This decision cannot be easily changed later, so it’s important to get it right from the start.

In Matrix, the server name (also referred to as the server’s domain name) is a key identifier. It becomes part of your Matrix ID (e.g., @user:yourdomain.com) and is also used when other servers federate with yours. Therefore, selecting the appropriate domain name is essential.

By default, your Matrix server must be accessible directly via the domain you specify as the server name — specifically over port 8448. This is the default port the Matrix federation protocol uses for communication between servers. But depending on your setup (especially when using Docker, reverse proxies, or non-root domains), this might not be ideal.

What is Delegation?

Delegation allows you to separate your public Matrix domain from the actual server hosting Synapse. It works by placing a small .well-known file at https://example.com/.well-known/matrix/server, which tells the rest of the Matrix network where your Synapse server is really hosted.

Example .well-known/matrix/server:

{
  "m.server": "matrix.example.com:443"
}

With this setup, other servers will federate with matrix.example.com (on port 443), but your users will still appear as @user:example.com.

This is useful if you:

  • Want clean Matrix IDs based on your main domain.
  • Can’t or don’t want to expose Synapse directly on port 8448.
  • Run multiple services and want to keep Matrix on a subdomain.

Why Delegation Matters Now

Deciding whether or not to use delegation impacts what you enter as your server name in the Synapse configuration. If you plan to use delegation and set up a .well-known file, you can safely use your root or top level domain (e.g., example.com) as the server name, even if your actual Synapse instance is running on a subdomain (e.g., matrix.example.com).

Note: To setup a .well-known file you must be able to access the respective webserver of your top level domain service (e.g. webserver of example.com)

However, if you’re not planning to use delegation, the server name must exactly match the hostname where Synapse will be accessible on port 8448 over the internet.

Note: If you can only expose port 443 there are some tricks to be able to enable federation nevertheless. However I will not go into the details how to setup these kind of deployments to avoid confusing people.

Anyways make sure to decide this now, before moving on to generate the Synapse config files, as the server name you set during configuration will become a permanent and public part of your server’s identity in the Matrix network.

Generating the Configuration File

We’ll now generate the initial Synapse configuration using Docker. Open the Control Panel, go to Task Scheduler, and create a new user-defined script running as root. Use the following script (update UID, GID, paths, and domain as needed):

#!/bin/bash
docker run --rm \
--user 1026:100 \
-v /volume1/docker/synapse/data:/data \
-e SYNAPSE_CONFIG_PATH=/data/homeserver.yaml \
-e SYNAPSE_SERVER_NAME=yourdomain.com \
-e SYNAPSE_REPORT_STATS=yes \
matrixdotorg/synapse:latest generate

Save and run the script once. It will generate the homeserver.yaml configuration file inside /volume1/docker/synapse/data.

Editing the Configuration File

Navigate to /volume1/docker/synapse/data and open homeserver.yaml in a text editor. Add the following lines under your server name:

enable_registration: true
enable_registration_without_verification: true
enable_group_creation: true

Now remove the default SQLite database configuration within the homeserver.yaml:

database:
  name: sqlite3
  args:
    database: /data/homeserver.db

Replace it with a PostgreSQL configuration:

database:
  name: psycopg2
  args:
    user: synapseuser
    password: synapsepass
    database: synapsedb
    host: synapse-db
    cp_min: 5
    cp_max: 10

Modify user, password, and database according to your preferences. Save the file.

Creating the Docker Compose File

Open Container Manager, go to Projects, and create a new project. Set the project name (for example: matrix) and select the synapse directory as the project path. Choose to create the docker-compose.yml manually, then enter the following configuration:

version: "3.9"
services:

  synapse-db:
    image: postgres:17.4
    container_name: Synapse-DB
    hostname: synapse-db
    security_opt:
      - no-new-privileges:true
    healthcheck:
      test: ["CMD", "pg_isready", "-q", "-d", "synapsedb", "-U", "synapseuser"]
      timeout: 45s
      interval: 10s
      retries: 10
    user: 1026:100
    volumes:
      - /volume1/docker/synapse/db:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=synapsedb
      - POSTGRES_USER=synapseuser
      - POSTGRES_PASSWORD=synapsepass
      - POSTGRES_INITDB_ARGS=--encoding=UTF-8 --lc-collate=C --lc-ctype=C
    restart: always

  synapse:
    image: matrixdotorg/synapse:latest
    container_name: Synapse
    hostname: synapse
    security_opt:
      - no-new-privileges:true
    user: 1026:100
    environment:
      - TZ=Europe/Berlin
      - SYNAPSE_CONFIG_PATH=/data/homeserver.yaml
    volumes:
      - /volume1/docker/synapse/data:/data
    ports:
      - 8008:8008
    restart: always
    depends_on:
      synapse-db:
        condition: service_started

Adjust the values for volume paths, user ID, and database credentials to match your setup. Then start the project.

After starting, you should see two running containers in Container Manager: Synapse and Synapse-DB.

Setting Up Domain and Reverse Proxy

To make your Matrix server accessible from the internet, you need to set up a (sub-)domain and a reverse proxy.

First, configure your DNS provider to point your domain or subdomain to your NAS IP address. If you have a dynamic IP, use Dynamic DNS or set a CNAME record pointing to an existing DDNS entry.

Open Synology Control Panel and go to Login Portal. Under the Advanced tab, open the Reverse Proxy settings and create a new entry.

Under the General tab:

Source:
Protocol: HTTPS
Hostname: your.sub.domain
Port: 443

Enable HSTS.

Destination:
Protocol: HTTP
Hostname: localhost
Port: 8008

Switch to the Custom Header tab and add the following:

Header name: Upgrade
Value: $http_upgrade

Header name: Connection
Value: $connection_upgrade

Save the entry.

Now go to Control Panel > Security > Certificate. Create a new Let’s Encrypt certificate for your subdomain. After creation, assign this certificate to your reverse proxy rule under the Settings tab.

Once everything is set up, test your domain in a browser. You should be forwarded to your Synapse server running on port 8008 and served over HTTPS with a valid SSL certificate.

Registering a New User

To add a new user to your Matrix server, open your terminal or SSH into your NAS and run the following:

cd /volume1/docker/synapse
docker-compose exec synapse register_new_matrix_user -c /data/homeserver.yaml http://localhost:8008

Allow the prompts to enter a username and password. Your Matrix ID will be in the format @username:yourdomain.com.

Optimizing Homeserver Configuration

After your homeserver.yaml file has been generated, there are a few key tweaks and optimizations you can make to improve your Synapse server’s performance, security, and user experience.

Here are some recommended adjustments:

Federation & Client Management

Federation is enabled by default, but you can fine-tune federation behavior and client access:

serve_server_wellknown: false # only relevant if you want to delegated federation traffic over port 443 insteadt of 8448
allow_profile_lookup_over_federation: true # Show profile information to other homeservsers
allow_device_name_lookup_over_federation: false # Show Device Usage to other homeservers
allow_public_rooms_over_federation: false # Show Room Directory to other homeservers
federation:
  client_timeout: 180s
  max_short_retry_delay: 7s
  max_long_retry_delay: 100s
  max_short_retries: 5
  max_long_retries: 20
  destination_min_retry_interval: 30s
  destination_retry_multiplier: 5
  destination_max_retry_interval: 12h

Element Call (Voice/Video)

To be able to use the new MatrixRTC backend:

experimental_features:
  msc3266_enabled: true
  msc4222_enabled: true
max_event_delay_duration: 24h
rc_message:
  per_second: 0.5
  burst_count: 30
rc_delayed_event_mgmt:
  per_second: 1
  burst_count: 20

Deletion Policy

Define a data retention policy to limit the size of your database and comply with privacy standards:

retention:
  enabled: true
  default_policy:
    min_lifetime: 1d
    max_lifetime: 728d
  allowed_lifetime_min: 1d
  allowed_lifetime_max: 728d
  purge_jobs:
    - interval: 1d

Files and Media Usage

Manage storage growth and behavior:

media_store_path: /data/media_store
max_upload_size: "200M"
max_image_pixels: "35M"
dynamic_thumbnails: false
enable_media_repo: true
media_retention:
    local_media_lifetime: 728d
    remote_media_lifetime: 90d

You can also run a media cleanup cronjob periodically.

Thumbnail Settings

thumbnail_sizes:
- width: 32
  height: 32
  method: crop
- width: 96
  height: 96
  method: crop
- width: 320
  height: 240
  method: scale
- width: 640
  height: 480
  method: scale
- width: 800
  height: 600
  method: scale

User Registration

Control who can register and how:

enable_registration: true
registration_requires_token: true # If true one has to enter a registration token (see value below) to succesfull register to the homeserver
token: <define> 
allow_guest_access: false
enable_registration_without_verification: true
registration_shared_secret: "<DEFINE>"
auto_join_rooms: # Define rooms a new user auto joins
 - "#Lobby:example.com"
registrations_require_3pid: # Requires E-Mail to register
 - email
enable_3pid_lookup: true # E-MAil confirmation required to register
bcrypt_rounds: 12

Caching

Reduce memory usage on low-resource devices like a Synology NAS:

event_cache_size: 20K
caches:
  global_factor: 1.0
  per_cache_factors:
    get_users_who_share_room_with_user: 2.0
  sync_response_cache_duration: 2m
  cache_autotuning:
    max_cache_memory_usage: 2048M
    target_cache_memory_usage: 1024M
    min_cache_ttl: 5m

Web Client Delegation

If you don’t host your own Element Web, delegate to a trusted public client. Otherwise define your Element Web client domain:

web_client_location: "https://app.element.io"

Email Configuration

Set up email to enable password resets and notifications:

email:
  smtp_host: mail.example.com
  smtp_port: 587
  smtp_user: youruser@example.com
  smtp_pass: yourpassword
  notif_from: "Matrix Server <noreply@example.com>"
  require_transport_security: true

Misc

The default homeserver.yaml is huge. Once you’ve set your desired options, it’s a good idea to comment out or remove unused keys to make your config easier to maintain. More information on the available config parameter and best practise settings can be found here.

Conclusion

You’ve now set up your own self-hosted Matrix Synapse server on a Synology NAS with Docker, PostgreSQL, SSL encryption, domain routing and an optimized homeserver config. You can now log in using any Matrix-compatible client like Element and start chatting securely.

Leave a Reply

Your email address will not be published. Required fields are marked *