Setting Up a Matrix Server on Ubuntu 20.04 – Part 2

In part 1 of this tutorial, I dived into my reasons for setting up a Matrix Synapse homeserver, and how to set up the basics of the server and it’s required software. In part 2, I’m going to register myself an admin account, log into the server using the online chat client, to verify it’s all working as it should, and migrate the database engine from SQLite to Postgres.

A quick reminder, all server commands are run as the root user.

Register an admin user account

Installing the Matrix Synapse server software also installs a few executables on the server, that can be used for specific tasks. register_new_matrix_user is one such executable, and it allows you to register a new user from the command line of the server.

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

The process will ask you for a user name, password, and whether to make this user an admin or not.

Once you’ve created the user, you can log in to the homeserver via the Element web client hosted at, or download Element for your operating system, and Sign in from the client.

Either way, to sign in to your server, click on the Change link, next to “Sign in to your Matrix account on”.

Enter the server domain as the homeserver URL and click Next.

Enter your user name and password and click Sign in.

Switch Database Engine

While Matrix Synapse shops with SQLite by default, the official documentation suggests this only for testing purposes or for servers with light workloads. Otherwise, it’s recommended to switch to Postgres, as it provides significant performance improvements due to the superior threading and caching model, and smarter query optimiser, and allows the database to be run on separate hardware.

Install Postgres

First step is to install Postgres on the server.

apt install postgresql postgresql-contrib

We then need to create a user for synapse to use to access the database. We do this by switching to the postgres system user, and running the createuser command

su - postgres
createuser --pwprompt synapse_user

The createuser command will ask you for a password, and create the synapse_user with that password.

Now we can create the database, by logging into the Postgres database server, while operating as the postgres system user.


Once logged in, we can create the database, and assign it to the synapse_user

 OWNER synapse_user;

Then we need to allow the synapse_user to connect to the database. The Postgres docs for Synapse talk about possibly needing to enable password authentication, but I found that by default this was already endabled, so all I had to do was add the relevant file to the pg_hba.conf file. I wasn’t sure how to find the pg_hba.conf file on my system, but this Stack Overflow thread explained what commands I could use when logged into the Postgres database server.

show hba_file;

My pb_hba.conf file was located at /etc/postgresql/12/main/pg_hba.conf.

Towards the bottom of the file, I added the Synapse local connection section to allow the synapse user access to Postgres.

# Database administrative login by Unix domain socket
local   all             postgres                                peer

# TYPE  DATABASE        USER            ADDRESS                 METHOD

# "local" is for Unix domain socket connections only
local   all             all                                     peer
# IPv4 local connections:
host    all             all               md5
# Synapse local connection:
host    synapse         synapse_user    ::1/128                 md5
# IPv6 local connections:
host    all             all             ::1/128                 md5
# Allow replication connections from localhost, by a user with the
# replication privilege.
local   replication     all                                     peer
host    replication     all               md5
host    replication     all             ::1/128                 md5

Because line order matters in pg_hba.conf, the Synapse Postgres docs make a point of the fact that the Synapse local connection needs to be just above the IPv6 local connections.

Migrating the SQLite data to the Postgres database

In order for the data to be migrated from the SQLite database to the PostgreSQL database, we need to use the synapse_port_db executable, which requires that the homeserver.yaml file includes the correct server_name. So edit the homeserver.yaml, and set the server_name to your domain name from part 1.

nano /etc/matrix-synapse/homeserver.yaml
server_name: ""

The next step is to make a copy of the homeserver.yaml file, in preparation for the Postgres set up

cp /etc/matrix-synapse/homeserver.yaml /etc/matrix-synapse/homeserver-postgres.yaml

Then, edit the new /etc/matrix-synapse/homeserver-postgres.yaml file, so that the database settings point to the newly created Postgres database.

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

  name: psycopg2
    user: synapse_user
    password: dbpassword
    database: synapse
    host: localhost
    cp_min: 5
    cp_max: 10

Make sure that the newly created /etc/matrix-synapse/homeserver-postgres.yaml file is owned by the correct system user.

chown matrix-synapse:nogroup /etc/matrix-synapse/homeserver-postgres.yaml

Next step is to copy the SQLite database, so that we can import from the copy, and give that copy the correct permissions.

