Skip to content

wlphi/nixmatrix

Repository files navigation

nixMatrix

A complete, self-hosted Matrix homeserver stack as a single NixOS flake. Deploy a federated chat server — with modern OIDC login, web clients, messaging bridges, video calls, and monitoring — to a fresh VPS in one command.

Everything is declarative and reproducible: the entire server is described in this repo, secrets are encrypted with sops-nix, and deployment is a single nixos-anywhere run.

This is the NixOS sibling of ess-docker-compose — the same stack as a Docker Compose deployment. Use that one for Docker on an existing box; use this if you run (or want to run) NixOS and prefer a single declarative config. Both stay in sync.

Status: the whole stack boots and passes automated tests in CI, but hasn't been widely run on real servers yet — see Project status. If you deploy it, please open an issue and say how it went.


What you get

Area Components
Homeserver Synapse with federation
Authentication Matrix Authentication Service (MAS) — modern OIDC/OAuth2 login (MSC3861)
Web clients Element Web, FluffyChat, and an admin panel
Bridges mautrix Telegram, WhatsApp, Signal, Discord
Voice / video Element Call backed by LiveKit
SSO (optional) Authelia as an upstream identity provider
TLS & routing Caddy with automatic Let's Encrypt certificates
Data PostgreSQL 16 (per-service users, daily backups) + Redis
Observability Prometheus, node/postgres exporters, and Grafana dashboards

All secrets stay encrypted at rest and are only ever decrypted to tmpfs at runtime — never written to the Nix store.

Architecture

A single host runs everything behind Caddy, which terminates TLS and routes each subdomain to the right service:

                          ┌──────────────────────── your-domain.com ────────────────────────┐
   Internet ──443──▶ Caddy │  matrix.*  → Synapse        auth.*    → MAS                       │
                          │  element.* → Element Web    chat.*    → FluffyChat               │
                          │  admin.*   → Admin panel    rtc.*     → LiveKit / Element Call   │
                          │  call.*    → Element Call   monitoring.* → Grafana               │
                          └──────────────────────────────────────────────────────────────────┘
                                   │              │               │
                              PostgreSQL        Redis        mautrix bridges

Every subdomain is derived automatically from the one nixmatrix.domain value you set.

Prerequisites

  • A server you can SSH into as root, running any Linux (it gets reinstalled with NixOS) — 2+ vCPU and 4+ GB RAM recommended.
  • A domain you control, with DNS pointed at the server (see DNS).
  • Locally: Nix with flakes enabled, plus age and sops (if missing, the bootstrap script prints the nix shell command to get them).

Quick start (production)

git clone <this-repo> nixmatrix && cd nixmatrix

# 1. Guided setup: generates encryption keys, fills in secrets, sets your domain.
./scripts/bootstrap.sh

# 2. Review the generated config, then deploy to your server.
nix run github:nix-community/nixos-anywhere -- \
  --flake .#matrix-server --target-host root@<SERVER_IP> \
  --extra-files .bootstrap/extra-files -i ~/.ssh/id_rsa

The bootstrap script walks you through everything interactively. For the full manual procedure, DNS records, and post-install steps, see docs/DEPLOY.md.

After the first deploy, push config changes with:

nixos-rebuild switch --flake .#matrix-server --target-host root@<SERVER_IP>

Try it locally first (no server needed)

You can build and boot the whole stack in a QEMU VM on your laptop to see it work before touching a real server:

./test/setup-test-secrets.sh                       # one-time: dummy secrets
nixos-rebuild build-vm --flake .#matrix-server-vm
./result/bin/run-nixmatrix-vm

Then browse to https://localhost:8443 (self-signed cert). See test/README.md for details and known VM limitations.

Configuration

The only value you must change is your domain, in hosts/matrix-server.nix:

nixmatrix.domain = "your-domain.com";   # everything else is derived from this

You'll also set, in the same file:

  • users.users.root.openssh.authorizedKeys.keys — your SSH public key (password login is disabled, so this is required or you'll be locked out).
  • disko.devices.disk.main.device in modules/disk.nix — the target disk (/dev/sda, /dev/vda, /dev/nvme0n1; check with lsblk).

Bridges are opt-in. Enable only what you use:

nixmatrix.bridges.whatsapp.enable = true;
nixmatrix.bridges.signal.enable   = true;
# telegram also needs API credentials in secrets.yaml (see below)
nixmatrix.bridges.hookshot.enable = true;  # GitHub/GitLab/Jira/webhooks/RSS (not a chat network)

A disabled bridge contributes nothing and can never prevent the homeserver from starting. The chat bridges (Telegram/WhatsApp/Signal/Discord) connect to those networks; hookshot instead links Matrix to GitHub, GitLab, Jira, generic webhooks, and RSS.

Other optional toggles (all default off, set in the same file):

nixmatrix.openRegistration     = true;  # public self-signup (else admin-only)
nixmatrix.sso.enable           = true;  # Authelia SSO in front of MAS
nixmatrix.externalProxy.enable = true;  # sit behind your own nginx/Apache (see docs)
nixmatrix.turn.enable          = true;  # TURN fallback so calls work behind strict NAT

Already run nginx or Apache? nixMatrix can sit behind it — see examples/reverse-proxy/ for ready-to-use configs.

Secrets live in secrets/secrets.yaml (encrypted with sops). The bootstrap script generates them for you; the template is documented in secrets/secrets.yaml.

Documentation

Testing

./test/check-nix.sh    # static checks for known config pitfalls (no build)
nix flake check        # evaluates every config + runs the VM integration test (needs /dev/kvm)
./test/smoke-test.sh   # assertions against an already-running VM or host

The integration test (test/integration.nix) is what backs the "boot-verified" claim below. CI runs the static checks on every push and the full build + integration test on PRs and main (.github/workflows/ci.yml).

Project status

On every change, CI boots the entire stack in a VM and checks that all the core services start and stay up, the databases are created, and the important paths work — login through MAS, account discovery, and Element loading. So the stack is known to come up correctly from the config in this repo.

What it hasn't done yet:

  • Run widely on real servers. The automated test uses self-signed certificates and throwaway secrets, so it doesn't prove real Let's Encrypt certificates or federation with other Matrix servers. Your first deploy is the real test — please report how it goes.
  • Calls behind difficult networks. Voice/video works on a normal VPS out of the box; for users behind strict NAT/CGNAT, enable the built-in TURN fallback (nixmatrix.turn.enable). Untested across every network type — see docs/DEPLOY.md.
  • Bridges end-to-end. They're off by default and you enable the ones you want; bridge encryption is intentionally disabled (it isn't compatible with MAS yet).
  • Slack and IRC chat bridges aren't implemented yet (GitHub/GitLab/Jira/ webhooks are covered by hookshot).

Bug reports and "it worked / it didn't" notes are very welcome.

License

MIT.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors