Fix deploy.sh directory creation and add multi-machine deployment guide
Deploy Script Fix: - Add Step 1.5: Create directory structure before config generation - Fixes "No such file or directory" error when writing configs - Creates authelia/config, mas/config, element/config, etc. - Ensures all required directories exist before deploy starts Multi-Machine Configuration Guide: - New file: MULTI_MACHINE_CONFIG_SNIPPETS.md (750+ lines) - Complete guide for 3-machine deployment architecture - All services accessible on standard HTTPS port 443 Architecture: - Machine 1: Caddy (SSL termination) - matrix, auth, element domains - Machine 2: Authelia (SSO with own reverse proxy) - authelia domain - Machine 3: Matrix Stack (Synapse, MAS, Element, PostgreSQL) Key Features: - Step-by-step deployment workflow (6 phases) - Explains how to generate and extract secrets from deploy.sh - Simple copy-paste method: scp generated configs to servers - Complete Authelia config with port 443 reverse proxy examples - Complete Caddy config for Matrix/MAS/Element proxying - DNS configuration guide - Validation checklist - Troubleshooting section Authelia Integration: - Authelia behind its own reverse proxy (Caddy/Nginx) on port 443 - MAS uses correct discovery_url: https://authelia.example.com - OAuth2 client secrets and hashes all generated by deploy.sh - Config files have secrets pre-embedded for easy deployment Validated: - Production deployment tested - Directory creation works correctly - Config files generated successfully - Discovery URL uses HTTPS domain in production mode 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,801 @@
|
||||
# Multi-Machine Configuration Snippets
|
||||
|
||||
This document provides configuration snippets for deploying Matrix stack across multiple machines where Authelia and Caddy are running on separate servers.
|
||||
|
||||
## Key Points
|
||||
|
||||
✅ **All services accessible on standard HTTPS port 443**
|
||||
✅ **Authelia has its own reverse proxy on Machine 2**
|
||||
✅ **MAS connects to Authelia via HTTPS (not internal port 9091)**
|
||||
✅ **DNS points authelia.example.com directly to Machine 2**
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
Machine 1: Caddy (SSL Termination) → Port 443 (matrix, auth, element domains)
|
||||
Machine 2: Authelia (SSO) → Port 443 (authelia domain, with own reverse proxy)
|
||||
Machine 3: Matrix Stack (this machine) → Synapse, MAS, Element, PostgreSQL (internal ports)
|
||||
```
|
||||
|
||||
**Network Flow**:
|
||||
- User → `https://matrix.example.com` → Caddy (Machine 1) → Synapse (Machine 3:8008)
|
||||
- User → `https://auth.example.com` → Caddy (Machine 1) → MAS (Machine 3:8080)
|
||||
- User → `https://authelia.example.com` → Authelia's reverse proxy (Machine 2) → Authelia (Machine 2:9091)
|
||||
- MAS → `https://authelia.example.com` → Authelia's reverse proxy (Machine 2) → Authelia (Machine 2:9091)
|
||||
|
||||
## Prerequisites - Generate Secrets First!
|
||||
|
||||
**IMPORTANT**: Before you can configure Authelia and Caddy, you must run the deploy script on the Matrix server to generate all secrets.
|
||||
|
||||
### Step 1: Generate Secrets on Matrix Server (Machine 3)
|
||||
|
||||
```bash
|
||||
# On Matrix server
|
||||
cd /path/to/matrix-docker-compose
|
||||
./deploy.sh
|
||||
|
||||
# Choose:
|
||||
# - Deployment: Production
|
||||
# - Authelia: Yes
|
||||
# - Enter your domain, IPs, email
|
||||
```
|
||||
|
||||
The script will:
|
||||
1. Generate all secure secrets (passwords, keys, tokens)
|
||||
2. Create `.env` file with secrets
|
||||
3. Create configuration files with secrets embedded
|
||||
4. Display the admin password (SAVE THIS!)
|
||||
|
||||
### Step 2: Extract Secrets from Generated Files
|
||||
|
||||
After deploy.sh completes, you'll have these files with embedded secrets:
|
||||
|
||||
```bash
|
||||
# On Matrix server
|
||||
ls -la authelia/config/configuration.yml # Authelia config with secrets
|
||||
ls -la mas/config/config.yaml # MAS config with CLIENT_SECRET_PLAIN
|
||||
ls -la .env # All environment variables
|
||||
ls -la authelia_private.pem # RSA key for Authelia
|
||||
```
|
||||
|
||||
### Step 3: Copy Secrets to Your Separate Servers
|
||||
|
||||
Now extract the secrets and copy them to the appropriate machines.
|
||||
|
||||
---
|
||||
|
||||
## How to Extract Secrets
|
||||
|
||||
On the Matrix server after running deploy.sh:
|
||||
|
||||
### Extract from `.env` file:
|
||||
|
||||
```bash
|
||||
# On Matrix server
|
||||
cat .env
|
||||
|
||||
# You'll see these values (copy them):
|
||||
POSTGRES_PASSWORD=...
|
||||
AUTHELIA_JWT_SECRET=...
|
||||
AUTHELIA_SESSION_SECRET=...
|
||||
AUTHELIA_STORAGE_ENCRYPTION_KEY=...
|
||||
```
|
||||
|
||||
### Extract CLIENT_SECRET_PLAIN from MAS config:
|
||||
|
||||
```bash
|
||||
# On Matrix server
|
||||
grep "client_secret:" mas/config/config.yaml | grep -v "#"
|
||||
|
||||
# Output will show:
|
||||
# client_secret: 'YOUR_CLIENT_SECRET_PLAIN'
|
||||
# Copy this value - you'll need it for Authelia config
|
||||
```
|
||||
|
||||
### Get CLIENT_SECRET_HASH for Authelia:
|
||||
|
||||
```bash
|
||||
# On Matrix server
|
||||
grep "client_secret:" authelia/config/configuration.yml | grep -v "#"
|
||||
|
||||
# Output will show:
|
||||
# client_secret: '$pbkdf2-sha512$310000$...'
|
||||
# Copy this hash - it's the hashed version of CLIENT_SECRET_PLAIN
|
||||
```
|
||||
|
||||
### Get RSA Private Key:
|
||||
|
||||
```bash
|
||||
# On Matrix server
|
||||
cat authelia_private.pem
|
||||
|
||||
# Copy the entire key including:
|
||||
# -----BEGIN RSA PRIVATE KEY-----
|
||||
# ...
|
||||
# -----END RSA PRIVATE KEY-----
|
||||
```
|
||||
|
||||
### Get Admin Password Hash:
|
||||
|
||||
```bash
|
||||
# On Matrix server
|
||||
grep "password:" authelia/config/users_database.yml | grep -v "#"
|
||||
|
||||
# Output will show:
|
||||
# password: "$argon2id$v=19$m=65536,t=3,p=4$..."
|
||||
# Copy this hash
|
||||
```
|
||||
|
||||
### Admin Password (Plain Text):
|
||||
|
||||
The deploy script displays this once. Example output:
|
||||
```
|
||||
⚠ Default admin password: 58XiX7kLoRjqApEKB2GeQJJotLYHXmI7 (SAVE THIS!)
|
||||
```
|
||||
|
||||
**SAVE THIS PASSWORD** - you'll need it to log into Authelia!
|
||||
|
||||
---
|
||||
|
||||
## Simple Copy-Paste Method
|
||||
|
||||
Instead of manually copying values, just copy the entire generated configs:
|
||||
|
||||
```bash
|
||||
# On Matrix server
|
||||
|
||||
# Copy Authelia config to Machine 2
|
||||
scp authelia/config/configuration.yml user@authelia-server:/tmp/
|
||||
scp authelia/config/users_database.yml user@authelia-server:/tmp/
|
||||
|
||||
# Then on Authelia server, move to proper location:
|
||||
sudo mv /tmp/configuration.yml /etc/authelia/
|
||||
sudo mv /tmp/users_database.yml /etc/authelia/
|
||||
```
|
||||
|
||||
This way all secrets are already embedded!
|
||||
|
||||
---
|
||||
|
||||
## Configuration for Authelia Server (Machine 2)
|
||||
|
||||
**Note**: Authelia should be behind your own reverse proxy (Nginx, Caddy, etc.) on port 443 with proper HTTPS certificates. The configuration below shows Authelia's internal config.
|
||||
|
||||
### File: `/etc/authelia/configuration.yml`
|
||||
|
||||
```yaml
|
||||
---
|
||||
# Authelia Configuration for Matrix Stack
|
||||
# Machine: Authelia Server
|
||||
# Note: This should be behind a reverse proxy handling HTTPS on port 443
|
||||
|
||||
theme: auto
|
||||
|
||||
server:
|
||||
address: 'tcp://0.0.0.0:9091' # Internal port, reverse proxy forwards to this
|
||||
|
||||
log:
|
||||
level: 'info'
|
||||
format: 'text'
|
||||
|
||||
authentication_backend:
|
||||
file:
|
||||
path: '/config/users_database.yml'
|
||||
password:
|
||||
algorithm: 'argon2'
|
||||
argon2:
|
||||
variant: 'argon2id'
|
||||
iterations: 3
|
||||
memory: 65536
|
||||
parallelism: 4
|
||||
key_length: 32
|
||||
salt_length: 16
|
||||
|
||||
session:
|
||||
secret: 'YOUR_AUTHELIA_SESSION_SECRET'
|
||||
cookies:
|
||||
- domain: 'example.com' # Your base domain
|
||||
authelia_url: 'https://authelia.example.com'
|
||||
default_redirection_url: 'https://element.example.com'
|
||||
|
||||
redis:
|
||||
host: 'redis' # Adjust if Redis is elsewhere
|
||||
port: 6379
|
||||
|
||||
storage:
|
||||
encryption_key: 'YOUR_AUTHELIA_STORAGE_ENCRYPTION_KEY'
|
||||
postgres:
|
||||
address: 'tcp://postgres:5432' # Adjust to your PostgreSQL location
|
||||
database: 'authelia'
|
||||
username: 'synapse'
|
||||
password: 'YOUR_POSTGRES_PASSWORD'
|
||||
|
||||
notifier:
|
||||
filesystem:
|
||||
filename: '/config/notification.txt'
|
||||
|
||||
identity_validation:
|
||||
reset_password:
|
||||
jwt_secret: 'YOUR_AUTHELIA_JWT_SECRET'
|
||||
|
||||
access_control:
|
||||
default_policy: 'deny'
|
||||
rules:
|
||||
- domain:
|
||||
- 'matrix.example.com'
|
||||
policy: 'two_factor'
|
||||
- domain:
|
||||
- 'element.example.com'
|
||||
policy: 'two_factor'
|
||||
|
||||
identity_providers:
|
||||
oidc:
|
||||
hmac_secret: 'YOUR_AUTHELIA_JWT_SECRET'
|
||||
jwks:
|
||||
- key_id: 'main'
|
||||
algorithm: 'RS256'
|
||||
use: 'sig'
|
||||
key: |
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
YOUR_RSA_PRIVATE_KEY_HERE
|
||||
(paste content of authelia_private.pem)
|
||||
-----END RSA PRIVATE KEY-----
|
||||
clients:
|
||||
- client_id: 'mas-client'
|
||||
client_name: 'Matrix Authentication Service'
|
||||
client_secret: 'YOUR_CLIENT_SECRET_HASH' # pbkdf2-sha512 hash
|
||||
public: false
|
||||
authorization_policy: 'two_factor' # Require 2FA
|
||||
redirect_uris:
|
||||
- 'https://auth.example.com/oauth2/callback'
|
||||
scopes:
|
||||
- 'openid'
|
||||
- 'profile'
|
||||
- 'email'
|
||||
- 'offline_access'
|
||||
grant_types:
|
||||
- 'authorization_code'
|
||||
- 'refresh_token'
|
||||
response_types:
|
||||
- 'code'
|
||||
token_endpoint_auth_method: 'client_secret_basic'
|
||||
```
|
||||
|
||||
### File: `/etc/authelia/users_database.yml`
|
||||
|
||||
```yaml
|
||||
---
|
||||
users:
|
||||
admin:
|
||||
displayname: "Administrator"
|
||||
password: "YOUR_ADMIN_PASSWORD_HASH" # argon2 hash
|
||||
email: admin@example.com
|
||||
groups:
|
||||
- admins
|
||||
```
|
||||
|
||||
### Authelia Reverse Proxy Configuration (Machine 2)
|
||||
|
||||
Since Authelia should be accessible on port 443, you need a reverse proxy on Machine 2. Example with Caddy:
|
||||
|
||||
**File: `/etc/caddy/Caddyfile` (on Authelia server)**
|
||||
|
||||
```caddy
|
||||
{
|
||||
email YOUR_LETSENCRYPT_EMAIL
|
||||
}
|
||||
|
||||
authelia.example.com:443 {
|
||||
reverse_proxy localhost:9091
|
||||
}
|
||||
```
|
||||
|
||||
Or with Nginx:
|
||||
|
||||
**File: `/etc/nginx/sites-available/authelia` (on Authelia server)**
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
server_name authelia.example.com;
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/authelia.example.com/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/authelia.example.com/privkey.pem;
|
||||
|
||||
location / {
|
||||
proxy_pass http://localhost:9091;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Configuration for Caddy Server (Machine 1)
|
||||
|
||||
### File: `/etc/caddy/Caddyfile`
|
||||
|
||||
```caddy
|
||||
# Caddy Configuration for Matrix Stack (Production)
|
||||
# Machine: Caddy SSL Termination Server
|
||||
{
|
||||
admin 0.0.0.0:2019
|
||||
email YOUR_LETSENCRYPT_EMAIL
|
||||
}
|
||||
|
||||
# Matrix Homeserver (Synapse)
|
||||
matrix.example.com:443 {
|
||||
# Well-known client endpoint
|
||||
@wk path /.well-known/matrix/client
|
||||
handle @wk {
|
||||
header Content-Type application/json
|
||||
respond `{"m.homeserver":{"base_url":"https://matrix.example.com"},"m.authentication":{"issuer":"https://auth.example.com/"}}` 200
|
||||
}
|
||||
|
||||
# Well-known server endpoint (federation)
|
||||
@wk_server path /.well-known/matrix/server
|
||||
handle @wk_server {
|
||||
header Content-Type application/json
|
||||
respond `{"m.server":"matrix.example.com:443"}` 200
|
||||
}
|
||||
|
||||
# Client versions endpoint with CORS
|
||||
@versions path /_matrix/client/versions
|
||||
handle @versions {
|
||||
header Access-Control-Allow-Origin "*"
|
||||
header Access-Control-Allow-Methods "GET, OPTIONS"
|
||||
header Access-Control-Allow-Headers "Authorization, Content-Type, Accept"
|
||||
header Vary "Origin, Access-Control-Request-Method, Access-Control-Request-Headers"
|
||||
reverse_proxy 10.0.1.10:8008 { # Matrix server IP
|
||||
header_down -Access-Control-Allow-Origin
|
||||
header_down -Access-Control-Allow-Methods
|
||||
header_down -Access-Control-Allow-Headers
|
||||
header_down -Vary
|
||||
}
|
||||
}
|
||||
|
||||
# CORS preflight for auth metadata
|
||||
@auth_preflight {
|
||||
method OPTIONS
|
||||
path /_matrix/client/unstable/org.matrix.msc2965/auth_metadata
|
||||
}
|
||||
handle @auth_preflight {
|
||||
header Access-Control-Allow-Origin "*"
|
||||
header Access-Control-Allow-Methods "GET, OPTIONS"
|
||||
header Access-Control-Allow-Headers "Authorization, Content-Type, Accept"
|
||||
header Access-Control-Max-Age "86400"
|
||||
respond 204
|
||||
}
|
||||
|
||||
# CORS preflight for all Matrix API
|
||||
@preflight {
|
||||
method OPTIONS
|
||||
path_regexp matrix ^/_matrix/.*$
|
||||
}
|
||||
handle @preflight {
|
||||
header Access-Control-Allow-Origin "*"
|
||||
header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
|
||||
header Access-Control-Allow-Headers "Authorization, Content-Type, Accept"
|
||||
header Access-Control-Max-Age "86400"
|
||||
respond 204
|
||||
}
|
||||
|
||||
# MAS compat endpoints (login/logout/refresh) with CORS
|
||||
@compat path \
|
||||
/_matrix/client/v3/login* \
|
||||
/_matrix/client/v3/logout* \
|
||||
/_matrix/client/v3/refresh* \
|
||||
/_matrix/client/r0/login* \
|
||||
/_matrix/client/r0/logout* \
|
||||
/_matrix/client/r0/refresh*
|
||||
handle @compat {
|
||||
header Access-Control-Allow-Origin "*"
|
||||
header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
|
||||
header Access-Control-Allow-Headers "Authorization, Content-Type, Accept"
|
||||
header Vary "Origin, Access-Control-Request-Method, Access-Control-Request-Headers"
|
||||
reverse_proxy 10.0.1.10:8080 { # Matrix server IP (MAS port)
|
||||
header_down -Access-Control-Allow-Origin
|
||||
header_down -Access-Control-Allow-Methods
|
||||
header_down -Access-Control-Allow-Headers
|
||||
header_down -Vary
|
||||
}
|
||||
}
|
||||
|
||||
# Everything else under /_matrix → Synapse with CORS
|
||||
@matrix_rest path_regexp matrix ^/_matrix/.*$
|
||||
handle @matrix_rest {
|
||||
header Access-Control-Allow-Origin "*"
|
||||
header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
|
||||
header Access-Control-Allow-Headers "Authorization, Content-Type, Accept"
|
||||
header Vary "Origin, Access-Control-Request-Method, Access-Control-Request-Headers"
|
||||
reverse_proxy 10.0.1.10:8008 { # Matrix server IP
|
||||
header_down -Access-Control-Allow-Origin
|
||||
header_down -Access-Control-Allow-Methods
|
||||
header_down -Access-Control-Allow-Headers
|
||||
header_down -Vary
|
||||
}
|
||||
}
|
||||
|
||||
# Federation endpoint
|
||||
handle /_matrix/federation/* {
|
||||
reverse_proxy 10.0.1.10:8008 # Matrix server IP
|
||||
}
|
||||
|
||||
# Default: everything else → Synapse
|
||||
handle {
|
||||
reverse_proxy 10.0.1.10:8008 # Matrix server IP
|
||||
}
|
||||
}
|
||||
|
||||
# Matrix Authentication Service (MAS)
|
||||
auth.example.com:443 {
|
||||
# OIDC Discovery
|
||||
@disco path /.well-known/openid-configuration
|
||||
handle @disco {
|
||||
header ?Access-Control-Allow-Origin "*"
|
||||
header ?Access-Control-Allow-Methods "GET, OPTIONS"
|
||||
header ?Access-Control-Allow-Headers "*"
|
||||
reverse_proxy 10.0.1.10:8080 # Matrix server IP (MAS)
|
||||
}
|
||||
|
||||
# Dynamic Client Registration: CORS preflight
|
||||
@reg_opts {
|
||||
method OPTIONS
|
||||
path /oauth2/registration
|
||||
}
|
||||
handle @reg_opts {
|
||||
header ?Access-Control-Allow-Origin "*"
|
||||
header ?Access-Control-Allow-Methods "POST, OPTIONS"
|
||||
header ?Access-Control-Allow-Headers "*"
|
||||
respond 204
|
||||
}
|
||||
|
||||
# Dynamic Client Registration (POST)
|
||||
@reg path /oauth2/registration
|
||||
route @reg {
|
||||
header ?Access-Control-Allow-Origin "*"
|
||||
header ?Access-Control-Allow-Methods "POST, OPTIONS"
|
||||
header ?Access-Control-Allow-Headers "*"
|
||||
reverse_proxy 10.0.1.10:8080 # Matrix server IP (MAS)
|
||||
}
|
||||
|
||||
# JWKS preflight
|
||||
@jwks_opts {
|
||||
method OPTIONS
|
||||
path /oauth2/keys.json
|
||||
}
|
||||
handle @jwks_opts {
|
||||
header ?Access-Control-Allow-Origin "*"
|
||||
header ?Access-Control-Allow-Methods "GET, OPTIONS"
|
||||
header ?Access-Control-Allow-Headers "*"
|
||||
respond 204
|
||||
}
|
||||
|
||||
# Map keys.json → /oauth2/jwks
|
||||
@jwksjson path /oauth2/keys.json
|
||||
route @jwksjson {
|
||||
header ?Access-Control-Allow-Origin "*"
|
||||
header ?Access-Control-Allow-Methods "GET, OPTIONS"
|
||||
header ?Access-Control-Allow-Headers "*"
|
||||
uri replace /oauth2/keys.json /oauth2/jwks
|
||||
reverse_proxy 10.0.1.10:8080 # Matrix server IP (MAS)
|
||||
}
|
||||
|
||||
# Generic OAuth2 endpoints
|
||||
@oauth path /oauth2/*
|
||||
route @oauth {
|
||||
header ?Access-Control-Allow-Origin "*"
|
||||
header ?Access-Control-Allow-Methods "GET, OPTIONS, POST"
|
||||
header ?Access-Control-Allow-Headers "*"
|
||||
reverse_proxy 10.0.1.10:8080 # Matrix server IP (MAS)
|
||||
}
|
||||
|
||||
# Account portal
|
||||
handle_path /account/* {
|
||||
reverse_proxy 10.0.1.10:8080 # Matrix server IP (MAS)
|
||||
}
|
||||
|
||||
# Authelia endpoints (proxy to Authelia server via HTTPS)
|
||||
handle_path /authelia/* {
|
||||
reverse_proxy https://authelia.example.com {
|
||||
header_up Host {upstream_hostport}
|
||||
}
|
||||
}
|
||||
|
||||
# Fallback: everything else to MAS
|
||||
handle {
|
||||
reverse_proxy 10.0.1.10:8080 # Matrix server IP (MAS)
|
||||
}
|
||||
|
||||
# Add CORS on error responses
|
||||
handle_errors {
|
||||
header ?Access-Control-Allow-Origin "*"
|
||||
header ?Access-Control-Allow-Headers "*"
|
||||
header ?Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
|
||||
}
|
||||
}
|
||||
|
||||
# Authelia SSO
|
||||
# Note: If Authelia runs on its own machine (Machine 2) with its own reverse proxy,
|
||||
# DNS for authelia.example.com should point directly to Machine 2.
|
||||
# This section is NOT needed on Caddy Machine 1. Remove this block.
|
||||
#
|
||||
# authelia.example.com:443 {
|
||||
# # Not needed - handled by Authelia's own reverse proxy on Machine 2
|
||||
# }
|
||||
|
||||
# Element Web Client
|
||||
element.example.com:443 {
|
||||
# Serve config.json with proper settings
|
||||
@cfg path /config.json
|
||||
handle @cfg {
|
||||
header Content-Type application/json
|
||||
header Cache-Control no-store
|
||||
respond `{
|
||||
"default_server_config": {
|
||||
"m.homeserver": {
|
||||
"base_url": "https://matrix.example.com",
|
||||
"server_name": "matrix.example.com"
|
||||
}
|
||||
},
|
||||
"default_server_name": "matrix.example.com",
|
||||
"disable_custom_urls": false,
|
||||
"disable_guests": true,
|
||||
"features": {
|
||||
"feature_oidc_aware_navigation": true
|
||||
}
|
||||
}` 200
|
||||
}
|
||||
|
||||
# Everything else to Element container
|
||||
handle {
|
||||
reverse_proxy 10.0.1.10:80 # Matrix server IP (Element port)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Important**: Replace all IP addresses (10.0.1.10, 10.0.1.20) with your actual server IPs.
|
||||
|
||||
---
|
||||
|
||||
## DNS Configuration
|
||||
|
||||
Configure your DNS records to point to the correct servers:
|
||||
|
||||
```
|
||||
matrix.example.com A/AAAA → Caddy Server IP (Machine 1)
|
||||
element.example.com A/AAAA → Caddy Server IP (Machine 1)
|
||||
auth.example.com A/AAAA → Caddy Server IP (Machine 1)
|
||||
authelia.example.com A/AAAA → Authelia Server IP (Machine 2)
|
||||
```
|
||||
|
||||
**Important**:
|
||||
- Caddy (Machine 1) handles Matrix, Element, and MAS (auth) endpoints
|
||||
- Authelia (Machine 2) handles its own domain with its own reverse proxy
|
||||
- Matrix server (Machine 3) is not directly accessible from internet
|
||||
|
||||
---
|
||||
|
||||
## Deployment Steps - Complete Workflow
|
||||
|
||||
### Phase 1: Generate Configs on Matrix Server (Machine 3)
|
||||
|
||||
```bash
|
||||
# On Matrix server
|
||||
cd /path/to/matrix-docker-compose
|
||||
./deploy.sh
|
||||
|
||||
# Choose:
|
||||
# - Deployment type: Production
|
||||
# - Include Authelia: Yes
|
||||
# - Domain: example.com
|
||||
# - Matrix server IP: 10.0.1.10 (this machine)
|
||||
# - Authelia server IP: 10.0.1.20 (Authelia machine)
|
||||
# - Email: your-email@example.com
|
||||
|
||||
# SAVE THE ADMIN PASSWORD shown at the end!
|
||||
```
|
||||
|
||||
After completion, you'll have:
|
||||
- `authelia/config/configuration.yml` ← Copy to Authelia server
|
||||
- `authelia/config/users_database.yml` ← Copy to Authelia server
|
||||
- `mas/config/config.yaml` ← Already has correct discovery_url
|
||||
- `.env` ← All secrets stored here
|
||||
|
||||
### Phase 2: Deploy Authelia (Machine 2)
|
||||
|
||||
```bash
|
||||
# Copy configs from Matrix server to Authelia server
|
||||
scp authelia/config/configuration.yml user@10.0.1.20:/tmp/
|
||||
scp authelia/config/users_database.yml user@10.0.1.20:/tmp/
|
||||
|
||||
# On Authelia server
|
||||
sudo mkdir -p /etc/authelia
|
||||
sudo mv /tmp/configuration.yml /etc/authelia/
|
||||
sudo mv /tmp/users_database.yml /etc/authelia/
|
||||
|
||||
# Set up reverse proxy (Caddy example)
|
||||
sudo tee /etc/caddy/Caddyfile << 'EOF'
|
||||
{
|
||||
email your-email@example.com
|
||||
}
|
||||
|
||||
authelia.example.com:443 {
|
||||
reverse_proxy localhost:9091
|
||||
}
|
||||
EOF
|
||||
|
||||
# Start/reload Caddy
|
||||
sudo systemctl reload caddy
|
||||
|
||||
# Start Authelia (Docker or systemd)
|
||||
docker compose up -d authelia
|
||||
# OR
|
||||
sudo systemctl start authelia
|
||||
```
|
||||
|
||||
Verify Authelia is working:
|
||||
```bash
|
||||
curl https://authelia.example.com/.well-known/openid-configuration
|
||||
# Should return JSON with OIDC endpoints
|
||||
```
|
||||
|
||||
### Phase 3: Deploy Caddy Reverse Proxy (Machine 1)
|
||||
|
||||
```bash
|
||||
# On Caddy server
|
||||
# Copy the Caddyfile from this document (see "Configuration for Caddy Server" section)
|
||||
# Update IP addresses: 10.0.1.10 and 10.0.1.20 with your actual IPs
|
||||
|
||||
sudo vim /etc/caddy/Caddyfile
|
||||
# Paste and customize the Caddyfile configuration
|
||||
|
||||
# Reload Caddy
|
||||
sudo caddy reload --config /etc/caddy/Caddyfile
|
||||
```
|
||||
|
||||
Verify Caddy is proxying:
|
||||
```bash
|
||||
curl https://auth.example.com/.well-known/openid-configuration
|
||||
# Should return MAS OIDC config
|
||||
```
|
||||
|
||||
### Phase 4: Start Matrix Stack (Machine 3)
|
||||
|
||||
```bash
|
||||
# On Matrix server
|
||||
cd /path/to/matrix-docker-compose
|
||||
|
||||
# Edit docker-compose.production.yml to remove Caddy and Authelia services
|
||||
# (They're running on separate machines)
|
||||
|
||||
# Start Matrix services
|
||||
docker compose -f docker-compose.production.yml up -d
|
||||
|
||||
# Check services
|
||||
docker compose -f docker-compose.production.yml ps
|
||||
```
|
||||
|
||||
### Phase 5: Verify Everything Works
|
||||
|
||||
```bash
|
||||
# From any external machine
|
||||
|
||||
# Test Matrix API
|
||||
curl https://matrix.example.com/_matrix/client/versions
|
||||
|
||||
# Test MAS
|
||||
curl https://auth.example.com/.well-known/openid-configuration
|
||||
|
||||
# Test Authelia
|
||||
curl https://authelia.example.com/.well-known/openid-configuration
|
||||
|
||||
# Test Element
|
||||
curl https://element.example.com
|
||||
|
||||
# All should return valid responses with Let's Encrypt certificates
|
||||
```
|
||||
|
||||
### Phase 6: First Login
|
||||
|
||||
1. Open `https://element.example.com` in your browser
|
||||
2. Click "Sign In"
|
||||
3. You'll be redirected to Authelia
|
||||
4. Login with:
|
||||
- Username: `admin`
|
||||
- Password: (the one shown during deploy.sh)
|
||||
5. Set up 2FA if required
|
||||
6. You'll be redirected back to Element
|
||||
|
||||
---
|
||||
|
||||
## Verification
|
||||
|
||||
Test each endpoint:
|
||||
|
||||
```bash
|
||||
# From external machine
|
||||
curl https://matrix.example.com/_matrix/client/versions
|
||||
curl https://auth.example.com/.well-known/openid-configuration
|
||||
curl https://authelia.example.com/.well-known/openid-configuration
|
||||
curl https://element.example.com
|
||||
```
|
||||
|
||||
All should return valid responses with Let's Encrypt certificates.
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference: What Goes Where
|
||||
|
||||
### Machine 1 (Caddy - SSL Termination)
|
||||
|
||||
**File**: `/etc/caddy/Caddyfile`
|
||||
|
||||
Handles:
|
||||
- `matrix.example.com` → proxies to Matrix Server (10.0.1.10:8008)
|
||||
- `auth.example.com` → proxies to Matrix Server (10.0.1.10:8080 - MAS)
|
||||
- `element.example.com` → proxies to Matrix Server (10.0.1.10:80 - Element)
|
||||
|
||||
**Note**: Does NOT handle `authelia.example.com` - that's on Machine 2
|
||||
|
||||
### Machine 2 (Authelia - SSO)
|
||||
|
||||
**Files**:
|
||||
- `/etc/authelia/configuration.yml` - Authelia config with OIDC client for MAS
|
||||
- `/etc/authelia/users_database.yml` - User database
|
||||
- `/etc/caddy/Caddyfile` or `/etc/nginx/sites-available/authelia` - Reverse proxy for port 443
|
||||
|
||||
Handles:
|
||||
- `authelia.example.com` on port 443
|
||||
- Authelia listens internally on port 9091
|
||||
- Reverse proxy forwards HTTPS (443) → localhost:9091
|
||||
|
||||
### Machine 3 (Matrix Stack)
|
||||
|
||||
**Services running**:
|
||||
- Synapse (port 8008) - Matrix homeserver
|
||||
- MAS (port 8080) - Authentication service
|
||||
- Element (port 80) - Web client
|
||||
- PostgreSQL (port 5432) - Database
|
||||
|
||||
**Configuration**:
|
||||
- MAS configured with `discovery_url: 'https://authelia.example.com/.well-known/openid-configuration'`
|
||||
- All services communicate with Authelia via public HTTPS URL
|
||||
- Not directly accessible from internet (behind Caddy)
|
||||
|
||||
---
|
||||
|
||||
## Validation Checklist
|
||||
|
||||
After deployment, verify:
|
||||
|
||||
```bash
|
||||
# From external machine or browser
|
||||
|
||||
# 1. Check Authelia OIDC discovery (should return JSON)
|
||||
curl https://authelia.example.com/.well-known/openid-configuration
|
||||
|
||||
# 2. Check MAS OIDC discovery (should return JSON)
|
||||
curl https://auth.example.com/.well-known/openid-configuration
|
||||
|
||||
# 3. Check Matrix well-known (should return base_url and issuer)
|
||||
curl https://matrix.example.com/.well-known/matrix/client
|
||||
|
||||
# 4. Check Matrix versions endpoint
|
||||
curl https://matrix.example.com/_matrix/client/versions
|
||||
|
||||
# 5. Check Element loads
|
||||
curl https://element.example.com
|
||||
|
||||
# All should return valid responses with proper Let's Encrypt certificates
|
||||
```
|
||||
|
||||
If any fail:
|
||||
- Check DNS records point to correct IPs
|
||||
- Verify firewall allows port 443
|
||||
- Check reverse proxy configs
|
||||
- Review Let's Encrypt certificate issuance in logs
|
||||
- Review Let's Encrypt certificate issuance in logs
|
||||
@@ -275,6 +275,18 @@ fi
|
||||
print_status "Prerequisites OK"
|
||||
echo ""
|
||||
|
||||
# Step 1.5: Create directory structure
|
||||
echo -e "${BLUE}[1.5/13] Creating directory structure...${NC}"
|
||||
mkdir -p authelia/config
|
||||
mkdir -p mas/config mas/data mas/certs
|
||||
mkdir -p element/config
|
||||
mkdir -p synapse/data
|
||||
mkdir -p postgres/data
|
||||
mkdir -p caddy/data caddy/config
|
||||
mkdir -p bridges/{telegram,whatsapp,signal}/config
|
||||
print_status "Directory structure created"
|
||||
echo ""
|
||||
|
||||
# Step 2: Generate secure secrets
|
||||
echo -e "${BLUE}[2/12] Generating secure secrets...${NC}"
|
||||
POSTGRES_PASSWORD=$(generate_secret)
|
||||
|
||||
Reference in New Issue
Block a user