Choose a scenario below. Each guide walks you through every step with real examples.
Get clean usernames like @user:example.com while the server runs at matrix.example.com. This uses .well-known delegation — Caddy handles it automatically.
Same as subdomain mode, plus one extra DNS record:
| What | Details |
|---|---|
| A VPS / server | Debian 13 (tested on 1 GB RAM / 1 CPU / 25 GB SSD — DigitalOcean $6/mo droplet). Not tested on other OS or specs |
| Root access | Either logged in as root, or a user with sudo |
| A domain name | Any domain you own (e.g., example.com) |
| DNS access | You'll need two A records — one for the root domain and one for the subdomain |
example.com) must also point to this server. If you already have a website at example.com, choose Option B during install (see Step 3).
Add both records to your DNS provider:
| Type | Name | Value | Why |
|---|---|---|---|
A | @ (root) | Your server IP | Serves .well-known delegation files |
A | matrix | Your server IP | Runs the actual Matrix server |
AAAA | @ (root) | IPv6 (if available) | Optional but recommended |
AAAA | matrix | IPv6 (if available) | Optional but recommended |
# Verify both records resolve dig example.com +short # → your server IP dig matrix.example.com +short # → your server IP
ssh root@your-server-ip curl -fsSL https://raw.githubusercontent.com/balnaimi/conduit-deploy/main/conduit-deploy.sh -o conduit-deploy.sh sudo bash conduit-deploy.sh
* How do you want your usernames to look? 1) Clean username — @user:example.com (server at matrix.example.com) 2) Subdomain only — @user:chat.example.com (simpler, no delegation) ⚠ This is permanent — you cannot change it later! Choose [1/2]: 1
Your domain name: example.com VPS public IP [203.0.113.10]: ↵ (press Enter to accept)
The script asks how you want to handle .well-known delegation:
* .well-known Delegation Your usernames will be @user:example.com but the server runs at matrix.example.com The root domain needs to tell clients where to find the server. A) Root domain (example.com) has NO existing website — Caddy handles it B) Root domain (example.com) has an existing website — I'll give you instructions Choose [A/B]: A
.well-known files on your root domain automatically. Best if this server is your only use for example.com. ✅ Tested.well-known JSON files to add to your existing web server. Use this if example.com already hosts a website elsewhere. ⚠️ Not fully tested yetSame as subdomain mode — defaults are fine for most setups:
| Setting | Default |
|---|---|
| Max upload size | 100 MB (enter number in MB only, max 1024) |
| Max media storage | 10 GB |
| Cached files idle expiry | 30 days |
| Cached files max age | 90 days |
| User files idle expiry | 365 days |
| Thumbnail storage | 1 GB |
Summary: Server name: example.com Usernames: @user:example.com Matrix URL: https://matrix.example.com VPS IP: 203.0.113.10 .well-known: Caddy (automatic) Start installation? [Y/n] Y
Installation takes about 5–10 minutes. The script will:
.well-known delegationexample.com and matrix.example.com═══ Create Your Admin Account ═══ ⚠ This is the ONLY admin account. The first account on the server automatically gets admin privileges. You'll use this account to manage everything from the Admin Room. Username: alice Password: ******** ✅ Account created: @alice:example.com ═══ You're All Set! 🎉 ═══ Server URL: https://matrix.example.com Server name: example.com Admin Account Username: @alice:example.com Role: Server Administrator Admin Room Commands (quick reference) Create user: @conduit:example.com create-user <name> <pass> List users: @conduit:example.com list-local-users Reset password: @conduit:example.com reset-password <user_id> <pass>
/opt/conduit/CREDENTIALS.txt. The script will ask if you want to delete it — say yes after saving the info. If you forget your password later, use Services → Password Recovery (no credentials file needed).
After install, verify that delegation is working:
# These should return JSON responses curl -s https://example.com/.well-known/matrix/server # → {"m.server": "matrix.example.com:443"} curl -s https://example.com/.well-known/matrix/client # → {"m.homeserver": {"base_url": "https://matrix.example.com"}}
@user:example.com, their client checks example.com/.well-known/matrix/server to find where the actual server is (matrix.example.com). Caddy serves these files automatically.
From the main menu, choose 3:
Services: ✅ conduit is running ✅ caddy is running ✅ coturn is running Connectivity: ✅ HTTPS working (matrix.example.com) ✅ Federation port 8448 working ✅ IPv6 working Security: ✅ firewalld active ✅ firewalld interface bound (eth0) ✅ firewalld masquerade enabled ✅ Docker internet access OK ✅ Fail2ban active ✅ SSH password auth disabled
The first account was created during installation. To add more users, log in to Element and find the Admin Room:
# In the Admin Room, type: @conduit:example.com create-user alice MySecurePass123! # Response: ✅ Account created: @alice:example.com
Notice the clean username: @alice:example.com — no "matrix" subdomain in the user ID! 🎉
See the Admin Room guide for all available commands (reset password, deactivate user, etc.).
Open any Matrix client (Element, SchildiChat, FluffyChat):
example.commatrix.example.com, users enter example.com as the homeserver. The client follows the .well-known redirect automatically.
.well-known delegation. Message anyone on matrix.org and it just works!
Before you start, make sure you have:
| What | Details |
|---|---|
| A VPS / server | Debian 13 (tested on 1 GB RAM / 1 CPU / 25 GB SSD — DigitalOcean $6/mo droplet). Not tested on other OS or specs |
| Root access | Either logged in as root, or a user with sudo |
| A domain name | Any domain you own (e.g., example.com). You'll create a subdomain like matrix.example.com |
| DNS access | Ability to add DNS records (A and AAAA) at your domain registrar or DNS provider |
@user:matrix.example.com.
Go to your DNS provider and add these records pointing to your server's IP address:
| Type | Name | Value | TTL |
|---|---|---|---|
A | matrix | Your server's IPv4 (e.g. 203.0.113.10) | 3600 |
AAAA | matrix | Your server's IPv6 (if available) | 3600 |
dig matrix.example.com +short
SSH into your server and run the script:
# SSH into your server ssh root@your-server-ip # Download and run the installer curl -fsSL https://raw.githubusercontent.com/balnaimi/conduit-deploy/main/conduit-deploy.sh -o conduit-deploy.sh sudo bash conduit-deploy.sh
* How do you want your usernames to look? 1) Clean username — @user:example.com (server at matrix.example.com) 2) Subdomain only — @user:matrix.example.com (simpler, no delegation) Choose [1/2]: 2
Your domain name: example.com Subdomain for the server [matrix]: matrix VPS public IP [203.0.113.10]: ↵ (press Enter to accept)
example.com), not the full address.
The defaults are good for most setups — just press Enter to accept each one:
| Setting | Default | What It Means |
|---|---|---|
| Max upload size | 100 MB | Largest file a user can send (enter MB only, max 1024) |
| Max media storage | 10 GB | Total space for all files (auto-cleans oldest) |
| Cached files idle expiry | 30 days | Delete cached federation files after 30 days idle |
| Cached files max age | 90 days | Hard limit for cached federation files |
| User files idle expiry | 365 days | Delete user uploads after 1 year idle |
| Thumbnail storage | 1 GB | Auto-generated image previews |
Summary: Server name: matrix.example.com Usernames: @user:matrix.example.com Matrix URL: https://matrix.example.com VPS IP: 203.0.113.10 .well-known: Not needed (subdomain mode) Start installation? [Y/n] Y
The installer will:
═══ Create Your Admin Account ═══ ⚠ This is the ONLY admin account. Username: alice Password: ******** ✅ Account created: @alice:matrix.example.com ═══ You're All Set! 🎉 ═══ Admin Account Username: @alice:matrix.example.com Role: Server Administrator Forgot your password? Run this script again → Services → Password Recovery
/opt/conduit/CREDENTIALS.txt. Delete the file after saving your info! If you forget your password, use Services → Password Recovery. See the Admin Room guide for managing users.
From the main menu, choose 3 (Health Check):
Services: ✅ conduit is running ✅ caddy is running ✅ coturn is running Connectivity: ✅ HTTPS working (matrix.example.com) ✅ Federation port 8448 working ✅ IPv6 working Security: ✅ firewalld active ✅ firewalld interface bound (eth0) ✅ firewalld masquerade enabled ✅ Docker internet access OK ✅ Fail2ban active ✅ SSH password auth disabled TLS Certificates: ✅ Coturn TLS cert valid (89 days left) ✅ TLS auto-sync watcher active Resources: ✅ Disk: 4.1G used / 20G free ✅ RAM: 442Mi / 967Mi Registration: ✅ Registration is CLOSED
The first account was created during installation. To add more users, log in to Element and find the Admin Room:
# In the Admin Room, type: @conduit:matrix.example.com create-user alice MySecurePass123! # Response: ✅ Account created: @alice:matrix.example.com
See the Admin Room guide for all available commands.
| Client | Platforms | Link |
|---|---|---|
| Element | Web, Desktop, iOS, Android | element.io |
| SchildiChat | Desktop, iOS, Android | schildi.chat |
| FluffyChat | iOS, Android, Linux | fluffychat.im |
matrix.example.commatrix.org — it just works!
| Component | What It Contains |
|---|---|
| Database | All rooms, messages, user accounts, encryption keys (exported from Docker volume) |
| Media files | Images, videos, documents uploaded by users (optional — can be excluded) |
| Configuration | .env, docker-compose.yml, conduit.toml, Caddyfile, turnserver.conf |
| TLS certificates | Let's Encrypt certs and Caddy data (exported from Docker volume) |
| Secrets | Registration token, TURN secret |
| Pinned image versions | SHA256 digests of the exact Docker images that were running |
/opt/conduit/ ← Your live installation (database, config, media) /opt/conduit-backups/ ← Your backups (separate — survives uninstall!)
From the main menu: 5 (Services) → 7 (Backup with version pinning)
# The script checks disk space (includes Docker volume sizes) ✅ Disk space OK (need ~84MB, have 19604MB free) # If you have 3+ old backups, it offers cleanup ⚠ You have 3 old backups in /opt/conduit-backups/ Delete old backups? Keep only the latest 2. [y/N]: y ✅ Deleted: conduit-backup-2026-03-15-082818.tar.gz # Saves the exact Docker image versions ═══ Saving current image versions ═══ ✅ conduit: matrixconduit/matrix-conduit:latest → 4078e80577cc ✅ caddy: caddy:2-alpine → fce4f15aad23 ✅ coturn: coturn/coturn:alpine → 229f87ef2428 # Exports database and certificates from Docker volumes ℹ Exporting database and certificates from Docker volumes... ✅ Database exported ✅ TLS certificates exported # If you have media files, you can choose to include or exclude them Media files: 30M Media includes user uploads (images, videos, documents) and cached federation files. Include media files in backup? [Y/n]: y # Creates the backup ℹ Creating backup... ✅ Backup saved: conduit-backup-2026-03-16-022313.tar.gz (30M)
n to skip media files for a much smaller backup. Accounts and messages are always saved. No-media backups get a -no-media suffix.
When you restore, the script pulls the exact same Docker images (by SHA256 digest) that were running when the backup was taken:
For extra safety, keep a copy on your local machine:
# From your local machine (not the server)
scp root@your-server:/opt/conduit-backups/conduit-backup-*.tar.gz ~/backups/
Something broke after an update, configuration change, or you just want to roll back to a known good state. Your server is the same machine — you just want to go back in time.
ssh root@your-server bash conduit-deploy.sh
From the main menu: 5 (Services) → 8 (Restore from backup)
═══ Restore from Backup ═══ Backups are stored in: /opt/conduit-backups/ Available backups: conduit-backup-2026-03-15-180609.tar.gz conduit-backup-2026-03-15-145926.tar.gz Backup file path: /opt/conduit-backups/conduit-backup-2026-03-15-180609.tar.gz
⛔ WARNING: This will replace your current installation! All current data, accounts, and messages will be overwritten. Type 'RESTORE' to confirm: RESTORE ℹ Restoring from backup... ✅ Files restored # Imports database and certificates into Docker volumes ℹ Importing database from backup... ✅ Database imported ✅ TLS certificates imported ═══ Restoring pinned image versions ═══ Pulling the exact same images that were running at backup time. ✅ conduit ✅ caddy ✅ coturn ℹ Starting services... ✅ Restore complete! Services are running. # Re-creates infrastructure (firewall, TLS sync) ✅ Firewall rules verified ✅ TLS cert auto-sync restored ✅ UDP redirect rule restored
Run a Health Check (3) to confirm everything is working. All your accounts, messages, and rooms should be exactly as they were when the backup was taken.
Restore brings you back to the exact software versions from the backup (pinned by SHA256 digest). But your server isn't frozen there — after verifying everything works, you can update normally:
# After restore, update to latest versions anytime:
Menu → Services → Update containers (pull latest)
The pinning only applies during the restore itself — to give you a known-good starting point. After that, your server works like any other and you control when to update.
Moving to a bigger VPS, switching providers, or setting up a disaster recovery server. Everything transfers: accounts, messages, rooms, media, and settings.
On your current/old server, create a fresh backup:
# On the old server bash conduit-deploy.sh # Menu: 5 (Services) → 7 (Backup)
# From your local machine — download from old, upload to new scp root@old-server:/opt/conduit-backups/conduit-backup-*.tar.gz /tmp/ # Upload to the new server ssh root@new-server "mkdir -p /opt/conduit-backups" scp /tmp/conduit-backup-*.tar.gz root@new-server:/opt/conduit-backups/
scp root@old-server:/opt/conduit-backups/*.tar.gz root@new-server:/opt/conduit-backups/
Point your domain to the new server's IP address:
| Type | Name | New Value |
|---|---|---|
A | matrix (or your subdomain) | New server's IPv4 |
AAAA | matrix (or your subdomain) | New server's IPv6 |
# Verify DNS points to the new server dig matrix.example.com +short # Should return the NEW server's IP
ssh root@new-server curl -sL https://raw.githubusercontent.com/balnaimi/conduit-deploy/main/conduit-deploy.sh -o conduit-deploy.sh chmod +x conduit-deploy.sh bash conduit-deploy.sh
The script detects Conduit is not installed. Go to 5 (Services) — only Restore is available:
═══ Service Management ═══ Conduit is not installed. Only restore is available. 8) Restore from backup 0) Back to main menu Choose: 8
Select your backup file and confirm:
Type 'RESTORE' to confirm: RESTORE ℹ Restoring from backup... ✅ Files restored ✅ Database imported ✅ TLS certificates imported ✅ conduit, caddy, coturn pulled ℹ Starting services... ✅ Restore complete! Services are running. ✅ Firewall rules verified ✅ TLS cert auto-sync restored ✅ UDP redirect rule restored
Run Health Check (3) on the new server:
# On the OLD server — stop services bash conduit-deploy.sh # Menu: 5 → 2 (Stop all services) # Or: Menu: 6 (Uninstall) to remove everything
/opt/conduit-backups/)dig matrix.example.com +short)