Matrix Synapse on Opalstack: self-host chat without Docker (no root, no systemctl)

Matrix Synapse on Opalstack: self-host chat without Docker (no root, no systemctl)
Matrix Synapse on Opalstack — userspace installer, no root required

Matrix is what you run when you want your own chat without giving a platform permanent custody of your community.

Synapse is the “reference” homeserver implementation — and it’s absolutely runnable on managed hosting as long as you treat it like an app (not a snowflake pet server).

On Opalstack, Synapse runs the way we think apps should run:

  • userspace
  • isolated per app
  • restartable
  • loggable
  • upgradeable
  • and readable (it’s a script, not a black box)

TL;DR

  1. Create a Matrix Synapse app as an Open App Stack (Proxied Port).
  2. Map it to a domain/site (so HTTPS works normally).
  3. Set server_name + public_baseurl once (then never change them).
  4. Create your first admin user.
  5. Add .well-known so federation works cleanly behind port 443.
  6. Keep it alive with a cron watchdog (every ~10 minutes).

The pitch

Most “how to host Matrix” guides assume one of these:

  • root access
  • Docker spaghetti
  • “just systemctl it bro”
  • a reverse proxy config you’re supposed to guess

That’s not how Opalstack works.

Here, Synapse runs as a userspace service under your account — same model as every other Open App Stack.


What you get from the Synapse Open App Stack

A production-ish baseline that looks like this:

  • Synapse installed into a per-app Python venv
  • Postgres-backed config (recommended once you’re past toy usage)
  • Start/stop scripts: ~/apps/<appname>/start and ~/apps/<appname>/stop
  • Logs where you’d expect them
  • Cron watchdog for boring reliability

Where it lives on disk (so you can debug like an adult)

Your app folder looks like:

  • App root: ~/apps/<appname>/
  • Project dir: ~/apps/<appname>/matrix/
  • Virtualenv: ~/apps/<appname>/matrix/venv/
  • Config: ~/apps/<appname>/matrix/config/homeserver.yaml
  • Data: ~/apps/<appname>/matrix/data/
  • Log: ~/apps/<appname>/matrix/synapse.log

First run checklist (do this once)

1) Set your domain (this matters)

Open:

~/apps/<appname>/matrix/config/homeserver.yaml

Set these to your real domain:

server_name: "chat.example.com"
public_baseurl: "https://chat.example.com/"

Do not change server_name later unless you intend to wipe and rebuild. (Synapse treats it as identity, not cosmetics.)

2) Start it

~/apps/<appname>/start
tail -f ~/apps/<appname>/matrix/synapse.log

Quick local sanity check:

curl -sS http://127.0.0.1:<YOUR_APP_PORT>/_matrix/client/versions

3) Create your first admin user

Synapse ships a helper for this. The pattern looks like:

~/apps/<appname>/matrix/venv/bin/register_new_matrix_user \
  -c ~/apps/<appname>/matrix/config/homeserver.yaml \
  -u admin -p "use-a-real-password" -a \
  http://127.0.0.1:<YOUR_APP_PORT>

That gets you an initial admin without opening public registration.


Federation on managed hosting (the part everyone trips on)

By default, other Matrix servers expect to reach yours at https://<server_name>:8448/.

On shared hosting, you generally don’t expose 8448 — you run behind standard HTTPS (443). So you must tell the federation network where to find you.

That’s what .well-known is for.

Minimum: /.well-known/matrix/server

Serve this JSON from:

https://<server_name>/.well-known/matrix/server

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

Serve this JSON from:

https://<server_name>/.well-known/matrix/client

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

CORS note: Clients expect CORS headers on the .well-known responses. If you’re serving these as static files, add Access-Control-Allow-Origin: *.


Voice/video (straight talk)

If you want reliable voice/video calling, you’ll need a TURN server.

On shared hosting, opening the giant UDP port ranges TURN wants is typically a non-starter. If you need TURN, use a VPS (or use an external TURN provider).


Security notes (straight talk)

  • Turn off open registration unless you want spam accounts forever.
  • Treat your config + signing keys as secrets.
  • If you expose admin surfaces publicly, you’re responsible for access control.
  • Backups aren’t optional once people care about the server.

Next up

If you want to go further after the base install:

  • add SSO / OIDC
  • add moderation tooling
  • add retention policies
  • tune Postgres pooling
  • set up real monitoring/alerting

That’s what “managed hosting” should feel like: boring, inspectable, fixable.

Read more