Skip to content

Instantly share code, notes, and snippets.

@matusnovak
Last active January 20, 2026 11:56
Show Gist options
  • Select an option

  • Save matusnovak/37109e60abe79f4b59fc9fbda10896da to your computer and use it in GitHub Desktop.

Select an option

Save matusnovak/37109e60abe79f4b59fc9fbda10896da to your computer and use it in GitHub Desktop.

Revisions

  1. matusnovak revised this gist Apr 19, 2021. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -484,9 +484,9 @@ services:
    nginx:
    ...
    riot:
    image: "bubuntux/riot-web:latest"
    image: "vectorim/riot-web:latest"
    volumes:
    - "./data/matrix/riot/config.json:/etc/riot-web/config.json:ro"
    - "./data/matrix/riot/config.json:/app/config.json:ro"
    labels:
    - "traefik.enable=true"
    - "traefik.http.services.riot.loadbalancer.server.port=80"
  2. matusnovak revised this gist Mar 4, 2021. 1 changed file with 32 additions and 1 deletion.
    33 changes: 32 additions & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -68,7 +68,7 @@ certificatesResolvers:
    entryPoint: "web"
    ```
    The following additional Traefik config is useful for http to https automatic redirection.
    The following additional Traefik config is useful for http to https automatic redirection. This is purely optional, you don't need these two files.
    ```yml
    # data/traefik/config/routers.yml
    @@ -93,6 +93,37 @@ http:
    permanent: true
    ```
    One more thing, you will have to create an empty JSON file for the `acme.json`. This file will store Let's Encrypt certificates. Simply create a file `data/traefik/acme.json` with an empty JSON object such as the following:

    ```json
    {}
    ```

    Finally, the most importing part, you will have to use the following Docker compose config to run Traefik:

    ```yml
    services:
    traefik:
    image: "traefik:latest"
    restart: "unless-stopped"
    ports:
    - "80:80"
    - "443:443"
    volumes:
    - "/var/run/docker.sock:/var/run/docker.sock:ro"
    - "./data/traefik/traefik.yml:/etc/traefik/traefik.yml:ro"
    - "./data/traefik/config:/config:ro"
    - "./data/traefik/acme.json:/acme.json"
    # The following labels are optional. If you keep them, you will be able to
    # access Traefik dashboard via https://traefik.example.com/
    labels:
    - "traefik.enable=true"
    - "traefik.http.services.traefik.loadbalancer.server.port=8080"
    - "traefik.http.routers.traefik.rule=Host(`traefik.example.com`)"
    - "traefik.http.routers.traefik.entrypoints=web-secure"
    - "traefik.http.routers.traefik.tls.certresolver=letsencrypt"
    ```
    # 2. Postgres
    Make sure you have a postgres database with a login for the Synapse server.
  3. matusnovak revised this gist Feb 9, 2021. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -642,9 +642,9 @@ Next, deploy the Coturn server by running `docker-compose up -d`. You will also
    That is all, you should be now be able to make calls.
    _**Note:** I highly recommend testing this on two separate ISP networks! If your Coturn or the port-forwarding is misconfigured, you will very likely be able to make calls within your local network. The best way to test is that you create two accounts on your Matrix and call each other from different ISP networks. Perhaps try using your 4G connection on your phone with the Riot app?_
    _**Note:** I highly recommend testing this on two separate ISP networks! If your Coturn or the port-forwarding is misconfigured, you will very likely be able to make calls within your local network, and you will not realise that there is a problem. The best way to test is that you create two accounts on your Matrix and call each other from different ISP networks. Perhaps try using your 4G connection on your phone with the Riot app?_
    _**Note:** If you do not have a public IP and you are using some kind of VPN, then the `allow-loopback-peers` in Coturn config file is required! Also, the `external-ip=` becomes your local VPN IP address (the address of your tun0 interface) followed by `/` followed by the external VPN IP address that is accessible from the internet. Do not use your LAN IP address and do not use 127.0.0.1.
    _**Note:** If you do not have a public IP and you are using some kind of VPN, then the `allow-loopback-peers` in Coturn config file is required! Also, the `external-ip=` becomes your local VPN IP address (the address of your tun0 interface) followed by `/` followed by the external VPN IP address that is accessible from the internet. Do not use your LAN IP address and do not use 127.0.0.1._
    # The end
  4. matusnovak revised this gist Feb 9, 2021. 1 changed file with 94 additions and 0 deletions.
    94 changes: 94 additions & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -554,6 +554,98 @@ services:
    - "./data/ldap/config:/etc/ldap/slapd.d"
    ```

    # Optional Turn Server (video calls)

    You will need to do this if you want to enable VoIP. This guide will not explain what a Turn server is. First, create a `data/matrix/coturn/turnserver.conf` file with the following contents.

    ```
    use-auth-secret
    static-auth-secret=SomeSecretPasswordForMatrix
    realm=matrix.example.com
    listening-port=3478
    tls-listening-port=5349
    min-port=49160
    max-port=49200
    verbose
    allow-loopback-peers
    cli-password=SomePasswordForCLI
    external-ip=192.168.0.2/123.123.123.123
    ```
    You will have to replace the `SomeSecretPasswordForMatrix` and `SomePasswordForCLI` with your own password. You can generate a random password by using the following command:
    ```
    openssl rand -hex 32
    ```
    **You will also have to modify your external-ip**! This is a two part value divided by a slash `/`. The left part is your local IP address allocated to your server. You can find it by executing `ip route get 1` (for example, `src 192.168.0.2 uid 1000`). The right part is your public IP address, you can find it here: https://whatismyipaddress.com/
    You will then have to edit your Matrix yml configuration, found in `data/matrix/synapse/homeserver.yaml` and add the following lines at the bottom:
    ```yml
    turn_uris:
    - "turn:matrix.example.com:3478?transport=udp"
    - "turn:matrix.example.com:3478?transport=tcp"
    - "turns:matrix.example.com:3478?transport=udp"
    - "turns:matrix.example.com:3478?transport=tcp"
    turn_shared_secret: "SomeSecretPasswordForMatrix"
    turn_user_lifetime: 86400000
    turn_allow_guests: True
    ```

    You will have to match the password you have set for `static-auth-secret`.

    _**Note:** Changing Synapse's homeserver.yml file requires a service restart. Do it via `docker restart example_matrix_synapse_1` command._

    Next, add the Coturn server into the `docker-compose.yml` file:

    ```yml
    # docker-compose.yml
    services:
    traefik:
    ...
    postgres:
    ...
    redis:
    ...
    synapse:
    ...
    nginx:
    ...
    riot:
    ...
    coturn:
    image: "instrumentisto/coturn:latest"
    restart: "unless-stopped"
    volumes:
    - "./data/matrix/coturn/turnserver.conf:/etc/coturn/turnserver.conf"
    ports:
    - "49160-49200:49160-49200/udp"
    - "3478:3478"
    - "5349:5349"
    ```
    Next, you will have to enable these ports in your firewall, if you are using one. In case of `ufw` on Ubuntu server, the following commands will be sufficient:

    ```
    sudo ufw allow from 0.0.0.0/0 to any port 5349
    sudo ufw allow from 0.0.0.0/0 to any port 3478
    sudo ufw allow from 0.0.0.0/0 to any port 49160:49200 proto udp
    ```
    Next, you will have to allow these ports (5349 udp+tcp, 3478 udp+tcp, and 49160-49200 udp) in your router and forward them to your server! This is specific to your router and I can not provide a guide for all of the routers that exists, you will have to find out on your own. You probably already did this for your HTTP+HTTPS anyway.
    If you are using EC2, all you have to do is to modify the security group of your EC2 instance that is running your Matrix, and allow traffic from anywhere to ports 5349/tcp, 5349/udp, 3478/tcp, 3478/udp, and 49160-49200/udp.
    Next, deploy the Coturn server by running `docker-compose up -d`. You will also have to restart your Synapse (because the config has changed) via `docker restart example_matrix_synapse_1`. You can find the name of your Synapse container by simply running `docker ps | grep synapse`.
    That is all, you should be now be able to make calls.
    _**Note:** I highly recommend testing this on two separate ISP networks! If your Coturn or the port-forwarding is misconfigured, you will very likely be able to make calls within your local network. The best way to test is that you create two accounts on your Matrix and call each other from different ISP networks. Perhaps try using your 4G connection on your phone with the Riot app?_
    _**Note:** If you do not have a public IP and you are using some kind of VPN, then the `allow-loopback-peers` in Coturn config file is required! Also, the `external-ip=` becomes your local VPN IP address (the address of your tun0 interface) followed by `/` followed by the external VPN IP address that is accessible from the internet. Do not use your LAN IP address and do not use 127.0.0.1.
    # The end
    In the end, your files should look like this:
    @@ -572,6 +664,8 @@ example/
    traefik.yml
    acme.json
    matrix/
    coturn/ (optional)
    turnserver.conf
    nginx/
    www/
    .well-known/
  5. matusnovak revised this gist Aug 7, 2020. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -483,7 +483,7 @@ If you get 401 unauthorized error in your logs (Synapse logs), check the SVR DNS
    Add the following **SVR** record to your DNS server:

    ```
    _matrix._tcp.matrix.synapse.example.com
    _matrix._tcp.matrix.example.com
    ```

    With value of:
  6. matusnovak revised this gist Aug 6, 2020. 1 changed file with 6 additions and 0 deletions.
    6 changes: 6 additions & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -482,6 +482,12 @@ If you get 401 unauthorized error in your logs (Synapse logs), check the SVR DNS

    Add the following **SVR** record to your DNS server:

    ```
    _matrix._tcp.matrix.synapse.example.com
    ```

    With value of:

    ```
    1 10 443 synapse.example.com
    ```
  7. matusnovak revised this gist Aug 6, 2020. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -285,7 +285,7 @@ The [federation documentation](https://github.com/matrix-org/synapse/blob/master

    Create the following files:

    The Nginx configuration file at `data/matrix/nginx/matrix.cong` relative to your `docker-compose.yml` with the following contents:
    The Nginx configuration file at `data/matrix/nginx/matrix.conf` relative to your `docker-compose.yml` with the following contents:

    ```
    server {
  8. matusnovak revised this gist Aug 6, 2020. 1 changed file with 9 additions and 0 deletions.
    9 changes: 9 additions & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -24,6 +24,15 @@ example/
    docker-compose.yml
    ```

    You can generate them via:

    ```
    mkdir -p data/postgres/data
    mkdir -p data/traefik
    mkdir -p data/matrix/{nginx,synapse,riot}
    touch docker-compose.yml
    ```

    # 1. Traefik

    Create your basic Traefik configuration. The following should work out of the box, if you change your email in the ACME section.
  9. matusnovak created this gist Aug 6, 2020.
    577 changes: 577 additions & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,577 @@
    # Matrix

    matrix.org chat is split into two parts, the server and the client. The server we are going to use is called [Synapse](https://github.com/matrix-org/synapse) and the client is [Riot.im](https://github.com/vector-im/element-web). The Synapse will also need Postgres database and Redis for caching.

    # 0. Folders

    Make sure your folder structure looks like this.

    ```
    example/
    data/
    postgres/
    data/
    (empty)
    traefik/
    (empty)
    matrix/
    nginx/
    (empty)
    synapse/
    (empty)
    riot/
    (empty)
    docker-compose.yml
    ```

    # 1. Traefik

    Create your basic Traefik configuration. The following should work out of the box, if you change your email in the ACME section.

    ```yml
    # data/traefik/traefik.yml
    entryPoints:
    web:
    address: ":80"
    web-secure:
    address: ":443"

    api:
    dashboard: true
    insecure: true

    providers:
    file:
    directory: "/config"
    watch: true
    docker:
    endpoint: "unix:///var/run/docker.sock"
    network: "example_default"
    watch: true
    exposedByDefault: false

    certificatesResolvers:
    letsencrypt:
    acme:
    email: "your_name@example.com"
    storage: "/acme.json"
    httpChallenge:
    entryPoint: "web"
    ```
    The following additional Traefik config is useful for http to https automatic redirection.
    ```yml
    # data/traefik/config/routers.yml
    http:
    routers:
    redirecttohttps:
    entryPoints:
    - "web"
    middlewares:
    - "httpsredirect"
    rule: "HostRegexp(`{host:.+}`)"
    service: "noop@internal"
    ```
    ```yml
    # data/traefik/config/middlewares.yml
    http:
    middlewares:
    httpsredirect:
    redirectScheme:
    scheme: https
    permanent: true
    ```
    # 2. Postgres
    Make sure you have a postgres database with a login for the Synapse server.
    The following is a sample docker-compose config for Postgres.
    ```yml
    # docker-compose.yml
    services:
    traefik:
    ...
    postgres:
    image: "postgres:9.6"
    restart: "unless-stopped"
    environment:
    POSTGRES_PASSWORD: "admin"
    volumes:
    - "./data/postgres/data:/var/lib/postgresql/data"
    ```
    The following code will create a database `synapse` with user `synapse` and password `password`. Make sure that your database has the correct encoding!

    ```sql
    CREATE ROLE synapse;
    ALTER ROLE synapse WITH PASSWORD 'password';
    ALTER ROLE synapse WITH LOGIN;
    CREATE DATABASE synapse ENCODING 'UTF8' LC_COLLATE='C' LC_CTYPE='C' template=template0 OWNER synapse;
    GRANT ALL PRIVILEGES ON DATABASE synapse TO synapse;
    ```

    # 3. Redis

    Make sure you have redis running. Example docker-compose configuration:

    ```yml
    # docker-compose.yml
    services:
    traefik:
    ...
    postgres:
    ...
    redis:
    image: "redis:latest"
    restart: "unless-stopped"
    ```

    # 4. Synapse

    **Note:** You will have **two sub-domains** for Synapse via Traefik. One `matrix.example.com` which will be handled by Nginx and a second one `synapse.example.com` which will point directly into your Synapse server. It will be explained in a later section below.

    First create a sample config. This will also create your signing key and bunch of other secrets.

    ```
    docker run -it --rm \
    -v $(pwd)/data/matrix/synapse:/data \
    -e SYNAPSE_SERVER_NAME=matrix.example.com \
    -e SYNAPSE_REPORT_STATS=yes \
    -e UID=1000 \
    -e GID=1000 \
    matrixdotorg/synapse:latest generate
    ```
    This will create the following files:
    ```
    example/
    data/
    ...
    matrix/
    nginx/
    (empty)
    synapse/
    homeserver.yaml
    matrix.example.com.log.config
    matrix.example.com.signing.key
    riot/
    (empty)
    ```
    Edit the `homeserver.yaml` so you end up with something like the config below. (notice the `enable_registration`!)
    ```yml
    # data/matrix/synapse/homeserver.yaml
    server_name: "matrix.example.com"
    pid_file: /data/homeserver.pid
    web_client_location: https://riot.example.com/
    public_baseurl: https://synapse.example.com/
    report_stats: true
    enable_registration: true
    listeners:
    - port: 8008
    tls: false
    type: http
    x_forwarded: true
    resources:
    - names: [client, federation]
    compress: false
    retention:
    enabled: true
    federation_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'
    - '::1/128'
    - 'fe80::/64'
    - 'fc00::/7'
    database:
    name: psycopg2
    args:
    user: synapse
    password: password
    database: synapse
    host: postgres
    cp_min: 5
    cp_max: 10
    log_config: "/data/matrix.example.com.log.config"
    media_store_path: "/data/media_store"
    registration_shared_secret: "abc"
    macaroon_secret_key: "abc"
    form_secret: "abc"
    signing_key_path: "/data/matrix.example.com.signing.key"
    trusted_key_servers:
    - server_name: "matrix.org"
    redis:
    enabled: true
    host: redis
    port: 6379
    ```

    Now add your docker-compose config for Synapse:

    ```yml
    # docker-compose.yml
    services:
    traefik:
    ...
    postgres:
    ...
    redis:
    ...
    synapse:
    image: "matrixdotorg/synapse:latest"
    restart: "unless-stopped"
    environment:
    SYNAPSE_CONFIG_DIR: "/data"
    SYNAPSE_CONFIG_PATH: "/data/homeserver.yaml"
    UID: "1000"
    GID: "1000"
    TZ: "Europe/London"
    volumes:
    - "./data/matrix/synapse:/data"
    labels:
    - "traefik.enable=true"
    - "traefik.http.services.synapse.loadbalancer.server.port=8008"
    - "traefik.http.routers.synapse.rule=Host(`synapse.example.com`)"
    - "traefik.http.routers.synapse.entrypoints=web-secure"
    - "traefik.http.routers.synapse.tls.certresolver=letsencrypt"
    ```
    Now when you go to <https://synapse.example.com/> you should be redirected to <https://synapse.example.com/_matrix/static/> and you should see `It works! Synapse is running`.

    # 5. Nginx

    So the Synapse server is running, but this is not everything you need for federation. You may have noticed that we have used two domains: `synapse.example.com` and `matrix.example.com`.

    The [federation documentation](https://github.com/matrix-org/synapse/blob/master/docs/federate.md) is bit configusing if you don't know enough about how Matrix works internally. Hopefully this example below will explain it.

    Create the following files:

    The Nginx configuration file at `data/matrix/nginx/matrix.cong` relative to your `docker-compose.yml` with the following contents:

    ```
    server {
    listen 80 default_server;
    server_name matrix.example.com;
    # Traefik -> nginx -> synapse
    location /_matrix {
    proxy_pass http://synapse:8008;
    proxy_set_header X-Forwarded-For $remote_addr;
    client_max_body_size 128m;
    }
    location /.well-known/matrix/ {
    root /var/www/;
    default_type application/json;
    add_header Access-Control-Allow-Origin *;
    }
    }
    ```

    The `data/matrix/nginx/www/.well-known/matrix/client` with the following contents:

    ```
    {
    "m.homeserver": {
    "base_url": "https://matrix.example.com"
    }
    }
    ```

    And the `data/matrix/nginx/www/.well-known/matrix/server` with the following contents:

    ```
    {
    "m.server": "synapse.example.com:443"
    }
    ```

    And the docker-compose config for Nginx:

    ```yml
    # docker-compose.yml
    services:
    traefik:
    ...
    postgres:
    ...
    redis:
    ...
    synapse:
    ...
    nginx:
    image: "nginx:latest"
    restart: "unless-stopped"
    volumes:
    - "./data/matrix/nginx/matrix.conf:/etc/nginx/conf.d/matrix.conf"
    - ./data/matrix/nginx/www:/var/www/
    labels:
    - "traefik.enable=true"
    - "traefik.http.services.matrix.loadbalancer.server.port=80"
    - "traefik.http.routers.matrix.rule=Host(`matrix.example.com`)"
    - "traefik.http.routers.matrix.entrypoints=web-secure"
    - "traefik.http.routers.matrix.tls.certresolver=letsencrypt"
    ```
    After you start the container, you should be able to access <https://matrix.example.com/.well-known/matrix/client> which gives you `"base_url": "https://matrix.example.com"`.

    And also you should be able to access <https://matrix.example.com/.well-known/matrix/server> which gives you `"m.server": "synapse.example.com:443"`.
    And also accessing <https://matrix.example.com/_matrix/static/> should show you the exact same page as shown at <https://synapse.example.com/_matrix/static/>.
    The Nginx simply acts as a proxy in this case, with two additional files.
    # 6. Federation tester
    Now, when you go to <https://federationtester.matrix.org/> and type in your domain name, in this case `matrix.example.com` (without https) you should get all green checks.

    # 7. Riot Web UI

    The last thing is to set up the Riot Web UI which will be used to send the messages.

    Create a new file at `data/matrix/riot/config.json` with the following contents:

    ```json
    {
    "default_server_config": {
    "m.homeserver": {
    "base_url": "https://matrix.example.com",
    "server_name": "matrix.example.com"
    },
    "m.identity_server": {
    "base_url": "https://vector.im"
    }
    },
    "disable_custom_urls": false,
    "disable_guests": false,
    "disable_login_language_selector": false,
    "disable_3pid_login": false,
    "brand": "Element",
    "integrations_ui_url": "https://scalar.vector.im/",
    "integrations_rest_url": "https://scalar.vector.im/api",
    "integrations_widgets_urls": [
    "https://scalar.vector.im/_matrix/integrations/v1",
    "https://scalar.vector.im/api",
    "https://scalar-staging.vector.im/_matrix/integrations/v1",
    "https://scalar-staging.vector.im/api",
    "https://scalar-staging.riot.im/scalar/api"
    ],
    "bug_report_endpoint_url": "https://riot.im/bugreports/submit",
    "defaultCountryCode": "GB",
    "showLabsSettings": false,
    "features": {
    "feature_new_spinner": "labs",
    "feature_pinning": "labs",
    "feature_custom_status": "labs",
    "feature_custom_tags": "labs",
    "feature_state_counters": "labs"
    },
    "default_federate": true,
    "default_theme": "light",
    "roomDirectory": {
    "servers": [
    "matrix.org"
    ]
    },
    "welcomeUserId": "@riot-bot:matrix.org",
    "piwik": {
    "url": "https://piwik.riot.im/",
    "whitelistedHSUrls": [
    "https://matrix.org"
    ],
    "whitelistedISUrls": [
    "https://vector.im",
    "https://matrix.org"
    ],
    "siteId": 1
    },
    "enable_presence_by_hs_url": {
    "https://matrix.org": false,
    "https://matrix-client.matrix.org": false
    },
    "settingDefaults": {
    "breadcrumbs": true
    },
    "jitsi": {
    "preferredDomain": "jitsi.riot.im"
    }
    }
    ```

    And add Riot to your docker-compose file:

    ```yml
    # docker-compose.yml
    services:
    traefik:
    ...
    postgres:
    ...
    redis:
    ...
    synapse:
    ...
    nginx:
    ...
    riot:
    image: "bubuntux/riot-web:latest"
    volumes:
    - "./data/matrix/riot/config.json:/etc/riot-web/config.json:ro"
    labels:
    - "traefik.enable=true"
    - "traefik.http.services.riot.loadbalancer.server.port=80"
    - "traefik.http.routers.riot.rule=Host(`riot.example.com`)"
    - "traefik.http.routers.riot.entrypoints=web-secure"
    - "traefik.http.routers.riot.tls.certresolver=letsencrypt"
    ```
    # 8. Logging in
    Go to <https://riot.example.com> and click register and select "Advanced" and enter the Homeserver URL as <https://matrix.example.com> (NOT <https://synapse.example.com>!).
    After creating an account, simply log in. That's it.
    # 9. Testing federation by joinin public room
    Navigate to <https://riot.example.com/#/room/#hello-matrix:matrix.org> This will join you to `#hello-matrix:matrix.org` room on <matrix.org>.

    If you get 401 unauthorized error in your logs (Synapse logs), check the SVR DNS record below.

    # 10. SVR DNS record

    **Note:** This may not be needed!

    Add the following **SVR** record to your DNS server:

    ```
    1 10 443 synapse.example.com
    ```

    After it is done, you should be able to test if it is correct via `dig` or similar CLI tool:

    ```
    dig -t SRV _matrix._tcp.matrix.example.com @8.8.8.8
    ```

    And should print the following:

    ```
    ;; ANSWER SECTION:
    _matrix._tcp.matrix.example.com. 299 IN SRV 1 10 443 synapse.example.com.
    ```

    # Optional OpenLDAP

    It is possible to integrate Synapse with OpenLDAP. In this case you don't need to create any user from the Riot Web UI. All authentication will be handled by OpenLDAP server.

    Add this into your `homeserver.yml` file:

    ```yml
    password_providers:
    - module: "ldap_auth_provider.LdapAuthProvider"
    config:
    enabled: true
    uri: "ldap://openldap:389"
    start_tls: false
    base: "ou=users,dc=example,dc=com"
    attributes:
    uid: "uid"
    mail: "email"
    name: "cn"
    bind_dn: cn=admin,dc=example,dc=com
    bind_password: password
    filter: "(memberOf=cn=matrix,ou=groups,dc=example,dc=com)"
    ```

    Assuming that:

    * Your OpenLDAP server can be accessed via Docker network at `openldap:389`.
    * You have domain of `dc=example,dc=com`.
    * You have admin (or any user for bind) `cn=admin,dc=example,dc=com`.
    * You have an organization unit of users at `ou=users,dc=example,dc=com`.
    * You have a `groupOfUniqueNames` as `cn=matrix,ou=example,dc=example,dc=com`.
    * Your users are added into the group `cn=matrix` so they have a property `memberOf`.

    I recommend using OpenLDAP as the following:

    ```yml
    services:
    openldap:
    image: "osixia/openldap:latest"
    restart: "unless-stopped"
    environment:
    LDAP_ORGANISATION: "Homelab"
    LDAP_DOMAIN: "dc=example,dc=com"
    LDAP_ADMIN_PASSWORD: "password"
    LDAP_REMOVE_CONFIG_AFTER_SETUP: "false"
    volumes:
    - "./data/ldap/data:/var/lib/ldap"
    - "./data/ldap/config:/etc/ldap/slapd.d"
    ```

    # The end

    In the end, your files should look like this:


    ```
    example/
    data/
    postgres/
    data/
    ... stuff ...
    traefik/
    config/
    middlewares.yml
    routers.yml
    traefik.yml
    acme.json
    matrix/
    nginx/
    www/
    .well-known/
    matrix/
    server
    client
    matrix.conf
    synapse/
    media_store/
    ... stuff ...
    homeserver.yml
    matrix.example.com.log.config
    matrix.example.com.signing.key
    riot/
    config.json
    docker-compose.yml
    ```