Fediversity/matrix/synapse
2024-12-22 22:08:00 +01:00
..
conf.d Minor cleanup. 2024-12-04 09:37:01 +01:00
templates Added all configuration files, anonymized. 2024-12-02 15:40:44 +01:00
homeserver.yaml Added all configuration files, anonymized. 2024-12-02 15:40:44 +01:00
README.md Had to go in the workers.md file of course. 2024-12-21 15:46:14 +01:00
temp Had to go in the workers.md file of course. 2024-12-21 15:46:14 +01:00
workers.md Moved a few parts to different locations. 2024-12-22 22:08:00 +01:00

Table of Contents

Installation and configuration of Synapse

Mind you: this an installation on Debian Linux (at least for now).

Start by installing the latest Synapse server, see the upstream documentation.

apt install -y lsb-release wget apt-transport-https build-essential python3-dev libffi-dev \
               python3-pip python3-setuptools sqlite3 \
               libssl-dev virtualenv libjpeg-dev libxslt1-dev libicu-dev git python3-jinja2

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" |
    tee /etc/apt/sources.list.d/matrix-org.list

apt update
apt install matrix-synapse-py3

This leaves a very basic configuration in /etc/matrix-synapse/homeserver.yaml and two settings under /etc/conf.d. All other configuration items will also be configured with yaml-files in this directory.

Configure the domain you with to use in /etc/matrix-synapse/conf.d/server_name.yaml. What you configure here will also be the global part of your Matrix handles (the part after the colon). Also add the URL clients should connect to:

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

The public_baseurl will probably be different than the server_name, see also Delegation and DNS.

You now have a standard Matrix server that uses sqlite. You really don't want to use this in production, so probably want to replace this with PostgreSQL.

There are two different ways to configure Synapse, documented here:

We'll use Synapse, using the workers architecture to make it scalable, flexible and reusable.

Listeners

A fresh installation configures one listener, for both client and federation traffic. This listens on port 8008 on localhost (IPv4 and IPv6) and does not do TLS:

listeners:
  - port: 8008
    tls: false
    type: http
    x_forwarded: true
    bind_addresses: ['::1', '127.0.0.1']
    resources:
      - names: [client, federation]
        compress: false

Database

The default installation leaves you with an sqlite3 database. Nice for experimenting, but unsuitable for a production environment.

Here's how you setup PostgreSQL.

Once you've created a database and user in PostgreSQL, you configure Synapse to use it.

First delete (or comment out) the SQLITE datbase in homeserver.yaml:

#database:
#  name: sqlite3
#  args:
#    database: /var/lib/matrix-synapse/homeserver.db

Then create the database configuration for PostgreSQL in conf.d/database.yaml:

database:
  name: psycopg2
  args:
    user: synapse
    password: <password>
    dbname: synapse
    host: /var/run/postgresql
    cp_min: 5
    cp_max: 10

Note: you configure the directory where the UNIX socket file lives, not the actual file.

Of course, if you use localhost, you should configure it like this:

    host: localhost
    port: 5432

After changing the database, restart Synapse and check whether it can connect and create the tables it needs.

Create admin

Synapse doesn't create an admin account at install time, so you'll have to do that yourself.

You need to set a registration_shared_secret for this, set that in conf.d/keys.yaml like this:

registration_shared_secret: xxxx

You can create such a key by running pwgen -csn 52 1. Restart Synapse after setting this key.

Now create an admin user. Login and issue this command:

register_new_matrix_user -u admin -a -c /etc/matrix-synapse/conf.d/keys.yaml

This will ask for a password, choose a safe one.

Logging

Logging is configured in log.yaml. Some logging should go to systemd, the more specific logging to Synapse's own logfile(s).

This part is yet to be completed, the default configuration is adequate for most cases.

Delegation and DNS

If you run your server under a different FQDN than just the domain name you want to use, you need to delegate: point from your domain to the server.

Example. You want to use example.com for your domain, but your server is called matrix.example.com. To make that work, you need to serve 2 bits of JSON-code on example.com to point clients and servers to the correct machine: matrix.example.com.

Pointing servers to the correct server is done by publishing this bit of JSON-code under https://example.com/.well-known/matrix/server:

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

Pointing clients to the correct server needs this at https://example.com/.well-known/matrix/client:

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

Very important: both names (example.com and matrix.example.com) must be A and/or AAAA records in DNS, not CNAME.

See nginx for details about how to publish this data.

E-mail

Synapse should probably be able to send out e-mails; notifications for those who want that, and password reset for those who need one.

You configure this under the section email (yes, really).

First of all, you need an SMTP-server that is configured to send e-mail for your domain. Configuring that is out of scope, we'll assume we can use the server smtp.example.com.

Configure this in conf.d/email.yaml:

email:
  smtp_host: smtp.example.com
  smtp_port: 465
  smtp_user: matrix@example.com
  smtp_pass: SuperSecretPassword
  force_tls: true
  notif_from: "Your Matrix server <matrix@example.com>"

This configures an SMTP-connection with SSL (port 465, force_tls). See Matrix' email documentation for more information.

Media store

Files and avatars need to be stored somewhere, we configure these options in conf.d/mediastore.yaml:

media_store_path: /var/lib/matrix-synapse/media
enable_authenticated_media: true
max_upload_size: 50M
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'
  - '192.0.0.0/24'
  - '169.254.0.0/16'
  - '192.88.99.0/24'
  - '198.18.0.0/15'
  - '192.0.2.0/24'
  - '198.51.100.0/24'
  - '203.0.113.0/24'
  - '224.0.0.0/4'
  - '::1/128'
  - 'fe80::/10'
  - 'fc00::/7'
  - '2001:db8::/32'
  - 'ff00::/8'
  - 'fec0::/10'

These are a few sane (?) defaults, check Matrix' documentation for many more options.

Homeserver blocking

This is a series of options that can be used to block and/or limit users. The whole list of options can be found in Matrix' documentation, we're going to pick out a few useful ones.

Let's configure these options in conf.d/homeserver_blocking.yaml.

admin_contact: matrixadmin@example.com
mau_stats_only: true
max_avatar_size: 2M
allowed_avatar_mimetypes:
  - "image/png"
  - "image/jpeg"
  - "image/gif"
forgotten_room_retention_period: 7d

Authentication

Logging in can be done in basically two ways: an internal or external database. Let's start with the first: users and their passwords are stored in Synapse's database.

We use conf.d/authentication.yaml to configure this stuff.

password_config:
  policy:
    enabled: true
    localdb_enabled: true
    pepper: <random string>
    minimum_length: 8
    require_digit: true
    require_symbol: true
    require_lowercase: true
    require_uppercase: true

With this bit, we configure Synapse to let users pick and change their own passwords, as long as they meet the configured conditions. Mind you: pepper is a secret random string that should NEVER be changed after initial setup.

But in a bigger environment you'll probably want to use some authentication backend, such as LDAP. LDAP is configured by means of a module (see Synapse LDAP auth Provider on Github).

Configuring Synapse to use LDAP, would be something like this:

password_config:
  policy:
    enabled: only_for_reauth
    localdb_enabled: false

password_providers:
  - module: "ldap_auth_provider.LdapAuthProvider"
    config:
      enabled: true
      uri: "ldap://ldap.example.com:389"
      start_tls: true
      base: "ou=users,dc=example,dc=com"
      attributes:
         uid: "uid"
         mail: "mail"
         name: "cn"
      filter: "(&(objectClass=posixAccount)(accountStatus=active))"

      mode: "search"
      bind_dn: "cn=matrix,ou=service,dc=example,dc=com"
      bind_password: "<very secure password>"

This would connect to ldap.example.com over TLS, and authenticate users that live under ou=users,dc=example,dc=com and that are active Posix accounts. Users will not be able to change their passwords via Matrix, they have to do that in LDAP.

The bottom 3 lines enable search mode, necessary to find users' displayname and e-mail address. These values are in LDAP under the attributes "mail" and "cn" (completely dependent on your LDAP DIT of course, this setup is common for OpenLDAP). The bind_dn and bind_password are for the account Synapse can use to connect and search, necessary if anonymous access is prohibited.

Server configuration

See Define your homeserver name and other base options in the Synapse documentation.

It would be logical to put the next options under conf.d/server.yaml, but Debian insists on conf.d/server_name.yaml existing and containing the name of the domain. So we'll use that file for the next options as well. Add these options:

presence:
  enabled: true
  include_offline_users_on_sync: false

require_auth_for_profile_requests: true
allow_public_rooms_over_federation: true

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'
  - '192.0.0.0/24'
  - '169.254.0.0/16'
  - '192.88.99.0/24'
  - '198.18.0.0/15'
  - '192.0.2.0/24'
  - '198.51.100.0/24'
  - '203.0.113.0/24'
  - '224.0.0.0/4'
  - '::1/128'
  - 'fe80::/10'
  - 'fc00::/7'
  - '2001:db8::/32'
  - 'ff00::/8'
  - 'fec0::/10'

filter_timeline_limit: 500
delete_stale_devices_after: 1y

These should be reasonable defaults, but do check the Server block in Synapse's documentation for more options and information.

Registration

Registration of new users is configured under conf.d/registration.yaml:

enable_registration: false
enable_registration_without_verification: false
registrations_require_3pid: email
registration_shared_secret: <long random string>
allow_guest_access: false

enable_set_displayname: false
enable_3pid_changes: false

The last two lines prohibit users to change their displayname and 3pid-data (i.e. e-mail address and phone number). In many cases you'd want them to be able to set these, of course. But when you use LDAP, which provides these values, you don't want users to change those.

See for more options Synapse's documentation.

TURN

Check for more information about how to configure the TURN server or LiveKit. You probably want LiveKit, but read on if you choose coturn.

It might be useful to use both coturn and LiveKit, so as to support both legacy and EC calls, but you'd need to tweak the configurations so that they don't bite each other.

Once you've set up your TURN server, configure it in Synapse, in conf.d/turn.yaml:

turn_shared_secret: "<long random string>"
turn_uris:
  - "turn:turn.matrixdev.example.com?transport=udp"
  - "turn:turn.matrixdev.example.com?transport=tcp"
turn_user_lifetime: 86400000
turn_allow_guests: true

Restart Synapse to activate this bit.

Consent Tracking

As administrator you sometimes need to push a message to all your users. See the Synapse documentation to see how to configure that.

It's also necessary for moderation (see Draupnir).

Server Notices

Server notices allow administrators to send messages to users, much like the wall functionality in UNIX/Linux.

Add this bit of info to conf.d/server_notices.yaml:

server_notices:
  system_mxid_localpart: server
  system_mxid_display_name: "Server Notices"
# system_mxid_avatar_url: "mxc://example.com/QBBZcaxfrrpvreGeNhqRaCjG"
  room_name: "Server Notices"
# room_avatar_url: "mxc://example.com/QBBZcaxfrrpvreGeNhqRaCjG"
  room_topic: "Room used by your server admin to notice you of important
information"
  auto_join: true

This means that the user sending the messages (who isn't really a user anyway) is server@example.com, with the display name Server Notices. The room that users receive these messages in is called the same. The room will be created if it doesn't yet exist, every user that receives a server message will be put in a room with that name.

Every user gets his own room, so if you send a server notice to 100 users, there will be (at least) 100 rooms by that name, all containing 1 user.

The option auto_join means that users will automatically join the room as soon as it's created. They can leave afterwards, but they'll be put into it again as soon as they receive another server message.

The two commented out options are the avatars for user and room. This is a bit tricky. You'll need to upload an image to a room first, so that it's present in the media store. Then you can refer to it by the ID it gets, in the way shown above. These avatars will only be set or changed when you send a server notice.

Important bit: you must upload these pictures to an unencrypted room. Pictures in an encrypted room are... well... encrypted, and that causes a problem for the thumbnailer. Pictures in encrypted rooms are stored as MIME type application/octet-stream, you want one of the formats you configured under Homeserver Blocking. Or, if you haven't defined a whitelist, at least an image mimetype...

Apparently this was a bug that's supposed to be fixed in Synapse 1.20, but we haven't tested that yet.

You can find the ID of the picture in the database (table local_media_repository) or, more conveniently, in Synapse-Admin, which is also where you'll want to go if you want to send a server notice.

In Synapse-Admin, open the User tab, select the user(s) you want to send a notice to, and click "Send Server Notices".

If the result is that you're returned to the login screen of Synapse-Admin, there was an error sending the notice. Check the Synapse logs.

You can force your users to accept an agreement before you let them on your machine, see the Synapse Documentation.

First, make the directory where you want Synapse to search for the document, we create the directory consent_policy:

mkdir -p /var/lib/matrix-synapse/consent_policy/en

You'll have to add the directory en under that, as every document is assumed to be in English. Support for other languages is on the wish list.

Create a Jinja2 template with the texts you want: the text users have to agree to before they can use the service, and the text users that have already agreed will see. Something like this:

<!doctype html>
<html lang="en">
  <head>
    <title>Example End User Policy</title>
  </head>
  <body>
  {% if has_consented %}
    <p>
      You have already accepted the Example End User Policy.
    </p>
  {% else %}
<h1>Example End User Policy</h1>

These are the terms under which you can use this service. Unless you accept these terms, you
will not be allowed to send any messages.

<ol>
  <li>You will not be abusive to other users, be they on this server or on an other.
  <li>You will not do other nasty stuff.
  <li>Basically: you will behave like a good person.
</ol>

We promise you a few things too:

<ol>
  <li>We'll keep your data safe
  <li>We won't snoop on you
  <li>We'll only turn you in with the authorities if you do nasty stuff.
</ol>

If you accept these terms, you can use this system.
    {% if not public_version %}
      <!-- The variables used here are only provided when the 'u' param is given to the homeserver -->
      <form method="post" action="consent">
        <input type="hidden" name="v" value="{{version}}"/>
        <input type="hidden" name="u" value="{{user}}"/>
        <input type="hidden" name="h" value="{{userhmac}}"/>
        <input type="submit" value="I accept"/>
      </form>
    {% endif %}
  {% endif %}
  </body>
</html>

The name of this document needs to be a version name with the extension .html. Say you want your users to accept version 0.1, the file must be named 0.1.html. This version is referred to in the configuration.

After a user has agreed to this policy, he is presented with success.html, which you will also have to make (although it's not mentioned in the documentation). This doesn't have to be very complicated.

<!doctype html>
<html lang="en">
  <head>
    <title>ProcoliX End User Policy</title>
  </head>
  <body>
<p>You have agreed to our End User Policy, you can now use our service.</p>

<p>Have fun!</p>
  </body>
</html>

We now have the texts ready, time to configure Synapse to use it.

Create a form_secret:

pwgen -csny 30 1

Add this bit to conf.d/server_notices.yaml:

form_secret: "<previously generated secret>"
user_consent:
  require_at_registration: true
  policy_name: "Example End User Policy"
  template_dir: consent_policy
  version: <version>
  server_notice_content:
    msgtype: m.text
    body: >-
      You have to agree to our End User Policy before you can use this
      service. Please read and accept it at %(consent_uri)s.
  block_events_error: >-
    You haven't accepted the End User Policy yet, so you can't post any
    messages yet. Please read and accept the policy at %(consent_uri)s.

Last bit it to enable the consent tracking on all listeners where client is active. We have only one listener, so we add consent to that:

listeners:
  - port: 8008
    tls: false
    type: http
    x_forwarded: true
    bind_addresses: ['::1', '127.0.0.1']
    resources:
      - names:
        - client
        - consent
        - federation
        compress: false

Restart Synapse for these changes to take effect.

If you update your policy, you'll have to copy the current one to a new version, edit that (e.g. 0.2.html) and change the version to the new document. Restart Synapse after that. Your users will all have to agree to the new policy.

The options server_notice_content and block_events_error do not seem to be used, this is something that needs to be investigated.