cp /var/lib/matrix-synapse/homeserver.db /var/lib/matrix-synapse/homeserver.db.snapshot
chown matrix-synapse:nogroup /var/lib/matrix-synapse/homeserver.db.snapshot

We should then stop the matrix-synapse server, before we run the import.

systemctl stop matrix-synapse

Now we can use the synapse_port_db command to import the data from SQLite to Postgres, using the SQLite snapshot, and the Postgres enabled homeserver-postgres.yaml.

synapse_port_db --curses --sqlite-database homeserver.db.snapshot --postgres-config /etc/matrix-synapse/homeserver-postgres.yaml

Once the import successfully completes, we can backup the current SQLite enabled configuration.

mv /etc/matrix-synapse/homeserver.yaml /etc/matrix-synapse/homeserver-old-sqlite.yaml

Finally, we set the Postgres enabled yaml as the default.

mv /etc/matrix-synapse/homeserver-postgres.yaml /etc/matrix-synapse/homeserver.yaml

At this stage, it’s a good idea to make sure that the new /etc/matrix-synapse/homeserver.yaml file has the right permissions set, and if not, set them correctly.

chown matrix-synapse:nogroup /etc/matrix-synapse/homeserver.yaml

And that’s it, log into your Matrix server via the web client or desktop client, and if you’ve completed the import correctly, everything should be working as before.

That concludes the main set up requirements to have a working Matrix homeserver.

I do however plan to have two follow-up posts. In the first, I’ll dive into some of the quirks of signing into and verifying additional clients, once your initial sign-in has been successful.

For the second, I’ll be adding some testers to the mix, and I’ll document and any configuration changes I’ve needed to make, to get things usable as a community communication platform. This one might take a bit longer, as it relies on other folks testing the platform, giving me feedback, and me tweaking the server until it’s a workable solution.






