Matrix OSMatrix OS

Self-host

Install Matrix OS on your own Linux VPS with the main-domain server installer.

Self-host Matrix OS when you want the cloud-coding computer on infrastructure you control. The installer uses the same published host bundle shape as Matrix Cloud, then configures a standalone profile with local Postgres, systemd services, nginx, the web shell, gateway, code-server, and optional coding-agent tools.

curl -fsSL https://matrix-os.com/install-server.sh | sudo bash

Preview self-host path

The self-host installer is for developers comfortable operating a VPS. Matrix Cloud still provides managed routing, Clerk auth, backups, updates, billing, and integrations. Self-host installs start with nginx Basic Auth and can work from the server IP address; put the host behind HTTPS, Tailscale, Cloudflare Access, or another trusted edge for long-term use.

Requirements

  • A fresh apt-based Linux VPS with systemd.
  • Root or sudo access.
  • Ports 80 and the internal loopback service ports available.
  • Enough disk for the Matrix host bundle, local Postgres, projects, and coding tools.
  • Optional DNS record pointing at the server before install. If you skip DNS, the installer uses the server IP/default nginx vhost.

Install

Create or choose a VPS

Start from a clean Ubuntu or Debian-style server. A small development host works for evaluation; use more CPU and memory if you plan to run multiple coding agents and dev servers.

Run the main-domain installer

curl -fsSL https://matrix-os.com/install-server.sh | sudo bash

No domain is required. The default MATRIX_DOMAIN=_ makes nginx answer on the server IP address and the installer prints an http://<server-ip> URL.

Optional configuration:

curl -fsSL https://matrix-os.com/install-server.sh | sudo \
  MATRIX_DOMAIN=matrix.example.com \
  MATRIX_INSTALL_HANDLE=alice \
  MATRIX_DEVELOPER_TOOLS="codex claude-code opencode" \
  bash

Open the printed URL

The installer prints the URL, username, generated password, and code-server path. Store the initial password somewhere safe, then replace the edge auth with your preferred HTTPS and access-control setup.

Verify services

systemctl status matrix-gateway matrix-shell matrix-code nginx --no-pager
journalctl -u matrix-gateway -u matrix-shell -u matrix-code -n 200 --no-pager
sudo -u matrix bash

Verify CLI access

From the VPS, read the standalone gateway token and check that the terminal route lists sessions:

MATRIX_TOKEN=$(sudo sed -n 's/^MATRIX_AUTH_TOKEN=//p' /opt/matrix/env/host.env)
matrix shell ls --gateway http://<server-ip>/cli --token "$MATRIX_TOKEN"

For laptop access, use the canonical commands in CLI access from your laptop. Browser login is for Matrix Cloud; standalone self-host CLI access currently uses this bearer token.

Using Your Self-hosted VPS

What works automatically

After the installer completes, the browser shell, gateway, code-server proxy, local Postgres, nginx, and the default main zellij shell session are started by systemd. You do not need to run extra commands for the web UI: open the printed URL, sign in with the generated nginx Basic Auth username and password, and use the shell.

The CLI and direct SSH workflows are different. They are power-user access paths and currently need the standalone bearer token or the Matrix owner environment.

CLI access from your laptop

Standalone self-host installs do not use the Matrix Cloud browser login flow yet. matrix login and Clerk device auth are for managed Matrix Cloud profiles. For self-host, point the CLI at the printed /cli gateway and pass the token from the VPS:

export MATRIX_GATEWAY="http://<server-ip>/cli"
export MATRIX_TOKEN="$(ssh root@<server-ip> 'sudo sed -n "s/^MATRIX_AUTH_TOKEN=//p" /opt/matrix/env/host.env')"

matrix shell ls --gateway "$MATRIX_GATEWAY" --token "$MATRIX_TOKEN"
matrix run --gateway "$MATRIX_GATEWAY" --token "$MATRIX_TOKEN" -- echo "hello from Matrix OS"

If you want to avoid repeating the gateway URL, save a local profile for the URL and keep passing the token explicitly:

matrix profile set selfhost \
  --platform "http://<server-ip>" \
  --gateway "http://<server-ip>/cli"

matrix shell ls --profile selfhost --token "$MATRIX_TOKEN"

Treat MATRIX_TOKEN like a password. It grants CLI access to the standalone gateway.

Zellij sessions over SSH

The web terminal and SSH can share the same zellij sessions when both run as the matrix user with the Matrix owner environment. Root's zellij sessions are separate.

From an SSH session as root, first switch to the owner user:

sudo -iu matrix

Then run these commands inside the new matrix shell:

source /opt/matrix/env/host.env
source /opt/matrix/bin/matrix-owner-env
matrix_export_owner_env
export TERM=xterm-256color

/opt/matrix/bin/zellij list-sessions
/opt/matrix/bin/zellij attach main

If you are already the matrix user, skip sudo -iu matrix. The matrix user is not a sudoer by default. If zellij is not found, use /opt/matrix/bin/zellij or run matrix_export_owner_env to put /opt/matrix/bin on PATH.

AI agent handoff prompt

If you install Claude Code, Codex, or another coding agent on the VPS, you can paste this prompt into the agent from the Matrix terminal or an SSH session. It asks the agent to verify the instance without leaking secrets:

You are helping me finish and verify a standalone Matrix OS self-host install on this Linux VPS.

Rules:
- Do not print secret values. Redact MATRIX_AUTH_TOKEN, MATRIX_CODE_PROXY_TOKEN, Postgres passwords, Basic Auth passwords, private keys, and cookies.
- Do not expose ports 3000, 4000, 8787, 8788, or 5432 publicly.
- Do not rotate credentials, edit nginx, install TLS, or change firewall rules without asking me first.
- Prefer read-only checks first, then propose the smallest safe fix if something is broken.

Tasks:
1. Inspect /opt/matrix/release.json or /opt/matrix/app/BUNDLE_VERSION and tell me the installed Matrix OS version.
2. Check systemd health for matrix-gateway, matrix-shell, matrix-code, matrix-code-server, matrix-restore, docker, and nginx.
3. Verify local HTTP health:
   - curl http://127.0.0.1/health
   - curl http://127.0.0.1:4000/health
4. Read MATRIX_AUTH_TOKEN from /opt/matrix/env/host.env without printing it, then verify:
   - curl -H "Authorization: Bearer <redacted>" http://127.0.0.1:4000/api/terminal/sessions
   - curl -H "Authorization: Bearer <redacted>" http://127.0.0.1/cli/api/terminal/sessions
5. Verify the matrix user shell environment:
   - source /opt/matrix/env/host.env
   - source /opt/matrix/bin/matrix-owner-env
   - matrix_export_owner_env
   - /opt/matrix/bin/zellij list-sessions
6. Tell me the exact browser URL, code-server URL, CLI gateway URL, and the commands I should run from my laptop. Keep tokens redacted and show placeholders.
7. If I provide a custom domain, explain the DNS/TLS/security changes needed before making them.
8. Summarize what works, what is risky, and what still needs manual setup for mobile or desktop login.

Security hardening

The preview installer is intentionally minimal: nginx Basic Auth protects the browser UI, the gateway and code-server stay loopback-only behind nginx, and /cli requires the bearer token. Before long-term use on the public internet:

  • Put the host behind HTTPS with DNS, Tailscale, Cloudflare Access/Tunnel, or another trusted edge.
  • Keep ports 3000, 4000, 8787, 8788, and 5432 closed to the public internet.
  • Rotate /opt/matrix/env/initial-ui-password and MATRIX_AUTH_TOKEN if either is exposed.
  • Back up /home/matrix/home, the local Postgres volume, and /opt/matrix/env.
  • Keep SSH limited to trusted keys and trusted networks.

IP-only installs are fine for first boot and private testing, but they are plain HTTP unless you add a TLS/access layer.

When rotating MATRIX_AUTH_TOKEN, update both the service env file and nginx's injected gateway-token include, then restart the affected services:

NEW_TOKEN="$(openssl rand -hex 32)"
sudo sed -i "s/^MATRIX_AUTH_TOKEN=.*/MATRIX_AUTH_TOKEN=${NEW_TOKEN}/" /opt/matrix/env/host.env
printf 'proxy_set_header Authorization "Bearer %s";\n' "$NEW_TOKEN" | sudo tee /opt/matrix/env/gateway-auth-token.conf >/dev/null
sudo chmod 0600 /opt/matrix/env/gateway-auth-token.conf
sudo chown root:root /opt/matrix/env/gateway-auth-token.conf
sudo systemctl restart matrix-gateway matrix-shell nginx

Mobile and desktop login

Managed Matrix Cloud mobile and desktop login will use platform auth and managed routing. Standalone self-host mobile/desktop login is not enabled yet.

The intended self-host direction is:

  • Use a custom domain with HTTPS for the self-hosted gateway.
  • Pair the mobile or desktop app to that domain.
  • Use the self-host owner token or a future standalone device flow instead of the Matrix Cloud Clerk tenant.

Until that lands, use the browser shell and CLI for self-hosted instances. Do not expect the managed app.matrix-os.com mobile/desktop handoff to discover an arbitrary self-hosted IP address.

What You Get

  • Matrix web shell on your VPS.
  • Gateway API and WebSocket services protected by an internal bearer token.
  • Local owner-controlled Postgres on 127.0.0.1.
  • code-server behind the Matrix code proxy at /code/.
  • Persistent home directory at /home/matrix/home.
  • Optional Claude Code, Codex, OpenCode, and Pi CLI installs through Matrix tool packs.
  • Source-free install from a verified host bundle.

What You Manage

  • DNS and TLS.
  • Server firewalling, OS updates, and SSH access.
  • Backups and restore policy.
  • Upgrades to newer Matrix host bundles.
  • Edge auth hardening beyond the generated nginx Basic Auth.
  • Any external integration secrets.

Differences From Matrix Cloud

CapabilityMatrix CloudSelf-host preview
ProvisioningManaged VPS creationBring your own VPS
AuthClerk and platform sessionsGenerated nginx Basic Auth
Routingapp.matrix-os.com and code.matrix-os.comYour domain or server IP
BackupsManaged platform pathYou configure backups
UpdatesPlatform release fan-outManual installer/update path
IntegrationsPlatform-owned PipedreamNot configured by default
Mobile and desktop handoffUpcoming managed surfacesNot included yet

Security Notes

The shell runs in explicit standalone mode. Public browser access is expected to go through nginx, while same-origin API, file, app, and WebSocket requests are rewritten by the shell proxy with the internal MATRIX_AUTH_TOKEN. code-server runs loopback-only and is reached through a token-protected Matrix proxy.

IP-only installs are acceptable for first boot and private-network testing, but they are plain HTTP unless you add a trusted TLS/access layer. For a public VPS, prefer DNS plus TLS, Tailscale, Cloudflare Access/Tunnel, or another authenticated reverse proxy before storing long-lived work there.

Do not expose ports 3000, 4000, 8787, 8788, or 5432 publicly. Keep them on loopback and expose only your hardened reverse proxy.

The installer leaves GET /health open at nginx and returns only {"ok":true} so basic uptime monitors can check the public edge without credentials or gateway details. For deeper checks, use systemd status or local-only gateway health from the server.

Manual Install Telemetry

The installer sends lightweight, best-effort telemetry to Matrix OS so we can see how many people choose the manual path, which release channel/version they reach, whether installs finish, and where failures happen. The endpoint has a bounded request body and short-window rate limits to keep the signal useful. It records an anonymous install id, channel, installed version, IP-vs-DNS mode, default-vs-custom bundle source, selected developer-tool count, phase, status, and exit code.

It does not send your Matrix handle, password, auth tokens, Postgres password, domain name, project files, shell output, or code-server URL. The website telemetry endpoint also asks PostHog to discard client IP by setting $ip to 0.0.0.0.

Opt out per install:

curl -fsSL https://matrix-os.com/install-server.sh | sudo MATRIX_NO_TELEMETRY=1 bash

Or disable only installer telemetry:

curl -fsSL https://matrix-os.com/install-server.sh | sudo MATRIX_INSTALL_TELEMETRY=0 bash

Next Steps

How is this guide?

On this page