Self-Host Continuwuity: A Lightweight Matrix Homeserver
Matrix has a reputation problem. Ask around about self-hosting your own chat server and someone will tell you about the Postgres tuning, the worker processes, the box that quietly ate 4 GB of RAM to serve nine people. That reputation is mostly about Synapse, the reference implementation, and it has scared off a lot of people who just wanted a private group chat they actually own.
Continuwuity is the other answer. It's a Matrix homeserver written in Rust, it ships as a single binary, and it's designed to run on hardware you would not think twice about paying for.
Where this project came from
Worth knowing before you commit, because the lineage is unusual.
Continuwuity is the official community continuation of conduwuit, a Rust homeserver whose original project was archived and left unmaintained. Rather than let it disappear, a group of contributors forked it and kept going. That is not a red flag, it's the open source immune system doing its job, but it does mean you should check the project is still active before you deploy. At the time of writing the current release is v26.8.1, tagged on 22 August 2026, and commits land on main most weeks.
One quirk you'll notice immediately: the project doesn't live on GitHub. It self-hosts its own Forgejo instance at forgejo.ellis.link. Container images are mirrored to GHCR, Docker Hub and GitLab, so your pull works either way.
What you're trading away
Let's be honest about this up front, because a lot of writeups skip it.
Synapse is the reference implementation. It gets new Matrix features first, it has the widest ecosystem support, and if you're running a large public homeserver with thousands of federated users, it remains the safer institutional choice. Continuwuity targets the other end: small and mid-sized servers where efficiency matters more than being first to implement every spec change.
If you're a team, a family, a community, or a company that wants its own chat without a per-seat bill, that trade is very easy to make.
Before you start
- A domain name pointed at your server
- Ports 443 and 8448 open (443 for clients, 8448 for federation)
- A reverse proxy terminating TLS. Federation will not work over plain HTTP
The Docker Compose that actually works
services:
homeserver:
image: forgejo.ellis.link/continuwuation/continuwuity:latest
restart: unless-stopped
volumes:
- db:/var/lib/continuwuity
- ./resolv.conf:/etc/resolv.conf:ro
environment:
CONTINUWUITY_SERVER_NAME: example.com
CONTINUWUITY_DATABASE_PATH: /var/lib/continuwuity
CONTINUWUITY_ADDRESS: 0.0.0.0
CONTINUWUITY_PORT: 8008
CONTINUWUITY_ALLOW_REGISTRATION: "true"
CONTINUWUITY_REGISTRATION_TOKEN: "replace-this-with-something-long"
CONTINUWUITY_WELL_KNOWN: "{ client=https://example.com,server=example.com:443 }"
caddy:
image: docker.io/caddy:latest
restart: unless-stopped
ports:
- "80:80"
- "443:443"
- "8448:8448"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy_data:/data
volumes:
db:
caddy_data:
And the Caddyfile, which is three lines:
https://example.com:443, https://example.com:8448 {
reverse_proxy http://homeserver:8008
}
That compose file mounts a resolv.conf next to it, so create that too before you start. It is two lines, and the reason it matters is in the troubleshooting section below:
nameserver 1.0.0.1
nameserver 1.1.1.1
Then bring the stack up with docker compose up -d. Caddy handles certificates automatically.
The one setting you cannot change later
CONTINUWUITY_SERVER_NAME is permanent. It becomes part of every user ID and every room ID your server creates, so changing it later means wiping the database and starting over. Decide whether you want @you:example.com or @you:matrix.example.com before you press enter, not after.
If you want user IDs on your bare domain but the server running on a subdomain, that's what CONTINUWUITY_WELL_KNOWN handles. It advertises delegation so clients and federating servers know where to actually connect.
Registration, and a config option with a very long name
Leaving registration open is how you end up hosting other people's spam. Continuwuity makes it deliberately awkward to do that: setting allow_registration = true with no token requires a flag called yes_i_am_very_very_sure_i_want_an_open_registration_server_prone_to_abuse, and that flag only works if you compiled the binary with a specific feature enabled.
I appreciate a project that puts the consequences in the variable name. Set CONTINUWUITY_REGISTRATION_TOKEN and hand the token to people you actually want on your server.
Your first registered account becomes the admin. From any Matrix client you can then talk to the admin room and run commands like !admin users list or generate one-off invite tokens with !admin token.
Troubleshooting
Federation silently doesn't work. This is the big one, and it catches nearly everyone. Docker's built-in DNS resolver is known to cause timeouts on Matrix federation lookups, which is why the compose file above mounts that custom resolv.conf. If you skipped it, go back and add it. Symptoms are messages to remote servers that never arrive and no obvious error in the logs.
Check your work before blaming your config. The Matrix Federation Tester at federationtester.matrix.org will tell you exactly which part of the handshake is failing. Run it before you start editing things at random.
Rooms join slowly the first time. Joining a large federated room means pulling a lot of state from other servers. First join is slow, subsequent activity is not. This is Matrix behaviour, not a Continuwuity problem.
Port 8448 is closed and you cannot open it. Use .well-known delegation to route federation over 443 instead. The compose above already advertises server=example.com:443 for exactly this case.
What it costs to run
Open source means no license fees, but the server still has to live somewhere. Real Elestio infrastructure pricing:
| Config | Resources | Price/mo | Good for |
|---|---|---|---|
| NC-MEDIUM-2C-4G | 2 vCPU, 4 GB, 60 GB NVMe | $16 | A team, a family, a small community |
| NC-LARGE-4C-8G | 4 vCPU, 8 GB, 100 GB NVMe | $29 | Heavier federation, bridges, more media |
That's a flat cost regardless of how many people you add, which is the entire argument against per-seat chat pricing. Media storage is the thing that grows, so watch the disk rather than the RAM.
Getting it running without the reverse proxy work
Everything above is genuinely doable in an afternoon, and if you enjoy that, go do it. If you'd rather skip the TLS and DNS plumbing, Continuwuity on Elestio gives you a dedicated instance with certificates, backups, monitoring and updates handled, on any of 100+ regions.
Either way, the thing you end up with is a chat server whose user list nobody can price per seat, and whose message history nobody can hold hostage.
Thanks for reading ❤️