15 responses to “Setting Up a Matrix Server on Ubuntu 20.04 – Part 2”

  1. skarz Avatar

    This works really well until the very end when you import the data, and I get

    Traceback (most recent call last):
    File “/usr/bin/synapse_port_db”, line 1136, in
    hs_config = yaml.safe_load(args.postgres_config)
    File “/opt/venvs/matrix-synapse/lib/python3.8/site-packages/yaml/”, line 162, in safe_load
    return load(stream, SafeLoader)
    File “/opt/venvs/matrix-synapse/lib/python3.8/site-packages/yaml/”, line 114, in load
    return loader.get_single_data()
    File “/opt/venvs/matrix-synapse/lib/python3.8/site-packages/yaml/”, line 49, in get_single_data
    node = self.get_single_node()
    File “/opt/venvs/matrix-synapse/lib/python3.8/site-packages/yaml/”, line 39, in get_single_node
    if not self.check_event(StreamEndEvent):
    File “/opt/venvs/matrix-synapse/lib/python3.8/site-packages/yaml/”, line 98, in check_event
    self.current_event = self.state()
    File “/opt/venvs/matrix-synapse/lib/python3.8/site-packages/yaml/”, line 171, in parse_document_start
    raise ParserError(None, None,
    yaml.parser.ParserError: expected ”, but found ”
    in “/etc/matrix-synapse/homeserver-postgres.yaml”, line 35, column 1

    1. Jonathan Avatar

      I’m not a Matrix synapse expert, but happy to try and help debug.

      My guess is that it’s something in your /etc/matrix-synapse/homeserver-postgres.yaml file.

      Did you change that file to use the Postgres database credentials you set up in the previous steps?

  2. Rainer Avatar

    Thanks for this great tutorial. I successfully installed Matrix on my Ubuntu 20.04.
    Although I already had Apache installed I managed to get Matrix running with Nginx by changing some ports in Nginx setup.

    But now when trying to migrate to Postgres the synapse_port_db ends up with “Pending background updates exist in the SQLite3 database.” Doing a reboot and then copy the snapshot again didn’t help.

    Sounds for me as sth is locked. Any ideas?

    Thanks and best regards

    1. Jonathan Avatar

      Unfortunately no, as I’ve not encountered any issues like that. Usually what I do is do a search for the error, and start digging.

    2. Eric Lewellen Avatar
      Eric Lewellen

      Use this command instead of the one in the guide:

      synapse_port_db –curses –sqlite-database /var/lib/matrix-synapse/homeserver.db.snapshot –postgres-config /etc/matrix-synapse/homeserver-postgres.yaml

    3. News4G33ks (@News4G33ks) Avatar

      Use the command :

      update_synapse_database –run-background-updates –database-config /etc/matrix-synapse/homeserver.yaml

      It can take hours but when it’s finished you can copy the snapshot again and then run synapse_port_db properly

  3. Hanno Avatar

    i end up with “synapse_port_db –curses –sqlite-database homeserver.db.snapshot –postgres-config homeserver-postgres.yaml”

    File “/home/pi/synapse/env/lib/python3.7/site-packages/twisted/enterprise/”, line 297, in _runWithConnection
    result = func(conn, *args, **kw)
    File “/home/pi/synapse/env/lib/python3.7/site-packages/synapse/storage/”, line 734, in inner_func
    return func(db_conn, *args, **kwargs)
    File “/home/pi/synapse/env/lib/python3.7/site-packages/synapse/storage/”, line 534, in new_transaction
    r = func(cursor, *args, **kwargs)
    File “/home/pi/synapse/env/bin/synapse_port_db”, line 908, in _setup_events_stream_seqs_set_pos
    (curr_backward_id + 1,),
    TypeError: unsupported operand type(s) for +: ‘NoneType’ and ‘int’

    Do you have any idea?

    1. Jonathan Avatar

      Unfortunately no, as I’ve not encountered any issues like that. Usually what I do is do a search for the error, and start digging.

  4. C Moore Avatar
    C Moore

    huh. Everything seems to go okay up until i restart the matrix-synapse server and…

    root@matrix:/etc/matrix-synapse# systemctl start matrix-synapse
    Job for matrix-synapse.service failed because the control process exited with error code.
    See “systemctl status matrix-synapse.service” and “journalctl -xe” for details.
    root@matrix:/etc/matrix-synapse# tail /var/log/syslog
    Feb 16 15:35:46 matrix matrix-synapse[212255]: This server is configured to use ‘’ as its trusted key server via the
    Feb 16 15:35:46 matrix matrix-synapse[212255]: ‘trusted_key_servers’ config option. ‘’ is a good choice for a key
    Feb 16 15:35:46 matrix matrix-synapse[212255]: server since it is long-lived, stable and trusted. However, some admins may
    Feb 16 15:35:46 matrix matrix-synapse[212255]: wish to use another server for this purpose.
    Feb 16 15:35:46 matrix matrix-synapse[212255]: To suppress this warning and continue using ‘’, admins should set
    Feb 16 15:35:46 matrix matrix-synapse[212255]: ‘suppress_key_server_warning’ to ‘true’ in homeserver.yaml.
    Feb 16 15:35:46 matrix matrix-synapse[212255]: ——————————————————————————–
    Feb 16 15:35:47 matrix systemd[1]: matrix-synapse.service: Main process exited, code=exited, status=1/FAILURE
    Feb 16 15:35:47 matrix systemd[1]: matrix-synapse.service: Failed with result ‘exit-code’.
    Feb 16 15:35:47 matrix systemd[1]: Failed to start Synapse Matrix homeserver.

    well that’s pretty nonspecific, lol. the postgres server is running fine, has the synapse database , permissions all look okay but now that my matrix server is splat i can’t even go back to the matrix forums and ask for help….agh. may have to backtrack, but this info is basically congruent with

    any thoughts?

    1. Jonathan Avatar

      Have you tried running journalctl -xe as the output suggested. Usually that shows where the error is located

    2. jw Avatar

      Same issue here

    3. jigglywiggly Avatar

      You need to check /var/log/matrix-synapse/homeserver.log
      You likely need to run a few commands it mentions
      For me I ran:
      su – postgres
      psql –host=localhost –dbname=synapse –username=synapse_user
      SELECT setval(‘event_auth_chain_id’, (
      SELECT GREATEST(MAX(chain_id), 0) FROM event_auth_chains

  5. snappy Avatar

    Hey, this was so helpful.
    how would I go about adding a bridge like signal ( to this??

  6. Germano Avatar

    Hello, i have completed most of the steps up to the SQLite importing. After i apply this command >>>>>synapse_port_db –curses –sqlite-database homeserver.db.snapshot –postgres-config /etc/matrix-synapse/homeserver-postgres.yaml<<<<<<<<< it says “Database must use the ‘psycopg2’ connector.

    1. cliff1976 Avatar

      I have the same results as Germano.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: