Skip to content

Instantly share code, notes, and snippets.

@tmo1
Last active August 30, 2023 21:30
Show Gist options
  • Save tmo1/52956fcc710a5789108005b01636e91d to your computer and use it in GitHub Desktop.
Save tmo1/52956fcc710a5789108005b01636e91d to your computer and use it in GitHub Desktop.
Synapse behind Caddy as a reverse proxy, using Docker

Introduction

This is a guide to deploying Synapse behind a Caddy reverse proxy, both running in Docker containers (an official Synapse one and a caddy-docker-proxy one), with the goal of implementing as much as possible via docker-compose files.

This guide will frequently refer to aspects of my similar guide for deploying Nextcloud behind a Caddy reverse proxy.

Domain Name

Obtain a domain name as per the instructions in the Nextcloud guide. For some Synapse specific considerations, see the official documentation here and here. The remainder of this guide will assume the use of the domain name example.duckdns.org.

SSL

See the SSL section in the Nextcloud guide.

Docker

See the Docker section in the Nextcloud guide.

Docker Network

See the Docker network section in the Nextcloud guide.

Synapse

Create the following file as something like $HOME/docker/synapse/docker-compose.yml. It is based on this community contributed docker-compose file, modified for Caddy integration:

# based on: https://github.com/matrix-org/synapse/blob/develop/contrib/docker/docker-compose.yml

version: '3'

services:

  synapse:
    build:
        context: ../..
        dockerfile: docker/Dockerfile
    image: docker.io/matrixdotorg/synapse:latest
    # Since synapse does not retry to connect to the database, restart upon
    # failure
    restart: unless-stopped
    # See the readme for a full documentation of the environment settings
    # NOTE: You must edit homeserver.yaml to use postgres, it defaults to sqlite
    environment:
      - SYNAPSE_SERVER_NAME=example.duckdns.org
      - SYNAPSE_REPORT_STATS=no
    volumes:
      - ./files:/data
    networks:
      - caddy
    depends_on:
      - db

    # https://github.com/matrix-org/synapse/blob/develop/docker/README.md#running-synapse
    # For testing, bring up the container with the following two lines
    # uncommented, and try to access http://<docker_host_hostname_or_ip>:8008
    #ports:
    # - 8008:8008

    # See https://matrix-org.github.io/synapse/latest/reverse_proxy.html
    # https://matrix-org.github.io/synapse/latest/reverse_proxy.html#caddy-v2
    # https://matrix-org.github.io/synapse/latest/delegate.html#well-known-delegation
    # Note: delegation would normally not be required in the simple configuration
    # used here, but since Duck DNS is being used for dynamic DNS service
    # with wildcards, federation with matrix.org won't work without explicit delegation
    # See: https://github.com/matrix-org/synapse/issues/5882
    # https://github.com/matrix-org/synapse/issues/7764
    # https://github.com/matrix-org/matrix-federation-tester/issues/92  
    labels:
      caddy: (matrix-well-known-header)
      caddy.header_0: Access-Control-Allow-Origin "*"
      caddy.header_1: Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
      caddy.header_2: Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept, Authorization"
      caddy.header_3: Content-Type "application/json"
      caddy_0: example.duckdns.org
      caddy_0.reverse_proxy_0: /_matrix/* {{upstreams 8008}}
      caddy_0.reverse_proxy_1: /_synapse/client/* {{upstreams 8008}}
      caddy_0.handle_0: /.well-known/matrix/server
      caddy_0.handle_0.import: matrix-well-known-header
      caddy_0.handle_0.respond: "`{\"m.server\":\"example.duckdns.org:443\"}`"
        #caddy_0.handle_1: /.well-known/matrix/client
        #caddy_0.handle_0.import: matrix-well-known-header
        #caddy_0.handle_0.respond: `{"m.homeserver":{"base_url":"https://matrix.example.com"},"m.identity_server":{"base_url":"https://identity.example.com"}}`
    # If delegation is not required, the 'labels' section can be simplified to
    # something like the following:
    # labels:
    #   caddy_0: example.duckdns.org
    #   caddy_0.reverse_proxy_0: /_matrix/* {{upstreams 8008}}
    #   caddy_0.reverse_proxy_1: /_synapse/client/* {{upstreams 8008}}
    #   caddy_1: example.duckdns.org:8448
    #   caddy_1.reverse_proxy: "{{upstreams 8008}}"
  db:
    image: docker.io/postgres:12-alpine
    environment:
      - POSTGRES_USER=synapse
      - POSTGRES_PASSWORD=<secret_password>
      # ensure the database gets created correctly
      # https://matrix-org.github.io/synapse/latest/postgres.html#set-up-database
      - POSTGRES_INITDB_ARGS=--encoding=UTF-8 --lc-collate=C --lc-ctype=C
    volumes:
      - ./schemas:/var/lib/postgresql/data
    networks:
      - caddy
      - external: true

Change the password to a strong random password. (It is only used internally, and will not be needed anywhere outside this file.)

Configuration

As per the contributed documentation, generate a configuration file with the command (specifying SYNAPSE_SERVER_NAME and SYNAPSE_REPORT_STATS are unnecessary, since they have already been specified in the docker-compose file):

docker-compose run --rm synapse generate

Then edit the generated configuration file (at $HOME/docker/synapse/files/homeserver.yaml), making sure it contains the following lines:

server_name: "example.duckdns.org"
listeners:
  - port: 8008
    tls: false
    type: http
    x_forwarded: true

    resources:
      - names: [client, federation]
        compress: false

Starting the Container

In $HOME/docker/synapse/, run:

# docker-compose up -d

Caddy

Set up Caddy as per the instructions in the Nextcloud guide. (If already done for the Nextcloud deployment, it does not need to be done again.)

To enable federation, Caddy should listen on port 8448 as well as port 443, so an appropriate entry should be added to the ports list in the Caddy docker-compose.yml file (if the Caddy container is already running, restart it after modifying the file):

ports:
    - 80:80
    - 443:443
    - 8448:8448

Testing

If everything has worked, it should be possible to access the Synapse instance from a web client, at the address https://example.duckdns.org (without port number specification), as described in the official documentation. It is also possible to accesss the Synapse instance via a web browser, either proxied via Caddy at https://example.duckdns.org, or directly, without going through Caddy, at http://<docker_host_hostname_or_ip>:8008, where <docker_host_hostname_or_ip> is a hostname or IP address of the Docker host system.

To test and troubleshoot federation, the Matrix Federation Tester is useful.

Generating Users

Follow the official documentation to manually generate users with this command:

docker exec -it <synapse_container_name> register_new_matrix_user http://localhost:8008 -c /data/homeserver.yaml [--help]

where <synapse_container_name> is the name of the running Synapse container (e.g. synapse_synapse_1).

(Running with the --help switch shows the command usage and options - omit it actually to generate users.) Both admin and ordinary users can be created this way. See also the matrix-registration tool.

Updating

See the Updating section of the Nextcloud guide.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment