Matrix Homeserver
    Systemd Binary

    Deploy a Conduit Matrix Homeserver on a VPS

    Run a lightweight Matrix homeserver on a RamNode VPS — Conduit's single Rust binary with RocksDB, systemd, a reverse proxy, and federation delegation.

    Matrix is an open network for secure, decentralized communication. Run your own homeserver and you get a chat identity on your own domain that can federate with every other Matrix server in the world. Conduit is the lightweight choice for this: a single Rust binary with an embedded RocksDB database, designed for easy setup and low resource use. It is efficient enough to run on hardware as small as a Raspberry Pi, which makes it a great fit for a modest RamNode VPS serving a family, a team, or a small community.

    This guide deploys Conduit on Ubuntu 24.04 LTS using the prebuilt binary, a systemd service, and a reverse proxy with the federation delegation that lets the wider Matrix network find you.

    A quick word on the Conduit ecosystem

    Conduit is the original project by Timo Köster, hosted at gitlab.com/famedly/conduit. A family of forks has grown around it, including Continuwuity and Tuwunel, which add features and performance work. They share a code lineage, and security fixes often land across all of them at once. This guide targets upstream Conduit. Whichever you run, the single most important operational habit is to stay current: in early 2026 the Conduit based servers shipped coordinated critical security releases, so subscribe to the project's release feed and update promptly.

    Prerequisites

    • A RamNode VPS running Ubuntu 24.04 LTS. 1 to 2 GB RAM handles a small server comfortably; federation with busy rooms benefits from more.
    • Root or sudo access.
    • A domain you control. Two names matter:
      • The server name, the part after the colon in user IDs, for example example.com. This is what users type, as in @alice:example.com.
      • The delegated host that actually runs Conduit, for example matrix.example.com.
    • DNS A records for both names pointing at the VPS, and ports 80 and 443 open.

    The split between server name and delegated host is the standard, clean way to run Matrix: identities read nicely as @you:example.com while the service lives on a subdomain.

    Step 1: Create a service user and directories

    shell
    sudo useradd -r -m -d /var/lib/conduit -s /usr/sbin/nologin conduit
    sudo mkdir -p /etc/conduit

    Step 2: Install the Conduit binary

    Download the latest release binary for x86_64 and install it:

    shell
    cd /tmp
    wget -O conduit https://gitlab.com/famedly/conduit/-/releases/permalink/latest/downloads/conduit-linux-x86_64
    sudo install -m 755 conduit /usr/local/bin/conduit
    conduit --version

    If your VPS is ARM based, download the matching ARM artifact from the releases page instead. If a prebuilt binary is unavailable for your platform, you can build from source with Rust (cargo build --release), but the binary is the simplest path.

    Step 3: Write the configuration

    Create /etc/conduit/conduit.toml:

    shell
    [global]
    # The public server name in user IDs (@user:example.com)
    server_name = "example.com"
    
    # Embedded database
    database_path = "/var/lib/conduit"
    database_backend = "rocksdb"
    
    # Conduit listens locally; the reverse proxy terminates TLS
    address = "127.0.0.1"
    port = 6167
    
    max_request_size = 20_000_000  # 20 MB upload cap
    
    # Lock down registration: open it briefly only when adding users,
    # or use a token (see below)
    allow_registration = false
    
    allow_federation = true
    allow_check_for_updates = true
    
    # Trusted key server for federation key lookups
    trusted_servers = ["matrix.org"]

    Set ownership so the service user owns its database:

    shell
    sudo chown -R conduit:conduit /var/lib/conduit
    sudo chown conduit:conduit /etc/conduit/conduit.toml
    sudo chmod 600 /etc/conduit/conduit.toml

    Controlling registration with a token

    Leaving registration fully open invites spam accounts. The cleaner pattern is a registration token: keep allow_registration off for the public, and hand a token to people you actually want to onboard. Add to the [global] section:

    shell
    allow_registration = true
    registration_token = "choose-a-long-random-string"

    Only people who enter that token in their client can register. Rotate or remove it when you are done onboarding.

    Step 4: Create the systemd service

    Create /etc/systemd/system/conduit.service:

    shell
    [Unit]
    Description=Conduit Matrix Homeserver
    After=network.target
    
    [Service]
    User=conduit
    Group=conduit
    Environment="CONDUIT_CONFIG=/etc/conduit/conduit.toml"
    ExecStart=/usr/local/bin/conduit
    Restart=always
    RestartSec=5
    
    # Hardening
    NoNewPrivileges=true
    ProtectSystem=strict
    ProtectHome=true
    ReadWritePaths=/var/lib/conduit
    PrivateTmp=true
    
    [Install]
    WantedBy=multi-user.target

    Enable and start it:

    shell
    sudo systemctl daemon-reload
    sudo systemctl enable --now conduit
    sudo systemctl status conduit

    Confirm it is listening locally:

    shell
    curl http://127.0.0.1:6167/_matrix/client/versions

    A JSON response listing supported client API versions means Conduit is alive.

    Step 5: Reverse proxy, TLS, and federation delegation

    This is the step that makes your server reachable and federating. Caddy makes it short. Install it:

    shell
    sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https
    curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
    curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
    sudo apt update && sudo apt install -y caddy

    Two things have to be served:

    1. The Matrix API itself, proxied to Conduit, on the delegated host matrix.example.com.
    2. Two well known JSON files on the server name example.com that tell other servers and clients where to find your homeserver.

    Set /etc/caddy/Caddyfile:

    shell
    # The delegated host that actually runs Conduit
    matrix.example.com {
        reverse_proxy /_matrix/* 127.0.0.1:6167
    }
    
    # The server name: serve delegation well-known files
    example.com {
        # Server-to-server delegation (federation)
        handle /.well-known/matrix/server {
            header Content-Type application/json
            header Access-Control-Allow-Origin *
            respond `{"m.server": "matrix.example.com:443"}`
        }
    
        # Client discovery
        handle /.well-known/matrix/client {
            header Content-Type application/json
            header Access-Control-Allow-Origin *
            respond `{"m.homeserver": {"base_url": "https://matrix.example.com"}}`
        }
    
        # your normal website can be served here too
    }

    Reload Caddy:

    shell
    sudo systemctl restart caddy

    Caddy provisions Let's Encrypt certificates for both names automatically. The m.server delegation tells other homeservers to reach you at matrix.example.com:443, while the m.client file tells clients which base URL to log in against.

    Step 6: Firewall

    shell
    sudo ufw allow OpenSSH
    sudo ufw allow 80/tcp
    sudo ufw allow 443/tcp
    sudo ufw enable

    Conduit's port 6167 stays internal. Matrix federation runs over the standard HTTPS port 443 thanks to the delegation, so there is no extra federation port to open.

    Step 7: Create your first user and verify

    Open registration briefly or use your token, then register from a Matrix client such as Element. Point the client at the homeserver https://matrix.example.com (or just example.com, which the client well known file will redirect), and create your account.

    Verify federation works using the public tester:

    shell
    curl "https://federationtester.matrix.org/api/report?server_name=example.com"

    Look for "FederationOK": true in the response. Also sanity check your delegation files directly:

    shell
    curl https://example.com/.well-known/matrix/server
    curl https://example.com/.well-known/matrix/client

    Once federation is green, try joining a public room from another server, for example #matrix:matrix.org, to confirm end to end connectivity.

    Performance tuning

    For a busier server, add to the [global] section:

    shell
    # Raise concurrency on busy servers
    max_concurrent_requests = 200
    # Cache sizing (bytes); 1 GB shown
    cache_capacity = 1073741824

    Conduit's single binary, embedded database design means there are few moving parts to tune. Most small servers never need to touch these.

    Backups

    Stop Conduit first so the RocksDB database is consistent, copy it, then restart:

    shell
    sudo systemctl stop conduit
    sudo cp -a /var/lib/conduit /var/backups/conduit-$(date +%F)
    sudo systemctl start conduit

    For minimal downtime on a larger server, use a filesystem snapshot instead. Ship backups off the VPS and automate with cron.

    Updating

    Conduit security fixes can be urgent, so make updates easy:

    shell
    cd /tmp
    wget -O conduit https://gitlab.com/famedly/conduit/-/releases/permalink/latest/downloads/conduit-linux-x86_64
    sudo systemctl stop conduit
    sudo install -m 755 conduit /usr/local/bin/conduit
    sudo systemctl start conduit

    Watch the release feed and apply security releases without delay.

    Troubleshooting

    • FederationOK is false. Your .well-known/matrix/server file is missing, malformed, or not served over valid TLS. Re-fetch it with curl and confirm it returns exactly {"m.server": "matrix.example.com:443"} with a JSON content type.
    • Clients cannot find the homeserver. The m.client well known file is wrong or not reachable on the bare server name. Check it directly.
    • Conduit will not start. Check journalctl -u conduit. A common cause is a permissions problem on /var/lib/conduit; confirm the conduit user owns it.
    • Registration is refused. That is expected with allow_registration = false. Enable it temporarily or supply the registration token in your client.

    Wrap up

    You now run your own federating Matrix homeserver on a RamNode VPS: a single lightweight Conduit binary with an embedded database, TLS and federation delegation handled by Caddy, registration locked behind a token, and the database under regular backup. Your community gets @name:example.com identities and can talk to anyone, anywhere on the Matrix network, on infrastructure you fully control. Keep it patched and it will quietly run for a long time.