Sanitized mirror from private repository - 2026-04-05 11:54:56 UTC
This commit is contained in:
171
docs/services/matrix/FEDERATION.md
Normal file
171
docs/services/matrix/FEDERATION.md
Normal file
@@ -0,0 +1,171 @@
|
||||
# Mastodon Federation Guide
|
||||
|
||||
## What is Federation?
|
||||
|
||||
Federation allows your Mastodon instance to communicate with other Mastodon instances (and other ActivityPub-compatible servers). Users can follow accounts on other servers, and posts are shared across the network.
|
||||
|
||||
## Federation Requirements
|
||||
|
||||
### 1. HTTPS (Required)
|
||||
Federation only works over HTTPS. Cloudflare provides this automatically when proxying is enabled.
|
||||
|
||||
### 2. Correct Domain Configuration
|
||||
```env
|
||||
# .env.production
|
||||
LOCAL_DOMAIN=mastodon.vish.gg
|
||||
```
|
||||
|
||||
⚠️ **Warning**: Changing LOCAL_DOMAIN after setup will break existing accounts!
|
||||
|
||||
### 3. Webfinger Endpoint
|
||||
Must respond correctly at:
|
||||
```
|
||||
https://mastodon.vish.gg/.well-known/webfinger?resource=acct:username@mastodon.vish.gg
|
||||
```
|
||||
|
||||
Expected response:
|
||||
```json
|
||||
{
|
||||
"subject": "acct:vish@mastodon.vish.gg",
|
||||
"aliases": [
|
||||
"https://mastodon.vish.gg/@vish",
|
||||
"https://mastodon.vish.gg/users/vish"
|
||||
],
|
||||
"links": [
|
||||
{
|
||||
"rel": "http://webfinger.net/rel/profile-page",
|
||||
"type": "text/html",
|
||||
"href": "https://mastodon.vish.gg/@vish"
|
||||
},
|
||||
{
|
||||
"rel": "self",
|
||||
"type": "application/activity+json",
|
||||
"href": "https://mastodon.vish.gg/users/vish"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 4. ActivityPub Actor Endpoint
|
||||
Must respond at:
|
||||
```
|
||||
https://mastodon.vish.gg/users/vish
|
||||
```
|
||||
With `Accept: application/activity+json` header.
|
||||
|
||||
## Testing Federation
|
||||
|
||||
### Test Webfinger (from external server)
|
||||
```bash
|
||||
curl "https://mastodon.vish.gg/.well-known/webfinger?resource=acct:vish@mastodon.vish.gg"
|
||||
```
|
||||
|
||||
### Test Actor Endpoint
|
||||
```bash
|
||||
curl -H "Accept: application/activity+json" "https://mastodon.vish.gg/users/vish"
|
||||
```
|
||||
|
||||
### Test Outbound Federation
|
||||
Search for a remote user in your Mastodon instance:
|
||||
1. Go to https://mastodon.vish.gg
|
||||
2. Search for `@Gargron@mastodon.social`
|
||||
3. If federation works, you'll see the user's profile
|
||||
|
||||
### Test from Another Instance
|
||||
Go to any public Mastodon instance and search for:
|
||||
```
|
||||
@vish@mastodon.vish.gg
|
||||
```
|
||||
|
||||
## Cloudflare Configuration
|
||||
|
||||
### Required Settings
|
||||
|
||||
1. **Proxy Status**: Orange cloud (Proxied) ✅
|
||||
2. **SSL/TLS Mode**: Full (strict)
|
||||
3. **Cache Level**: Standard (or Bypass for API endpoints)
|
||||
|
||||
### Origin Rules (if using non-standard ports)
|
||||
|
||||
Since nginx listens on port 8082, configure an origin rule:
|
||||
|
||||
**Rule**:
|
||||
- If hostname equals `mastodon.vish.gg`
|
||||
- Then: Override destination port to 8082
|
||||
|
||||
### Firewall Rules
|
||||
Ensure port 8082 is accessible from Cloudflare IPs or use Cloudflare Tunnel.
|
||||
|
||||
## Common Federation Issues
|
||||
|
||||
### Issue: Remote users can't find your instance
|
||||
**Cause**: DNS not properly configured or Cloudflare not proxying
|
||||
**Fix**:
|
||||
1. Verify DNS A record points to your server
|
||||
2. Enable Cloudflare proxy (orange cloud)
|
||||
3. Wait for DNS propagation
|
||||
|
||||
### Issue: Webfinger returns 301 redirect
|
||||
**Normal behavior**: Mastodon redirects HTTP to HTTPS
|
||||
**Solution**: Ensure requests come via HTTPS
|
||||
|
||||
### Issue: Cannot follow remote users
|
||||
**Cause**: Outbound connections blocked
|
||||
**Fix**:
|
||||
1. Check firewall allows outbound HTTPS (443)
|
||||
2. Verify sidekiq is running: `docker compose ps`
|
||||
3. Check sidekiq logs: `docker compose logs sidekiq`
|
||||
|
||||
### Issue: Federation lag
|
||||
**Cause**: High queue backlog in sidekiq
|
||||
**Fix**:
|
||||
```bash
|
||||
# Check queue status
|
||||
docker compose exec web bin/tootctl sidekiq status
|
||||
|
||||
# Clear dead jobs if needed
|
||||
docker compose exec web bin/tootctl sidekiq kill
|
||||
```
|
||||
|
||||
## Federation Debug Commands
|
||||
|
||||
```bash
|
||||
# Check instance connectivity
|
||||
cd /opt/mastodon
|
||||
docker compose exec web bin/tootctl domains crawl mastodon.social
|
||||
|
||||
# Refresh a remote account
|
||||
docker compose exec web bin/tootctl accounts refresh @Gargron@mastodon.social
|
||||
|
||||
# Clear delivery failures
|
||||
docker compose exec web bin/tootctl domains purge <domain>
|
||||
```
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### Block/Allow Lists
|
||||
Configure in Admin → Federation:
|
||||
- Block specific domains
|
||||
- Silence (limit) specific domains
|
||||
- Allow specific domains (whitelist mode)
|
||||
|
||||
### Rate Limiting
|
||||
Mastodon has built-in rate limiting for federation requests to prevent abuse.
|
||||
|
||||
## Monitoring Federation Health
|
||||
|
||||
### Check Sidekiq Queues
|
||||
```bash
|
||||
docker compose exec web bin/tootctl sidekiq stats
|
||||
```
|
||||
|
||||
Healthy queues should have:
|
||||
- Low `push` queue (outbound deliveries)
|
||||
- Low `pull` queue (fetching remote content)
|
||||
- Minimal retries
|
||||
|
||||
### Check Federation Stats
|
||||
In Admin → Dashboard:
|
||||
- Known instances count
|
||||
- Active users (remote)
|
||||
- Incoming/outgoing messages
|
||||
21
docs/services/matrix/LICENSE
Normal file
21
docs/services/matrix/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 Vish
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
300
docs/services/matrix/MATRIX.md
Normal file
300
docs/services/matrix/MATRIX.md
Normal file
@@ -0,0 +1,300 @@
|
||||
# Matrix Synapse Setup
|
||||
|
||||
This VM runs **two Matrix Synapse instances**:
|
||||
|
||||
| Instance | server_name | Domain | Federation | Purpose |
|
||||
|----------|-------------|--------|------------|---------|
|
||||
| **Primary** | `mx.vish.gg` | https://mx.vish.gg | ✅ Yes | Main server with federation |
|
||||
| **Legacy** | `vish` | https://matrix.thevish.io | ❌ No | Historical data archive |
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
Internet
|
||||
│
|
||||
┌────────┴────────┐
|
||||
│ Cloudflare │
|
||||
└────────┬────────┘
|
||||
│
|
||||
┌─────────────┴─────────────┐
|
||||
│ │
|
||||
▼ ▼
|
||||
┌─────────────────┐ ┌─────────────────┐
|
||||
│ mx.vish.gg │ │ matrix.thevish.io│
|
||||
│ (port 443) │ │ (port 443) │
|
||||
└────────┬────────┘ └────────┬─────────┘
|
||||
│ │
|
||||
▼ ▼
|
||||
┌─────────────────┐ ┌─────────────────┐
|
||||
│ Synology Reverse│ │ Synology Reverse│
|
||||
│ Proxy → :8082 │ │ Proxy → :8081 │
|
||||
└────────┬────────┘ └────────┬─────────┘
|
||||
│ │
|
||||
└───────────┬───────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────┐
|
||||
│ Ubuntu VM (192.168.0.154) │
|
||||
│ ┌──────────────┐ ┌──────────────┐ │
|
||||
│ │ Nginx :8082 │ │ Nginx :8081 │ │
|
||||
│ │ mx.vish.gg │ │ thevish.io │ │
|
||||
│ └──────┬───────┘ └──────┬───────┘ │
|
||||
│ │ │ │
|
||||
│ ▼ ▼ │
|
||||
│ ┌──────────────┐ ┌──────────────┐ │
|
||||
│ │ Synapse:8018 │ │ Synapse:8008 │ │
|
||||
│ │ mx.vish.gg │ │ vish │ │
|
||||
│ └──────┬───────┘ └──────┬───────┘ │
|
||||
│ │ │ │
|
||||
│ ▼ ▼ │
|
||||
│ ┌──────────────┐ ┌──────────────┐ │
|
||||
│ │ synapse_mx │ │ synapse │ │
|
||||
│ │ PostgreSQL │ │ PostgreSQL │ │
|
||||
│ └──────────────┘ └──────────────┘ │
|
||||
└─────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Primary Server: mx.vish.gg
|
||||
|
||||
**This is the main server with federation enabled.**
|
||||
|
||||
### Configuration
|
||||
|
||||
- **Location**: `/opt/synapse-mx/`
|
||||
- **Config**: `/opt/synapse-mx/homeserver.yaml`
|
||||
- **Signing Key**: `/opt/synapse-mx/mx.vish.gg.signing.key`
|
||||
- **Media Store**: `/opt/synapse-mx/media_store/`
|
||||
- **Database**: `synapse_mx` (user: `synapse_mx`)
|
||||
- **Port**: 8018 (Synapse) → 8082 (Nginx)
|
||||
|
||||
### User IDs
|
||||
|
||||
Users on this server have IDs like: `@username:mx.vish.gg`
|
||||
|
||||
### Federation
|
||||
|
||||
- ✅ Can communicate with matrix.org and other federated servers
|
||||
- ✅ Can join public rooms on other servers
|
||||
- ✅ Other users can find and message your users
|
||||
|
||||
### Starting the Server
|
||||
|
||||
```bash
|
||||
sudo -u synapse /opt/synapse/venv/bin/python -m synapse.app.homeserver \
|
||||
--config-path=/opt/synapse-mx/homeserver.yaml --daemonize
|
||||
```
|
||||
|
||||
### Stopping the Server
|
||||
|
||||
```bash
|
||||
sudo pkill -f 'config-path=/opt/synapse-mx'
|
||||
```
|
||||
|
||||
## Legacy Server: vish (matrix.thevish.io)
|
||||
|
||||
**This server contains historical data and cannot federate.**
|
||||
|
||||
### Why No Federation?
|
||||
|
||||
The `server_name` is `vish` which is not a valid domain. Other Matrix servers cannot discover it because:
|
||||
- No DNS record for `vish`
|
||||
- Cannot serve `.well-known` at `https://vish/`
|
||||
|
||||
### Configuration
|
||||
|
||||
- **Location**: `/opt/synapse/`
|
||||
- **Config**: `/opt/synapse/homeserver.yaml`
|
||||
- **Signing Key**: `/opt/synapse/vish.signing.key`
|
||||
- **Media Store**: `/opt/synapse/media_store/`
|
||||
- **Database**: `synapse` (user: `synapse`)
|
||||
- **Port**: 8008 (Synapse) → 8081 (Nginx)
|
||||
|
||||
### User IDs
|
||||
|
||||
Users on this server have IDs like: `@username:vish`
|
||||
|
||||
### Starting the Server
|
||||
|
||||
```bash
|
||||
sudo -u synapse /opt/synapse/venv/bin/python -m synapse.app.homeserver \
|
||||
--config-path=/opt/synapse/homeserver.yaml --daemonize
|
||||
```
|
||||
|
||||
## TURN Server (coturn)
|
||||
|
||||
TURN server enables voice/video calls to work through NAT.
|
||||
|
||||
### Configuration
|
||||
|
||||
- **Config**: `/etc/turnserver.conf`
|
||||
- **Ports**: 3479 (TURN), 5350 (TURNS), 49201-49250 (Media relay UDP)
|
||||
- **Realm**: `matrix.thevish.io`
|
||||
- **Auth Secret**: Shared with Synapse (`turn_shared_secret`)
|
||||
|
||||
### Key Settings
|
||||
|
||||
```ini
|
||||
listening-port=3479
|
||||
tls-listening-port=5350
|
||||
listening-ip=0.0.0.0
|
||||
external-ip=YOUR_WAN_IP/192.168.0.154
|
||||
static-auth-secret=<shared-secret>
|
||||
realm=matrix.thevish.io
|
||||
min-port=49201
|
||||
max-port=49250
|
||||
```
|
||||
|
||||
### Port Forwarding Required
|
||||
|
||||
| Port | Protocol | Purpose |
|
||||
|------|----------|---------|
|
||||
| 3479 | TCP/UDP | TURN |
|
||||
| 5350 | TCP/UDP | TURNS (TLS) |
|
||||
| 49201-49250 | UDP | Media relay |
|
||||
|
||||
## Element Web
|
||||
|
||||
Element Web is served by Nginx for both instances.
|
||||
|
||||
### mx.vish.gg
|
||||
|
||||
- **Location**: `/opt/element/web/`
|
||||
- **Config**: `/opt/element/web/config.json`
|
||||
- **URL**: https://mx.vish.gg/
|
||||
|
||||
### matrix.thevish.io
|
||||
|
||||
- **Location**: `/opt/element/web-thevish/`
|
||||
- **Config**: `/opt/element/web-thevish/config.json`
|
||||
- **URL**: https://matrix.thevish.io/
|
||||
|
||||
## Nginx Configuration
|
||||
|
||||
### mx.vish.gg (port 8082)
|
||||
|
||||
Location: `/etc/nginx/sites-available/mx-vish-gg`
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 8082;
|
||||
server_name mx.vish.gg;
|
||||
root /opt/element/web;
|
||||
|
||||
location /health { proxy_pass http://127.0.0.1:8018; }
|
||||
location ~ ^(/_matrix|/_synapse/client) { proxy_pass http://127.0.0.1:8018; }
|
||||
location /_matrix/federation { proxy_pass http://127.0.0.1:8018; }
|
||||
location /.well-known/matrix/server { return 200 '{"m.server": "mx.vish.gg:443"}'; }
|
||||
location /.well-known/matrix/client { return 200 '{"m.homeserver": {"base_url": "https://mx.vish.gg"}}'; }
|
||||
location / { try_files $uri $uri/ /index.html; }
|
||||
}
|
||||
```
|
||||
|
||||
### matrix.thevish.io (port 8081)
|
||||
|
||||
Location: `/etc/nginx/sites-available/matrix-thevish`
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 8081;
|
||||
server_name matrix.thevish.io;
|
||||
root /opt/element/web-thevish;
|
||||
|
||||
location /health { proxy_pass http://127.0.0.1:8008; }
|
||||
location ~ ^(/_matrix|/_synapse/client) { proxy_pass http://127.0.0.1:8008; }
|
||||
location /.well-known/matrix/server { return 200 '{"m.server": "matrix.thevish.io:443"}'; }
|
||||
location /.well-known/matrix/client { return 200 '{"m.homeserver": {"base_url": "https://matrix.thevish.io"}}'; }
|
||||
location / { try_files $uri $uri/ /index.html; }
|
||||
}
|
||||
```
|
||||
|
||||
## Synology Reverse Proxy
|
||||
|
||||
| Name | Source (HTTPS) | Destination (HTTP) |
|
||||
|------|----------------|-------------------|
|
||||
| mx_vish_gg | mx.vish.gg:443 | 192.168.0.154:8082 |
|
||||
| matrix_thevish | matrix.thevish.io:443 | 192.168.0.154:8081 |
|
||||
|
||||
## Cloudflare DNS
|
||||
|
||||
| Type | Name | Content | Proxy |
|
||||
|------|------|---------|-------|
|
||||
| A | mx.vish.gg | YOUR_WAN_IP | ✅ Proxied |
|
||||
| A | matrix.thevish.io | YOUR_WAN_IP | ✅ Proxied |
|
||||
|
||||
## Database Backup
|
||||
|
||||
### Backup mx.vish.gg
|
||||
|
||||
```bash
|
||||
sudo -u postgres pg_dump -Fc synapse_mx > synapse_mx_backup_$(date +%Y%m%d).dump
|
||||
```
|
||||
|
||||
### Backup legacy vish
|
||||
|
||||
```bash
|
||||
sudo -u postgres pg_dump -Fc synapse > synapse_vish_backup_$(date +%Y%m%d).dump
|
||||
```
|
||||
|
||||
### Restore
|
||||
|
||||
```bash
|
||||
sudo -u postgres pg_restore -d <database_name> <backup_file.dump>
|
||||
```
|
||||
|
||||
## Testing Federation
|
||||
|
||||
Use the Matrix Federation Tester:
|
||||
|
||||
```bash
|
||||
curl -s "https://federationtester.matrix.org/api/report?server_name=mx.vish.gg" | python3 -c "
|
||||
import sys, json
|
||||
d = json.load(sys.stdin)
|
||||
print(f'Federation OK: {d.get(\"FederationOK\", False)}')
|
||||
"
|
||||
```
|
||||
|
||||
## Creating Users
|
||||
|
||||
### Via registration (if enabled)
|
||||
|
||||
Go to https://mx.vish.gg and click "Create account"
|
||||
|
||||
### Via command line
|
||||
|
||||
```bash
|
||||
cd /opt/synapse-mx
|
||||
sudo -u synapse /opt/synapse/venv/bin/register_new_matrix_user \
|
||||
-c /opt/synapse-mx/homeserver.yaml \
|
||||
-u <username> -p <password> -a
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Check if Synapse is running
|
||||
|
||||
```bash
|
||||
ps aux | grep synapse.app
|
||||
```
|
||||
|
||||
### View logs
|
||||
|
||||
```bash
|
||||
# mx.vish.gg
|
||||
tail -f /opt/synapse-mx/homeserver.log
|
||||
|
||||
# legacy vish
|
||||
tail -f /opt/synapse/homeserver.log
|
||||
```
|
||||
|
||||
### Test health endpoints
|
||||
|
||||
```bash
|
||||
curl http://localhost:8018/health # mx.vish.gg
|
||||
curl http://localhost:8008/health # legacy vish
|
||||
```
|
||||
|
||||
### Restart nginx
|
||||
|
||||
```bash
|
||||
sudo nginx -t && sudo systemctl reload nginx
|
||||
```
|
||||
197
docs/services/matrix/README.md
Normal file
197
docs/services/matrix/README.md
Normal file
@@ -0,0 +1,197 @@
|
||||
# Matrix Synapse + Element Web Bare-Metal Installation
|
||||
|
||||
Production-ready Matrix homeserver with Element Web client for Ubuntu 24.04 LTS.
|
||||
|
||||
## Features
|
||||
|
||||
- **Synapse** - Matrix homeserver with PostgreSQL backend
|
||||
- **Element Web** - Modern web client (v1.12.8)
|
||||
- **Coturn** - TURN server for voice/video calls
|
||||
- **Federation** - Connect with other Matrix servers
|
||||
- **Nginx** - Reverse proxy for HTTP traffic
|
||||
- **Auto-validation** - YAML config validation during install
|
||||
|
||||
## Quick Install
|
||||
|
||||
```bash
|
||||
# On a fresh Ubuntu 24.04 VM (run as root)
|
||||
export DOMAIN="mx.example.com"
|
||||
export ADMIN_USER="admin"
|
||||
curl -sSL https://git.vish.gg/Vish/matrix-element/raw/branch/main/install-baremetal.sh | bash
|
||||
```
|
||||
|
||||
### One-Liner (with defaults)
|
||||
|
||||
```bash
|
||||
curl -sSL https://git.vish.gg/Vish/matrix-element/raw/branch/main/install-baremetal.sh | DOMAIN=mx.example.com bash
|
||||
```
|
||||
|
||||
## Requirements
|
||||
|
||||
- Ubuntu 24.04 LTS
|
||||
- 2+ CPU cores
|
||||
- 4GB+ RAM
|
||||
- 50GB+ disk space
|
||||
- Domain with DNS pointing to your server
|
||||
|
||||
## Post-Installation
|
||||
|
||||
### 1. Configure Reverse Proxy
|
||||
|
||||
If using a reverse proxy (Synology, Cloudflare, etc.), point:
|
||||
- `https://your-domain.com:443` → `http://server-ip:8080`
|
||||
- Enable WebSocket support
|
||||
|
||||
### 2. Port Forwarding for TURN (Voice/Video Calls)
|
||||
|
||||
Forward these ports to your Matrix server:
|
||||
| Port | Protocol | Purpose |
|
||||
|------|----------|---------|
|
||||
| 3479 | TCP/UDP | TURN |
|
||||
| 5350 | TCP/UDP | TURNS (TLS) |
|
||||
| 49201-49250 | UDP | Media relay |
|
||||
|
||||
### 3. Change Admin Password
|
||||
|
||||
Login at `https://your-domain.com` and change the default password immediately.
|
||||
|
||||
## Scripts
|
||||
|
||||
### Verify Installation
|
||||
|
||||
```bash
|
||||
# Check health of all services
|
||||
./verify-matrix.sh
|
||||
```
|
||||
|
||||
This checks:
|
||||
- All services (synapse, nginx, coturn, postgresql)
|
||||
- Matrix Client and Federation APIs
|
||||
- Well-known endpoints
|
||||
- Element Web accessibility
|
||||
- Database status
|
||||
|
||||
### Fix/Repair
|
||||
|
||||
```bash
|
||||
# Diagnose and fix common issues
|
||||
./fix-matrix.sh
|
||||
```
|
||||
|
||||
This automatically fixes:
|
||||
- YAML configuration errors in homeserver.yaml
|
||||
- File ownership and permissions
|
||||
- Stopped services
|
||||
- Common configuration issues
|
||||
|
||||
### Backup
|
||||
|
||||
```bash
|
||||
# Create a full backup
|
||||
./backup-matrix.sh
|
||||
|
||||
# Or specify custom location
|
||||
BACKUP_DIR=/mnt/backup ./backup-matrix.sh
|
||||
```
|
||||
|
||||
Creates:
|
||||
- PostgreSQL database dump
|
||||
- Configuration files
|
||||
- Media files
|
||||
- Signing keys
|
||||
- TURN configuration
|
||||
|
||||
### Update
|
||||
|
||||
```bash
|
||||
# Update Synapse and Element to latest versions
|
||||
./update-matrix.sh
|
||||
```
|
||||
|
||||
This will:
|
||||
1. Create a backup (optional)
|
||||
2. Update Synapse via pip
|
||||
3. Run database migrations
|
||||
4. Download latest Element Web
|
||||
5. Restart services
|
||||
|
||||
## Configuration Files
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `/opt/synapse/homeserver.yaml` | Main Synapse config |
|
||||
| `/opt/synapse/*.signing.key` | Server signing key (CRITICAL - backup!) |
|
||||
| `/opt/element/web/config.json` | Element Web config |
|
||||
| `/etc/turnserver.conf` | TURN server config |
|
||||
| `/etc/nginx/sites-available/matrix` | Nginx config |
|
||||
| `/root/.matrix_secrets` | Passwords and secrets |
|
||||
|
||||
## Service Management
|
||||
|
||||
```bash
|
||||
# Check status
|
||||
systemctl status synapse nginx coturn
|
||||
|
||||
# Restart services
|
||||
systemctl restart synapse
|
||||
systemctl restart nginx
|
||||
systemctl restart coturn
|
||||
|
||||
# View logs
|
||||
journalctl -u synapse -f
|
||||
journalctl -u coturn -f
|
||||
```
|
||||
|
||||
## Federation Testing
|
||||
|
||||
Test federation status:
|
||||
```bash
|
||||
curl https://federationtester.matrix.org/api/report?server_name=your-domain.com
|
||||
```
|
||||
|
||||
## Adding Users
|
||||
|
||||
```bash
|
||||
# Create a new user
|
||||
cd /opt/synapse
|
||||
source venv/bin/activate
|
||||
register_new_matrix_user -c homeserver.yaml http://localhost:8008
|
||||
|
||||
# Create admin user
|
||||
register_new_matrix_user -c homeserver.yaml -a http://localhost:8008
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Check if services are running
|
||||
```bash
|
||||
systemctl status synapse nginx coturn postgresql
|
||||
```
|
||||
|
||||
### Test Matrix API locally
|
||||
```bash
|
||||
curl http://localhost:8008/_matrix/client/versions
|
||||
```
|
||||
|
||||
### Test well-known endpoints
|
||||
```bash
|
||||
curl https://your-domain.com/.well-known/matrix/server
|
||||
curl https://your-domain.com/.well-known/matrix/client
|
||||
```
|
||||
|
||||
### Check Synapse logs
|
||||
```bash
|
||||
journalctl -u synapse -n 100
|
||||
tail -f /opt/synapse/homeserver.log
|
||||
```
|
||||
|
||||
## Security Notes
|
||||
|
||||
- Change the admin password immediately after installation
|
||||
- Keep `/opt/synapse/*.signing.key` secure and backed up
|
||||
- Consider enabling rate limiting in production
|
||||
- Review `/opt/synapse/homeserver.yaml` for security settings
|
||||
|
||||
## License
|
||||
|
||||
MIT License
|
||||
259
docs/services/matrix/SETUP.md
Normal file
259
docs/services/matrix/SETUP.md
Normal file
@@ -0,0 +1,259 @@
|
||||
# Deployment Documentation
|
||||
|
||||
Complete setup guide for the Ubuntu VM Homelab with Mastodon, Mattermost, and Matrix/Element.
|
||||
|
||||
## Server Access
|
||||
|
||||
```
|
||||
IP: YOUR_WAN_IP
|
||||
SSH Port: 65533
|
||||
Username: test
|
||||
Password: "REDACTED_PASSWORD"
|
||||
```
|
||||
|
||||
## Service Credentials
|
||||
|
||||
### Mastodon Admin
|
||||
- **Username**: vish
|
||||
- **Email**: your-email@example.com
|
||||
- **Password**: `c16a0236e5a5da1e0c80bb296a290fc3`
|
||||
- **URL**: https://mastodon.vish.gg
|
||||
|
||||
### Mattermost
|
||||
- **URL**: https://mm.crista.love
|
||||
- **Admin**: (configured during first access)
|
||||
|
||||
### Matrix/Element
|
||||
- **URL**: https://mx.vish.gg
|
||||
- **Homeserver**: mx.vish.gg
|
||||
|
||||
## PostgreSQL Configuration
|
||||
|
||||
PostgreSQL 16 is configured to allow Docker container connections:
|
||||
|
||||
```
|
||||
# /etc/postgresql/16/main/pg_hba.conf
|
||||
host all all 172.17.0.0/16 md5
|
||||
host all all 0.0.0.0/0 md5
|
||||
|
||||
# /etc/postgresql/16/main/postgresql.conf
|
||||
listen_addresses = '*'
|
||||
```
|
||||
|
||||
### Database Credentials
|
||||
|
||||
| Database | User | Password |
|
||||
|----------|------|----------|
|
||||
| mastodon_production | mastodon | mastodon_pass_2026 |
|
||||
| mattermost | mmuser | (check /opt/mattermost/config/config.json) |
|
||||
| synapse | synapse | (check /opt/synapse/homeserver.yaml) |
|
||||
|
||||
## Nginx Configuration
|
||||
|
||||
### Ports
|
||||
- **8080**: Matrix/Element (mx.vish.gg)
|
||||
- **8081**: Mattermost (mm.crista.love)
|
||||
- **8082**: Mastodon (mastodon.vish.gg)
|
||||
|
||||
### Site Configs
|
||||
```
|
||||
/etc/nginx/sites-enabled/
|
||||
├── mastodon -> /etc/nginx/sites-available/mastodon
|
||||
├── matrix -> /etc/nginx/sites-available/matrix
|
||||
└── mattermost -> /etc/nginx/sites-available/mattermost
|
||||
```
|
||||
|
||||
## Mastodon Setup Details
|
||||
|
||||
### Directory Structure
|
||||
```
|
||||
/opt/mastodon/
|
||||
├── docker-compose.yml
|
||||
├── .env.production
|
||||
├── public/
|
||||
│ └── system/ # Media uploads
|
||||
└── redis/ # Redis data
|
||||
```
|
||||
|
||||
### Environment Variables
|
||||
```env
|
||||
LOCAL_DOMAIN=mastodon.vish.gg
|
||||
SINGLE_USER_MODE=false
|
||||
|
||||
# Database
|
||||
DB_HOST=172.17.0.1
|
||||
DB_PORT=5432
|
||||
DB_NAME=mastodon_production
|
||||
DB_USER=mastodon
|
||||
DB_PASS="REDACTED_PASSWORD"
|
||||
|
||||
# Redis
|
||||
REDIS_HOST=redis
|
||||
REDIS_PORT=6379
|
||||
|
||||
# SMTP (Gmail) - CONFIGURED AND WORKING ✅
|
||||
SMTP_SERVER=smtp.gmail.com
|
||||
SMTP_PORT=587
|
||||
SMTP_LOGIN=your-email@example.com
|
||||
SMTP_PASSWORD="REDACTED_PASSWORD"
|
||||
SMTP_AUTH_METHOD=plain
|
||||
SMTP_ENABLE_STARTTLS=auto
|
||||
SMTP_FROM_ADDRESS="Mastodon <notifications@mastodon.vish.gg>"
|
||||
|
||||
# Search
|
||||
ES_ENABLED=false
|
||||
```
|
||||
|
||||
### Common Commands
|
||||
```bash
|
||||
# View logs
|
||||
cd /opt/mastodon && docker compose logs -f
|
||||
|
||||
# Restart services
|
||||
cd /opt/mastodon && docker compose restart
|
||||
|
||||
# Run admin commands
|
||||
cd /opt/mastodon && docker compose exec web bin/tootctl <command>
|
||||
|
||||
# Create new user
|
||||
docker compose run --rm web bin/tootctl accounts create USERNAME --email=EMAIL --confirmed --role=Owner
|
||||
|
||||
# Database migration
|
||||
docker compose run --rm web bundle exec rake db:migrate
|
||||
```
|
||||
|
||||
## Mattermost Setup Details
|
||||
|
||||
### Directory Structure
|
||||
```
|
||||
/opt/mattermost/
|
||||
├── config/
|
||||
│ └── config.json
|
||||
├── data/
|
||||
├── logs/
|
||||
├── plugins/
|
||||
└── client/plugins/
|
||||
```
|
||||
|
||||
### Docker Command
|
||||
```bash
|
||||
docker run -d --name mattermost \
|
||||
-p 8065:8065 \
|
||||
-v /opt/mattermost/config:/mattermost/config \
|
||||
-v /opt/mattermost/data:/mattermost/data \
|
||||
-v /opt/mattermost/logs:/mattermost/logs \
|
||||
-v /opt/mattermost/plugins:/mattermost/plugins \
|
||||
--restart=always \
|
||||
mattermost/mattermost-team-edition:11.3
|
||||
```
|
||||
|
||||
## Matrix/Synapse Setup Details
|
||||
|
||||
### Directory Structure
|
||||
```
|
||||
/opt/synapse/
|
||||
├── homeserver.yaml
|
||||
├── *.signing.key
|
||||
└── media_store/
|
||||
|
||||
/opt/element/web/
|
||||
└── (Element Web static files)
|
||||
```
|
||||
|
||||
### Synapse Service
|
||||
```bash
|
||||
# Status
|
||||
systemctl status matrix-synapse
|
||||
|
||||
# Restart
|
||||
systemctl restart matrix-synapse
|
||||
|
||||
# Logs
|
||||
journalctl -u matrix-synapse -f
|
||||
```
|
||||
|
||||
## Cloudflare Configuration
|
||||
|
||||
For each service, configure Cloudflare:
|
||||
|
||||
1. **DNS Records** (A records pointing to VM public IP)
|
||||
- mastodon.vish.gg
|
||||
- mm.crista.love
|
||||
- mx.vish.gg
|
||||
|
||||
2. **Origin Rules** (Route to correct nginx port)
|
||||
- mastodon.vish.gg → Port 8082
|
||||
- mm.crista.love → Port 8081
|
||||
- mx.vish.gg → Port 8080
|
||||
|
||||
3. **SSL/TLS**: Full (strict)
|
||||
|
||||
## Federation (Mastodon)
|
||||
|
||||
Federation requires:
|
||||
1. ✅ Proper LOCAL_DOMAIN in .env.production
|
||||
2. ✅ HTTPS via Cloudflare
|
||||
3. ✅ Webfinger endpoint responding at `/.well-known/webfinger`
|
||||
4. ⏳ DNS properly configured
|
||||
|
||||
Test federation:
|
||||
```bash
|
||||
# From another server
|
||||
curl "https://mastodon.vish.gg/.well-known/webfinger?resource=acct:vish@mastodon.vish.gg"
|
||||
```
|
||||
|
||||
## SMTP Configuration (Gmail)
|
||||
|
||||
To send emails via Gmail:
|
||||
|
||||
1. Enable 2-Factor Authentication on your Google account
|
||||
2. Generate an App Password:
|
||||
- Go to https://myaccount.google.com/apppasswords
|
||||
- Create a new app password for "Mail"
|
||||
3. Update `/opt/mastodon/.env.production`:
|
||||
```
|
||||
SMTP_PASSWORD="REDACTED_PASSWORD"
|
||||
```
|
||||
4. Restart Mastodon:
|
||||
```bash
|
||||
cd /opt/mastodon && docker compose restart
|
||||
```
|
||||
|
||||
## Backup Locations
|
||||
|
||||
```
|
||||
/backup/
|
||||
├── YYYYMMDD_HHMMSS/
|
||||
│ ├── mattermost.sql
|
||||
│ ├── synapse.sql
|
||||
│ ├── mastodon.sql
|
||||
│ ├── mastodon_media.tar.gz
|
||||
│ ├── mattermost_data.tar.gz
|
||||
│ └── synapse_data.tar.gz
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Mastodon 403 Forbidden
|
||||
- Normal when accessing with wrong Host header
|
||||
- Always access via proper domain or use `-H "Host: mastodon.vish.gg"`
|
||||
|
||||
### Federation Not Working
|
||||
- Check Cloudflare proxy is enabled
|
||||
- Verify DNS resolves correctly
|
||||
- Test webfinger endpoint externally
|
||||
|
||||
### Database Connection Errors
|
||||
- Verify PostgreSQL is listening on all interfaces
|
||||
- Check pg_hba.conf allows Docker network
|
||||
- Restart PostgreSQL: `systemctl restart postgresql`
|
||||
|
||||
### Container Won't Start
|
||||
```bash
|
||||
# Check logs
|
||||
docker logs <container_name>
|
||||
|
||||
# Check Docker network
|
||||
docker network ls
|
||||
docker network inspect mastodon_internal_network
|
||||
```
|
||||
178
docs/services/matrix/SMTP.md
Normal file
178
docs/services/matrix/SMTP.md
Normal file
@@ -0,0 +1,178 @@
|
||||
# SMTP Email Configuration
|
||||
|
||||
Guide for configuring email delivery for Mastodon and Mattermost.
|
||||
|
||||
## Gmail SMTP Setup
|
||||
|
||||
### Prerequisites
|
||||
1. Google account with 2-Factor Authentication enabled
|
||||
2. App Password generated for "Mail"
|
||||
|
||||
### Generate Gmail App Password
|
||||
|
||||
1. Go to [Google Account Security](https://myaccount.google.com/security)
|
||||
2. Enable 2-Step Verification if not already enabled
|
||||
3. Go to [App Passwords](https://myaccount.google.com/apppasswords)
|
||||
4. Select "Mail" and your device
|
||||
5. Click "Generate"
|
||||
6. Copy the 16-character password
|
||||
|
||||
### Mastodon Configuration
|
||||
|
||||
Edit `/opt/mastodon/.env.production`:
|
||||
|
||||
```env
|
||||
# SMTP Configuration (Gmail)
|
||||
SMTP_SERVER=smtp.gmail.com
|
||||
SMTP_PORT=587
|
||||
SMTP_LOGIN=your-email@example.com
|
||||
SMTP_PASSWORD="REDACTED_PASSWORD"
|
||||
SMTP_AUTH_METHOD=plain
|
||||
SMTP_OPENSSL_VERIFY_MODE=none
|
||||
SMTP_ENABLE_STARTTLS=auto
|
||||
SMTP_FROM_ADDRESS="Mastodon <notifications@mastodon.vish.gg>"
|
||||
```
|
||||
|
||||
Apply changes:
|
||||
```bash
|
||||
cd /opt/mastodon && docker compose restart
|
||||
```
|
||||
|
||||
### Test Email Delivery
|
||||
|
||||
```bash
|
||||
# Send test email
|
||||
cd /opt/mastodon
|
||||
docker compose exec web bin/tootctl accounts modify vish --confirm
|
||||
|
||||
# Or trigger password reset
|
||||
# Go to login page and click "Forgot password"
|
||||
```
|
||||
|
||||
## Mattermost Email Configuration
|
||||
|
||||
Edit `/opt/mattermost/config/config.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"EmailSettings": {
|
||||
"EnableSignUpWithEmail": true,
|
||||
"EnableSignInWithEmail": true,
|
||||
"EnableSignInWithUsername": true,
|
||||
"SendEmailNotifications": true,
|
||||
"RequireEmailVerification": false,
|
||||
"FeedbackName": "Mattermost",
|
||||
"FeedbackEmail": "notifications@mm.crista.love",
|
||||
"SMTPUsername": "your-email@example.com",
|
||||
"SMTPPassword": "your_16_char_app_password",
|
||||
"SMTPServer": "smtp.gmail.com",
|
||||
"SMTPPort": "587",
|
||||
"ConnectionSecurity": "STARTTLS",
|
||||
"SendPushNotifications": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Restart Mattermost:
|
||||
```bash
|
||||
docker restart mattermost
|
||||
```
|
||||
|
||||
## Alternative: SendGrid
|
||||
|
||||
### Setup
|
||||
1. Create SendGrid account at https://sendgrid.com
|
||||
2. Generate API key with "Mail Send" permission
|
||||
|
||||
### Mastodon Configuration
|
||||
```env
|
||||
SMTP_SERVER=smtp.sendgrid.net
|
||||
SMTP_PORT=587
|
||||
SMTP_LOGIN=apikey
|
||||
SMTP_PASSWORD="REDACTED_PASSWORD"
|
||||
SMTP_AUTH_METHOD=plain
|
||||
SMTP_OPENSSL_VERIFY_MODE=peer
|
||||
SMTP_ENABLE_STARTTLS=auto
|
||||
SMTP_FROM_ADDRESS="Mastodon <notifications@mastodon.vish.gg>"
|
||||
```
|
||||
|
||||
## Alternative: Mailgun
|
||||
|
||||
### Setup
|
||||
1. Create Mailgun account at https://mailgun.com
|
||||
2. Verify your domain
|
||||
3. Get SMTP credentials
|
||||
|
||||
### Mastodon Configuration
|
||||
```env
|
||||
SMTP_SERVER=smtp.mailgun.org
|
||||
SMTP_PORT=587
|
||||
SMTP_LOGIN=postmaster@mg.yourdomain.com
|
||||
SMTP_PASSWORD="REDACTED_PASSWORD"
|
||||
SMTP_AUTH_METHOD=plain
|
||||
SMTP_OPENSSL_VERIFY_MODE=peer
|
||||
SMTP_ENABLE_STARTTLS=auto
|
||||
SMTP_FROM_ADDRESS="Mastodon <notifications@mastodon.vish.gg>"
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Check SMTP Connection
|
||||
```bash
|
||||
# Test from container
|
||||
docker compose exec web bash -c "echo 'test' | openssl s_client -connect smtp.gmail.com:587 -starttls smtp"
|
||||
```
|
||||
|
||||
### Check Sidekiq Mail Queue
|
||||
```bash
|
||||
# View failed email jobs
|
||||
docker compose exec web bin/tootctl sidekiq status
|
||||
```
|
||||
|
||||
### Common Errors
|
||||
|
||||
#### "Username and Password not accepted"
|
||||
- Verify App Password is correct (not your regular password)
|
||||
- Ensure 2FA is enabled on Google account
|
||||
- Check no extra spaces in password
|
||||
|
||||
#### "Connection refused"
|
||||
- Firewall blocking outbound port 587
|
||||
- Try port 465 with SSL instead
|
||||
|
||||
#### "Certificate verify failed"
|
||||
- Set `SMTP_OPENSSL_VERIFY_MODE=none` (less secure)
|
||||
- Or ensure CA certificates are up to date
|
||||
|
||||
### Gmail-Specific Issues
|
||||
|
||||
#### "Less secure app access"
|
||||
- Not needed when using App Passwords
|
||||
- App Passwords bypass this requirement
|
||||
|
||||
#### "Critical security alert"
|
||||
- Normal for first connection from new IP
|
||||
- Confirm it was you in Google Security settings
|
||||
|
||||
## Email Content Customization
|
||||
|
||||
### Mastodon
|
||||
Email templates are in the Mastodon source code. Custom templates require forking.
|
||||
|
||||
### Mattermost
|
||||
Edit in System Console → Site Configuration → Customization
|
||||
- Support Email
|
||||
- Notification Footer
|
||||
- Custom Branding
|
||||
|
||||
## SPF/DKIM/DMARC
|
||||
|
||||
For better deliverability, configure DNS records:
|
||||
|
||||
### SPF Record
|
||||
```
|
||||
TXT @ "v=spf1 include:_spf.google.com ~all"
|
||||
```
|
||||
|
||||
### Note on Gmail Sending
|
||||
When using Gmail SMTP, emails are sent "via gmail.com" which has good deliverability. Custom domain email requires additional DNS setup.
|
||||
119
docs/services/matrix/backup-matrix.sh
Executable file
119
docs/services/matrix/backup-matrix.sh
Executable file
@@ -0,0 +1,119 @@
|
||||
#!/bin/bash
|
||||
# =============================================================================
|
||||
# Matrix Synapse Backup Script
|
||||
# Creates a complete backup for migration
|
||||
# =============================================================================
|
||||
# Run as root
|
||||
|
||||
set -e
|
||||
|
||||
BACKUP_DIR="${BACKUP_DIR:-/opt/synapse/backups}"
|
||||
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
|
||||
BACKUP_NAME="matrix_backup_${TIMESTAMP}"
|
||||
BACKUP_PATH="${BACKUP_DIR}/${BACKUP_NAME}"
|
||||
|
||||
echo "=========================================="
|
||||
echo "Matrix Synapse Backup Script"
|
||||
echo "Backup location: ${BACKUP_PATH}"
|
||||
echo "=========================================="
|
||||
|
||||
mkdir -p "${BACKUP_PATH}"
|
||||
|
||||
# 1. Backup PostgreSQL
|
||||
echo "[1/5] Backing up PostgreSQL database..."
|
||||
sudo -u postgres pg_dump -Fc synapse > "${BACKUP_PATH}/synapse.dump"
|
||||
echo " Database: $(du -h ${BACKUP_PATH}/synapse.dump | cut -f1)"
|
||||
|
||||
# 2. Backup Synapse config and keys
|
||||
echo "[2/5] Backing up configuration..."
|
||||
cp /opt/synapse/homeserver.yaml "${BACKUP_PATH}/"
|
||||
cp /opt/synapse/*.signing.key "${BACKUP_PATH}/" 2>/dev/null || true
|
||||
cp /opt/synapse/*.log.config "${BACKUP_PATH}/" 2>/dev/null || true
|
||||
cp /root/.matrix_secrets "${BACKUP_PATH}/" 2>/dev/null || true
|
||||
|
||||
# 3. Backup media
|
||||
echo "[3/5] Backing up media files (this may take a while)..."
|
||||
if [ -d /opt/synapse/media_store ]; then
|
||||
tar -czf "${BACKUP_PATH}/media_store.tar.gz" -C /opt/synapse media_store
|
||||
echo " Media: $(du -h ${BACKUP_PATH}/media_store.tar.gz | cut -f1)"
|
||||
else
|
||||
echo " No media directory found"
|
||||
fi
|
||||
|
||||
# 4. Backup Element config
|
||||
echo "[4/5] Backing up Element config..."
|
||||
cp /opt/element/web/config.json "${BACKUP_PATH}/element_config.json" 2>/dev/null || true
|
||||
|
||||
# 5. Backup TURN config
|
||||
echo "[5/5] Backing up TURN config..."
|
||||
cp /etc/turnserver.conf "${BACKUP_PATH}/" 2>/dev/null || true
|
||||
|
||||
# Create restore instructions
|
||||
cat > "${BACKUP_PATH}/RESTORE.md" << 'RESTORE'
|
||||
# Matrix Restore Instructions
|
||||
|
||||
## On the new server:
|
||||
|
||||
1. Run the install script first (it will create a fresh install)
|
||||
|
||||
2. Stop services:
|
||||
```
|
||||
systemctl stop synapse nginx coturn
|
||||
```
|
||||
|
||||
3. Restore database:
|
||||
```
|
||||
sudo -u postgres dropdb synapse
|
||||
sudo -u postgres createdb -O synapse -E UTF8 -l C -T template0 synapse
|
||||
sudo -u postgres pg_restore -d synapse synapse.dump
|
||||
```
|
||||
|
||||
4. Restore config files:
|
||||
```
|
||||
cp homeserver.yaml /opt/synapse/
|
||||
cp *.signing.key /opt/synapse/
|
||||
cp *.log.config /opt/synapse/
|
||||
chown -R synapse:synapse /opt/synapse
|
||||
```
|
||||
|
||||
5. Restore media:
|
||||
```
|
||||
cd /opt/synapse
|
||||
tar -xzf /path/to/backup/media_store.tar.gz
|
||||
chown -R synapse:synapse media_store
|
||||
```
|
||||
|
||||
6. Restore TURN config:
|
||||
```
|
||||
cp turnserver.conf /etc/turnserver.conf
|
||||
```
|
||||
|
||||
7. Restore Element config:
|
||||
```
|
||||
cp element_config.json /opt/element/web/config.json
|
||||
```
|
||||
|
||||
8. Start services:
|
||||
```
|
||||
systemctl start coturn nginx synapse
|
||||
```
|
||||
RESTORE
|
||||
|
||||
# Create archive
|
||||
echo ""
|
||||
echo "Creating final archive..."
|
||||
cd "${BACKUP_DIR}"
|
||||
tar -czf "${BACKUP_NAME}.tar.gz" "${BACKUP_NAME}"
|
||||
rm -rf "${BACKUP_NAME}"
|
||||
|
||||
FINAL_SIZE=$(du -h "${BACKUP_DIR}/${BACKUP_NAME}.tar.gz" | cut -f1)
|
||||
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo "✅ Backup Complete!"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
echo "Backup file: ${BACKUP_DIR}/${BACKUP_NAME}.tar.gz"
|
||||
echo "Size: ${FINAL_SIZE}"
|
||||
echo ""
|
||||
echo "Download: scp root@server:${BACKUP_DIR}/${BACKUP_NAME}.tar.gz ."
|
||||
196
docs/services/matrix/fix-matrix.sh
Executable file
196
docs/services/matrix/fix-matrix.sh
Executable file
@@ -0,0 +1,196 @@
|
||||
#!/bin/bash
|
||||
# =============================================================================
|
||||
# Matrix Synapse Fix/Repair Script
|
||||
# Diagnoses and fixes common issues
|
||||
# =============================================================================
|
||||
# Run as root
|
||||
|
||||
echo "=========================================="
|
||||
echo "Matrix Synapse Fix/Repair Tool"
|
||||
echo "=========================================="
|
||||
|
||||
# Check root
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
echo "This script must be run as root"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
FIXED=0
|
||||
ERRORS=0
|
||||
|
||||
# 1. Check and fix YAML configuration
|
||||
echo ""
|
||||
echo "[1/6] Checking Synapse configuration..."
|
||||
if [ -f /opt/synapse/homeserver.yaml ]; then
|
||||
if python3 -c "import yaml; yaml.safe_load(open('/opt/synapse/homeserver.yaml'))" 2>/dev/null; then
|
||||
echo " ✓ homeserver.yaml is valid YAML"
|
||||
else
|
||||
echo " ✗ homeserver.yaml has YAML errors!"
|
||||
echo " Creating backup at /opt/synapse/homeserver.yaml.broken"
|
||||
cp /opt/synapse/homeserver.yaml /opt/synapse/homeserver.yaml.broken
|
||||
|
||||
# Try to fix common issues
|
||||
echo " Attempting automatic fix..."
|
||||
# Remove duplicate keys and fix indentation issues
|
||||
python3 << 'PYFIX'
|
||||
import yaml
|
||||
import re
|
||||
|
||||
try:
|
||||
with open('/opt/synapse/homeserver.yaml', 'r') as f:
|
||||
content = f.read()
|
||||
|
||||
# Try to parse and re-write
|
||||
# First, try to fix common issues
|
||||
lines = content.split('\n')
|
||||
fixed_lines = []
|
||||
in_list = False
|
||||
|
||||
for line in lines:
|
||||
# Skip empty turn_uris followed by list items not indented under it
|
||||
if line.strip() == 'turn_uris:':
|
||||
in_list = True
|
||||
fixed_lines.append(line)
|
||||
elif in_list and line.strip().startswith('- "turn:'):
|
||||
fixed_lines.append(' ' + line.strip())
|
||||
elif in_list and line.strip().startswith('- "turns:'):
|
||||
fixed_lines.append(' ' + line.strip())
|
||||
elif in_list and not line.strip().startswith('-') and line.strip():
|
||||
in_list = False
|
||||
fixed_lines.append(line)
|
||||
else:
|
||||
fixed_lines.append(line)
|
||||
|
||||
fixed_content = '\n'.join(fixed_lines)
|
||||
|
||||
# Validate the fix
|
||||
yaml.safe_load(fixed_content)
|
||||
|
||||
with open('/opt/synapse/homeserver.yaml', 'w') as f:
|
||||
f.write(fixed_content)
|
||||
|
||||
print(" ✓ Configuration fixed automatically")
|
||||
except Exception as e:
|
||||
print(f" ✗ Auto-fix failed: {e}")
|
||||
print(" Please manually fix /opt/synapse/homeserver.yaml")
|
||||
print(" Backup saved at /opt/synapse/homeserver.yaml.broken")
|
||||
PYFIX
|
||||
FIXED=$((FIXED + 1))
|
||||
fi
|
||||
else
|
||||
echo " ✗ homeserver.yaml not found!"
|
||||
ERRORS=$((ERRORS + 1))
|
||||
fi
|
||||
|
||||
# 2. Check file permissions
|
||||
echo ""
|
||||
echo "[2/6] Checking file permissions..."
|
||||
if [ -d /opt/synapse ]; then
|
||||
OWNER=$(stat -c '%U' /opt/synapse)
|
||||
if [ "$OWNER" = "synapse" ]; then
|
||||
echo " ✓ /opt/synapse owned by synapse user"
|
||||
else
|
||||
echo " ✗ Fixing ownership of /opt/synapse..."
|
||||
chown -R synapse:synapse /opt/synapse
|
||||
FIXED=$((FIXED + 1))
|
||||
fi
|
||||
|
||||
# Check config file permissions
|
||||
if [ -f /opt/synapse/homeserver.yaml ]; then
|
||||
PERMS=$(stat -c '%a' /opt/synapse/homeserver.yaml)
|
||||
if [ "$PERMS" = "600" ] || [ "$PERMS" = "640" ]; then
|
||||
echo " ✓ homeserver.yaml has correct permissions"
|
||||
else
|
||||
echo " ✗ Fixing homeserver.yaml permissions..."
|
||||
chmod 600 /opt/synapse/homeserver.yaml
|
||||
FIXED=$((FIXED + 1))
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# 3. Check services
|
||||
echo ""
|
||||
echo "[3/6] Checking services..."
|
||||
for svc in postgresql synapse nginx coturn; do
|
||||
if systemctl is-active --quiet $svc 2>/dev/null; then
|
||||
echo " ✓ $svc is running"
|
||||
else
|
||||
echo " ✗ $svc is not running, attempting to start..."
|
||||
systemctl start $svc 2>/dev/null
|
||||
sleep 2
|
||||
if systemctl is-active --quiet $svc; then
|
||||
echo " ✓ $svc started successfully"
|
||||
FIXED=$((FIXED + 1))
|
||||
else
|
||||
echo " ✗ Failed to start $svc"
|
||||
echo " Check logs: journalctl -u $svc -n 50"
|
||||
ERRORS=$((ERRORS + 1))
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# 4. Check database connection
|
||||
echo ""
|
||||
echo "[4/6] Checking database..."
|
||||
if sudo -u postgres psql -c "SELECT 1" synapse > /dev/null 2>&1; then
|
||||
echo " ✓ PostgreSQL connection successful"
|
||||
else
|
||||
echo " ✗ Cannot connect to synapse database"
|
||||
ERRORS=$((ERRORS + 1))
|
||||
fi
|
||||
|
||||
# 5. Check nginx configuration
|
||||
echo ""
|
||||
echo "[5/6] Checking nginx configuration..."
|
||||
if nginx -t 2>/dev/null; then
|
||||
echo " ✓ Nginx configuration is valid"
|
||||
else
|
||||
echo " ✗ Nginx configuration has errors"
|
||||
nginx -t
|
||||
ERRORS=$((ERRORS + 1))
|
||||
fi
|
||||
|
||||
# 6. Check API endpoints
|
||||
echo ""
|
||||
echo "[6/6] Checking API endpoints..."
|
||||
sleep 1
|
||||
if curl -sf http://localhost:8008/_matrix/client/versions > /dev/null 2>&1; then
|
||||
echo " ✓ Matrix Client API responding"
|
||||
else
|
||||
echo " ✗ Matrix Client API not responding"
|
||||
echo " Checking Synapse logs..."
|
||||
journalctl -u synapse -n 10 --no-pager 2>/dev/null | tail -5
|
||||
ERRORS=$((ERRORS + 1))
|
||||
fi
|
||||
|
||||
LISTEN_PORT=$(grep -oP '^ listen \K\d+' /etc/nginx/sites-enabled/matrix 2>/dev/null | head -1 || echo "8080")
|
||||
if curl -sf http://localhost:$LISTEN_PORT/ > /dev/null 2>&1; then
|
||||
echo " ✓ Element Web accessible on port $LISTEN_PORT"
|
||||
else
|
||||
echo " ✗ Element Web not accessible"
|
||||
ERRORS=$((ERRORS + 1))
|
||||
fi
|
||||
|
||||
# Summary
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
if [ $ERRORS -eq 0 ]; then
|
||||
if [ $FIXED -eq 0 ]; then
|
||||
echo "✅ All checks passed! No issues found."
|
||||
else
|
||||
echo "✅ Fixed $FIXED issue(s). All checks now pass."
|
||||
echo ""
|
||||
echo "You may want to restart services:"
|
||||
echo " systemctl restart synapse nginx"
|
||||
fi
|
||||
else
|
||||
echo "⚠️ Found $ERRORS error(s) that need manual attention."
|
||||
echo ""
|
||||
echo "Common fixes:"
|
||||
echo " - Check logs: journalctl -u synapse -f"
|
||||
echo " - Validate YAML: python3 -c \"import yaml; yaml.safe_load(open('/opt/synapse/homeserver.yaml'))\""
|
||||
echo " - Restart services: systemctl restart postgresql synapse nginx coturn"
|
||||
fi
|
||||
echo "=========================================="
|
||||
|
||||
exit $ERRORS
|
||||
377
docs/services/matrix/install-baremetal.sh
Executable file
377
docs/services/matrix/install-baremetal.sh
Executable file
@@ -0,0 +1,377 @@
|
||||
#!/bin/bash
|
||||
# =============================================================================
|
||||
# Matrix Synapse + Element Web Bare-Metal Install Script
|
||||
# For Ubuntu 24.04 LTS
|
||||
# =============================================================================
|
||||
# Usage:
|
||||
# export DOMAIN="mx.example.com"
|
||||
# export ADMIN_USER="admin"
|
||||
# export ADMIN_EMAIL="admin@example.com"
|
||||
# curl -sSL https://git.vish.gg/Vish/matrix-element/raw/branch/main/install-baremetal.sh | bash
|
||||
#
|
||||
# Run as root on a fresh Ubuntu 24.04 VM
|
||||
# =============================================================================
|
||||
|
||||
set -e
|
||||
|
||||
# Configuration
|
||||
DOMAIN="${DOMAIN:-mx.example.com}"
|
||||
ADMIN_USER="${ADMIN_USER:-admin}"
|
||||
ADMIN_EMAIL="${ADMIN_EMAIL:-admin@example.com}"
|
||||
TURN_DOMAIN="${TURN_DOMAIN:-$DOMAIN}"
|
||||
TURN_PORT="${TURN_PORT:-3479}"
|
||||
TURN_TLS_PORT="${TURN_TLS_PORT:-5350}"
|
||||
TURN_MIN_PORT="${TURN_MIN_PORT:-49201}"
|
||||
TURN_MAX_PORT="${TURN_MAX_PORT:-49250}"
|
||||
ELEMENT_VERSION="${ELEMENT_VERSION:-v1.12.8}"
|
||||
LISTEN_PORT="${LISTEN_PORT:-8080}"
|
||||
|
||||
echo "=========================================="
|
||||
echo "Matrix Synapse + Element Web Installer"
|
||||
echo "=========================================="
|
||||
echo "Domain: $DOMAIN"
|
||||
echo "Admin: $ADMIN_USER"
|
||||
echo "=========================================="
|
||||
|
||||
# Check root
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
echo "This script must be run as root"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Update system
|
||||
echo "[1/10] Updating system..."
|
||||
apt update && apt upgrade -y
|
||||
|
||||
# Install dependencies
|
||||
echo "[2/10] Installing dependencies..."
|
||||
apt install -y postgresql postgresql-contrib nginx coturn \
|
||||
python3-pip python3-venv python3-dev build-essential \
|
||||
libffi-dev libssl-dev libjpeg-dev libxslt1-dev \
|
||||
curl wget git jq
|
||||
|
||||
# Create synapse user
|
||||
echo "[3/10] Creating synapse user..."
|
||||
useradd -r -m -d /opt/synapse -s /bin/bash synapse 2>/dev/null || true
|
||||
mkdir -p /opt/synapse /opt/element
|
||||
chown synapse:synapse /opt/synapse
|
||||
|
||||
# Setup PostgreSQL
|
||||
echo "[4/10] Setting up PostgreSQL..."
|
||||
DB_PASS="REDACTED_PASSWORD" rand -hex 16)
|
||||
sudo -u postgres psql -c "CREATE USER synapse WITH PASSWORD 'REDACTED_PASSWORD';" 2>/dev/null || \
|
||||
sudo -u postgres psql -c "ALTER USER synapse WITH PASSWORD 'REDACTED_PASSWORD';"
|
||||
sudo -u postgres psql -c "CREATE DATABASE synapse ENCODING 'UTF8' LC_COLLATE='C' LC_CTYPE='C' template=template0 OWNER synapse;" 2>/dev/null || true
|
||||
|
||||
# Install Synapse
|
||||
echo "[5/10] Installing Synapse..."
|
||||
sudo -u synapse bash << SYNAPSE_INSTALL
|
||||
cd /opt/synapse
|
||||
python3 -m venv venv
|
||||
source venv/bin/activate
|
||||
pip install --upgrade pip setuptools wheel
|
||||
pip install matrix-synapse psycopg2-binary lxml 'prometheus-client<0.21'
|
||||
SYNAPSE_INSTALL
|
||||
|
||||
# Generate config
|
||||
echo "[6/10] Generating Synapse configuration..."
|
||||
cd /opt/synapse
|
||||
sudo -u synapse /opt/synapse/venv/bin/python -m synapse.app.homeserver \
|
||||
--server-name "$DOMAIN" \
|
||||
--config-path homeserver.yaml \
|
||||
--generate-config \
|
||||
--report-stats=no
|
||||
|
||||
# Get generated secrets
|
||||
REG_SECRET=$(grep 'registration_shared_secret' homeserver.yaml | head -1 | awk '{print $2}')
|
||||
MAC_SECRET=$(grep 'macaroon_secret_key' homeserver.yaml | head -1 | awk '{print $2}')
|
||||
FORM_SECRET=$(grep 'form_secret' homeserver.yaml | head -1 | awk '{print $2}')
|
||||
TURN_SECRET=$(openssl rand -hex 32)
|
||||
|
||||
# Create production config
|
||||
cat > /opt/synapse/homeserver.yaml << YAML
|
||||
server_name: "$DOMAIN"
|
||||
pid_file: /opt/synapse/homeserver.pid
|
||||
public_baseurl: https://$DOMAIN/
|
||||
|
||||
listeners:
|
||||
- port: 8008
|
||||
tls: false
|
||||
type: http
|
||||
x_forwarded: true
|
||||
resources:
|
||||
- names: [client, federation]
|
||||
compress: false
|
||||
|
||||
database:
|
||||
name: psycopg2
|
||||
args:
|
||||
user: synapse
|
||||
password: "REDACTED_PASSWORD"
|
||||
database: synapse
|
||||
host: localhost
|
||||
cp_min: 5
|
||||
cp_max: 10
|
||||
|
||||
log_config: "/opt/synapse/$DOMAIN.log.config"
|
||||
media_store_path: /opt/synapse/media_store
|
||||
signing_key_path: "/opt/synapse/$DOMAIN.signing.key"
|
||||
trusted_key_servers:
|
||||
- server_name: "matrix.org"
|
||||
|
||||
registration_shared_secret: $REG_SECRET
|
||||
macaroon_secret_key: $MAC_SECRET
|
||||
form_secret: $FORM_SECRET
|
||||
|
||||
enable_registration: false
|
||||
enable_registration_without_verification: false
|
||||
|
||||
turn_uris:
|
||||
- "turn:$TURN_DOMAIN:$TURN_PORT?transport=udp"
|
||||
- "turn:$TURN_DOMAIN:$TURN_PORT?transport=tcp"
|
||||
- "turns:$TURN_DOMAIN:$TURN_TLS_PORT?transport=udp"
|
||||
- "turns:$TURN_DOMAIN:$TURN_TLS_PORT?transport=tcp"
|
||||
turn_shared_secret: "$TURN_SECRET"
|
||||
turn_user_lifetime: 86400000
|
||||
turn_allow_guests: true
|
||||
|
||||
max_upload_size: 100M
|
||||
url_preview_enabled: true
|
||||
url_preview_ip_range_blacklist:
|
||||
- '127.0.0.0/8'
|
||||
- '10.0.0.0/8'
|
||||
- '172.16.0.0/12'
|
||||
- '192.168.0.0/16'
|
||||
- '100.64.0.0/10'
|
||||
- '169.254.0.0/16'
|
||||
- '::1/128'
|
||||
- 'fe80::/64'
|
||||
- 'fc00::/7'
|
||||
|
||||
suppress_key_server_warning: true
|
||||
enable_metrics: false
|
||||
report_stats: false
|
||||
YAML
|
||||
|
||||
# Validate YAML configuration
|
||||
echo "Validating Synapse configuration..."
|
||||
python3 -c "import yaml; yaml.safe_load(open('/opt/synapse/homeserver.yaml'))" || {
|
||||
echo "ERROR: Invalid YAML in homeserver.yaml"
|
||||
exit 1
|
||||
}
|
||||
|
||||
mkdir -p /opt/synapse/media_store
|
||||
chown -R synapse:synapse /opt/synapse
|
||||
|
||||
# Configure coturn
|
||||
echo "[7/10] Configuring TURN server..."
|
||||
cat > /etc/turnserver.conf << TURN
|
||||
listening-port=$TURN_PORT
|
||||
tls-listening-port=$TURN_TLS_PORT
|
||||
fingerprint
|
||||
use-auth-secret
|
||||
static-auth-secret=$TURN_SECRET
|
||||
realm=$DOMAIN
|
||||
total-quota=100
|
||||
bps-capacity=0
|
||||
stale-nonce=600
|
||||
no-multicast-peers
|
||||
min-port=$TURN_MIN_PORT
|
||||
max-port=$TURN_MAX_PORT
|
||||
log-file=/var/log/turnserver.log
|
||||
TURN
|
||||
|
||||
# Download Element Web
|
||||
echo "[8/10] Installing Element Web..."
|
||||
cd /opt/element
|
||||
wget -q "https://github.com/element-hq/element-web/releases/download/$ELEMENT_VERSION/element-$ELEMENT_VERSION.tar.gz"
|
||||
tar xzf "element-$ELEMENT_VERSION.tar.gz"
|
||||
mv "element-$ELEMENT_VERSION" web
|
||||
rm "element-$ELEMENT_VERSION.tar.gz"
|
||||
|
||||
cat > /opt/element/web/config.json << ELEMENT
|
||||
{
|
||||
"default_server_config": {
|
||||
"m.homeserver": {
|
||||
"base_url": "https://$DOMAIN",
|
||||
"server_name": "$DOMAIN"
|
||||
}
|
||||
},
|
||||
"disable_guests": true,
|
||||
"default_theme": "dark",
|
||||
"room_directory": {
|
||||
"servers": ["matrix.org", "$DOMAIN"]
|
||||
}
|
||||
}
|
||||
ELEMENT
|
||||
|
||||
# Configure nginx
|
||||
echo "[9/10] Configuring nginx..."
|
||||
cat > /etc/nginx/sites-available/matrix << NGINX
|
||||
server {
|
||||
listen $LISTEN_PORT;
|
||||
listen [::]:$LISTEN_PORT;
|
||||
server_name $DOMAIN;
|
||||
|
||||
root /opt/element/web;
|
||||
index index.html;
|
||||
|
||||
location ~ ^(/_matrix|/_synapse/client) {
|
||||
proxy_pass http://127.0.0.1:8008;
|
||||
proxy_set_header X-Forwarded-For \$remote_addr;
|
||||
proxy_set_header X-Forwarded-Proto \$scheme;
|
||||
proxy_set_header Host \$host;
|
||||
client_max_body_size 100M;
|
||||
proxy_http_version 1.1;
|
||||
}
|
||||
|
||||
location /_matrix/federation {
|
||||
proxy_pass http://127.0.0.1:8008;
|
||||
proxy_set_header X-Forwarded-For \$remote_addr;
|
||||
proxy_set_header X-Forwarded-Proto \$scheme;
|
||||
proxy_set_header Host \$host;
|
||||
client_max_body_size 100M;
|
||||
}
|
||||
|
||||
location /.well-known/matrix/server {
|
||||
default_type application/json;
|
||||
return 200 '{"m.server": "$DOMAIN:443"}';
|
||||
}
|
||||
|
||||
location /.well-known/matrix/client {
|
||||
default_type application/json;
|
||||
add_header Access-Control-Allow-Origin *;
|
||||
return 200 '{"m.homeserver": {"base_url": "https://$DOMAIN"}}';
|
||||
}
|
||||
|
||||
location / {
|
||||
try_files \$uri \$uri/ /index.html;
|
||||
}
|
||||
}
|
||||
NGINX
|
||||
|
||||
ln -sf /etc/nginx/sites-available/matrix /etc/nginx/sites-enabled/matrix
|
||||
rm -f /etc/nginx/sites-enabled/default
|
||||
nginx -t
|
||||
|
||||
# Create systemd service
|
||||
cat > /etc/systemd/system/synapse.service << SERVICE
|
||||
[Unit]
|
||||
Description=Synapse Matrix Homeserver
|
||||
After=network.target postgresql.service
|
||||
|
||||
[Service]
|
||||
Type=notify
|
||||
User=synapse
|
||||
Group=synapse
|
||||
WorkingDirectory=/opt/synapse
|
||||
ExecStart=/opt/synapse/venv/bin/python -m synapse.app.homeserver --config-path=/opt/synapse/homeserver.yaml
|
||||
ExecReload=/bin/kill -HUP \$MAINPID
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
SERVICE
|
||||
|
||||
# Start services
|
||||
echo "[10/10] Starting services..."
|
||||
systemctl daemon-reload
|
||||
systemctl enable --now postgresql nginx coturn synapse
|
||||
|
||||
# Create admin user
|
||||
sleep 3
|
||||
ADMIN_PASS="REDACTED_PASSWORD" rand -hex 12)
|
||||
cd /opt/synapse
|
||||
sudo -u synapse /opt/synapse/venv/bin/register_new_matrix_user \
|
||||
-c homeserver.yaml \
|
||||
-u "$ADMIN_USER" \
|
||||
-p "$ADMIN_PASS" \
|
||||
-a \
|
||||
http://localhost:8008
|
||||
|
||||
# Save secrets
|
||||
cat > /root/.matrix_secrets << SECRETS
|
||||
DOMAIN=$DOMAIN
|
||||
DB_PASS="REDACTED_PASSWORD"
|
||||
TURN_SECRET=$TURN_SECRET
|
||||
ADMIN_USER=$ADMIN_USER
|
||||
ADMIN_PASS="REDACTED_PASSWORD"
|
||||
SECRETS
|
||||
chmod 600 /root/.matrix_secrets
|
||||
|
||||
# Download helper scripts
|
||||
echo "Downloading helper scripts..."
|
||||
REPO_BASE="https://git.vish.gg/Vish/matrix-element/raw/branch/main"
|
||||
mkdir -p /opt/matrix-scripts
|
||||
for script in verify-matrix.sh fix-matrix.sh backup-matrix.sh update-matrix.sh; do
|
||||
curl -sSL "$REPO_BASE/$script" -o "/opt/matrix-scripts/$script" 2>/dev/null || true
|
||||
chmod +x "/opt/matrix-scripts/$script" 2>/dev/null || true
|
||||
done
|
||||
echo "Helper scripts installed to /opt/matrix-scripts/"
|
||||
|
||||
# Verify installation
|
||||
echo ""
|
||||
echo "Verifying installation..."
|
||||
sleep 2
|
||||
|
||||
VERIFY_FAILED=0
|
||||
|
||||
# Check services
|
||||
for svc in synapse nginx coturn postgresql; do
|
||||
if systemctl is-active --quiet $svc; then
|
||||
echo "✓ $svc is running"
|
||||
else
|
||||
echo "✗ $svc is NOT running"
|
||||
VERIFY_FAILED=1
|
||||
fi
|
||||
done
|
||||
|
||||
# Check Matrix API
|
||||
if curl -sf http://localhost:8008/_matrix/client/versions > /dev/null; then
|
||||
echo "✓ Matrix API responding"
|
||||
else
|
||||
echo "✗ Matrix API not responding"
|
||||
VERIFY_FAILED=1
|
||||
fi
|
||||
|
||||
# Check Element Web
|
||||
if curl -sf http://localhost:$LISTEN_PORT/ > /dev/null; then
|
||||
echo "✓ Element Web accessible"
|
||||
else
|
||||
echo "✗ Element Web not accessible"
|
||||
VERIFY_FAILED=1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
if [ $VERIFY_FAILED -eq 0 ]; then
|
||||
echo "✅ Matrix Installation Complete!"
|
||||
else
|
||||
echo "⚠️ Installation complete with warnings"
|
||||
fi
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
echo "Domain: $DOMAIN"
|
||||
echo "Admin User: @$ADMIN_USER:$DOMAIN"
|
||||
echo "Admin Password: "REDACTED_PASSWORD"
|
||||
echo ""
|
||||
echo "Listening on port $LISTEN_PORT (HTTP)"
|
||||
echo ""
|
||||
echo "Next steps:"
|
||||
echo "1. Configure reverse proxy: HTTPS:443 → HTTP:$LISTEN_PORT"
|
||||
echo "2. Forward TURN ports: $TURN_PORT, $TURN_TLS_PORT, $TURN_MIN_PORT-$TURN_MAX_PORT"
|
||||
echo "3. Login at https://$DOMAIN and change password"
|
||||
echo ""
|
||||
echo "Secrets saved to /root/.matrix_secrets"
|
||||
echo ""
|
||||
echo "Helper scripts installed to /opt/matrix-scripts/"
|
||||
echo " ./verify-matrix.sh - Check installation health"
|
||||
echo " ./fix-matrix.sh - Diagnose and fix issues"
|
||||
echo " ./backup-matrix.sh - Create full backup"
|
||||
echo " ./update-matrix.sh - Update Synapse and Element"
|
||||
echo ""
|
||||
echo "Useful commands:"
|
||||
echo " systemctl status synapse nginx coturn"
|
||||
echo " journalctl -u synapse -f"
|
||||
echo " curl http://localhost:8008/_matrix/client/versions"
|
||||
103
docs/services/matrix/update-matrix.sh
Executable file
103
docs/services/matrix/update-matrix.sh
Executable file
@@ -0,0 +1,103 @@
|
||||
#!/bin/bash
|
||||
# =============================================================================
|
||||
# Matrix Synapse + Element Web Update Script
|
||||
# =============================================================================
|
||||
# Run as root
|
||||
|
||||
set -e
|
||||
|
||||
echo "=========================================="
|
||||
echo "Matrix Synapse + Element Update Script"
|
||||
echo "=========================================="
|
||||
|
||||
# Check current versions
|
||||
CURRENT_SYNAPSE=$(/opt/synapse/venv/bin/python -c "import synapse; print(synapse.__version__)" 2>/dev/null || echo "unknown")
|
||||
CURRENT_ELEMENT=$(cat /opt/element/web/version 2>/dev/null || ls /opt/element/ | grep -oP 'v[\d.]+' | head -1 || echo "unknown")
|
||||
|
||||
echo "Current Synapse: $CURRENT_SYNAPSE"
|
||||
echo "Current Element: $CURRENT_ELEMENT"
|
||||
|
||||
# Get latest versions
|
||||
echo ""
|
||||
echo "Checking for updates..."
|
||||
LATEST_ELEMENT=$(curl -s https://api.github.com/repos/element-hq/element-web/releases/latest | jq -r '.tag_name')
|
||||
echo "Latest Element: $LATEST_ELEMENT"
|
||||
|
||||
read -p "Proceed with update? (y/N) " -n 1 -r
|
||||
echo
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
echo "Update cancelled."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Backup first
|
||||
echo ""
|
||||
echo "[1/4] Creating backup..."
|
||||
if [ -f ./backup-matrix.sh ]; then
|
||||
./backup-matrix.sh
|
||||
elif [ -f /opt/matrix-scripts/backup-matrix.sh ]; then
|
||||
/opt/matrix-scripts/backup-matrix.sh
|
||||
else
|
||||
echo "Backup script not found, skipping..."
|
||||
fi
|
||||
|
||||
# Update Synapse
|
||||
echo ""
|
||||
echo "[2/4] Updating Synapse..."
|
||||
systemctl stop synapse
|
||||
cd /opt/synapse
|
||||
sudo -u synapse bash << 'UPDATE_SYNAPSE'
|
||||
source venv/bin/activate
|
||||
pip install --upgrade matrix-synapse psycopg2-binary lxml 'prometheus-client<0.21'
|
||||
UPDATE_SYNAPSE
|
||||
|
||||
# Run database migrations
|
||||
echo ""
|
||||
echo "[3/4] Running database migrations..."
|
||||
sudo -u synapse /opt/synapse/venv/bin/python -m synapse.app.homeserver \
|
||||
--config-path /opt/synapse/homeserver.yaml \
|
||||
--generate-keys-if-missing
|
||||
|
||||
# Update Element Web
|
||||
echo ""
|
||||
echo "[4/4] Updating Element Web..."
|
||||
cd /opt/element
|
||||
if [ -n "$LATEST_ELEMENT" ] && [ "$LATEST_ELEMENT" != "null" ]; then
|
||||
# Backup old config
|
||||
cp web/config.json /tmp/element_config_backup.json
|
||||
|
||||
# Download new version
|
||||
wget -q "https://github.com/element-hq/element-web/releases/download/$LATEST_ELEMENT/element-$LATEST_ELEMENT.tar.gz"
|
||||
|
||||
# Remove old, extract new
|
||||
rm -rf web
|
||||
tar xzf "element-$LATEST_ELEMENT.tar.gz"
|
||||
mv "element-$LATEST_ELEMENT" web
|
||||
rm "element-$LATEST_ELEMENT.tar.gz"
|
||||
|
||||
# Restore config
|
||||
cp /tmp/element_config_backup.json web/config.json
|
||||
echo "Element updated to $LATEST_ELEMENT"
|
||||
else
|
||||
echo "Could not determine latest Element version, skipping Element update"
|
||||
fi
|
||||
|
||||
# Start services
|
||||
echo ""
|
||||
echo "Starting services..."
|
||||
systemctl start synapse
|
||||
systemctl restart nginx
|
||||
|
||||
# Verify
|
||||
sleep 3
|
||||
NEW_SYNAPSE=$(/opt/synapse/venv/bin/python -c "import synapse; print(synapse.__version__)" 2>/dev/null || echo "unknown")
|
||||
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo "✅ Update Complete!"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
echo "Synapse: $CURRENT_SYNAPSE → $NEW_SYNAPSE"
|
||||
echo "Element: $CURRENT_ELEMENT → $LATEST_ELEMENT"
|
||||
echo ""
|
||||
echo "Please verify your instance is working correctly."
|
||||
126
docs/services/matrix/verify-matrix.sh
Executable file
126
docs/services/matrix/verify-matrix.sh
Executable file
@@ -0,0 +1,126 @@
|
||||
#!/bin/bash
|
||||
# =============================================================================
|
||||
# Matrix Synapse + Element Web Verification Script
|
||||
# =============================================================================
|
||||
# Run as root or with sudo
|
||||
|
||||
echo "=========================================="
|
||||
echo "Matrix/Element Health Check"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
|
||||
FAILED=0
|
||||
WARN=0
|
||||
|
||||
# Load domain from secrets if available
|
||||
if [ -f /root/.matrix_secrets ]; then
|
||||
source /root/.matrix_secrets
|
||||
echo "Domain: ${DOMAIN:-unknown}"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "[Service Status]"
|
||||
for svc in synapse nginx coturn postgresql; do
|
||||
STATUS=$(systemctl is-active $svc 2>/dev/null || echo "not-found")
|
||||
if [ "$STATUS" = "active" ]; then
|
||||
echo " ✓ $svc: running"
|
||||
elif [ "$STATUS" = "not-found" ]; then
|
||||
echo " - $svc: not installed"
|
||||
else
|
||||
echo " ✗ $svc: $STATUS"
|
||||
FAILED=1
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "[Matrix API]"
|
||||
# Client API
|
||||
if curl -sf http://localhost:8008/_matrix/client/versions > /dev/null 2>&1; then
|
||||
VERSION_COUNT=$(curl -s http://localhost:8008/_matrix/client/versions | python3 -c "import sys,json; print(len(json.load(sys.stdin).get('versions',[])))" 2>/dev/null || echo "0")
|
||||
echo " ✓ Client API: responding ($VERSION_COUNT protocol versions)"
|
||||
else
|
||||
echo " ✗ Client API: not responding"
|
||||
FAILED=1
|
||||
fi
|
||||
|
||||
# Federation API
|
||||
FED_RESULT=$(curl -sf http://localhost:8008/_matrix/federation/v1/version 2>/dev/null)
|
||||
if [ -n "$FED_RESULT" ]; then
|
||||
SYNAPSE_VER=$(echo "$FED_RESULT" | python3 -c "import sys,json; print(json.load(sys.stdin).get('server',{}).get('version','unknown'))" 2>/dev/null)
|
||||
echo " ✓ Federation API: responding (Synapse $SYNAPSE_VER)"
|
||||
else
|
||||
echo " ✗ Federation API: not responding"
|
||||
FAILED=1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "[Well-Known Endpoints]"
|
||||
# Check nginx port
|
||||
LISTEN_PORT=$(grep -oP 'listen \K\d+' /etc/nginx/sites-enabled/matrix 2>/dev/null | head -1 || echo "8080")
|
||||
|
||||
SERVER_WK=$(curl -sf http://localhost:$LISTEN_PORT/.well-known/matrix/server 2>/dev/null)
|
||||
if [ -n "$SERVER_WK" ]; then
|
||||
echo " ✓ /.well-known/matrix/server: $SERVER_WK"
|
||||
else
|
||||
echo " ✗ /.well-known/matrix/server: not configured"
|
||||
WARN=1
|
||||
fi
|
||||
|
||||
CLIENT_WK=$(curl -sf http://localhost:$LISTEN_PORT/.well-known/matrix/client 2>/dev/null)
|
||||
if [ -n "$CLIENT_WK" ]; then
|
||||
echo " ✓ /.well-known/matrix/client: configured"
|
||||
else
|
||||
echo " ✗ /.well-known/matrix/client: not configured"
|
||||
WARN=1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "[Element Web]"
|
||||
if curl -sf http://localhost:$LISTEN_PORT/ > /dev/null 2>&1; then
|
||||
echo " ✓ Element Web: accessible on port $LISTEN_PORT"
|
||||
else
|
||||
echo " ✗ Element Web: not accessible"
|
||||
FAILED=1
|
||||
fi
|
||||
|
||||
# Check Element config
|
||||
if [ -f /opt/element/web/config.json ]; then
|
||||
HOMESERVER=$(python3 -c "import json; print(json.load(open('/opt/element/web/config.json')).get('default_server_config',{}).get('m.homeserver',{}).get('base_url','not set'))" 2>/dev/null)
|
||||
echo " ✓ Element config: homeserver=$HOMESERVER"
|
||||
else
|
||||
echo " ✗ Element config: /opt/element/web/config.json not found"
|
||||
WARN=1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "[TURN Server]"
|
||||
if systemctl is-active --quiet coturn; then
|
||||
TURN_PORT=$(grep -oP '^listening-port=\K\d+' /etc/turnserver.conf 2>/dev/null | head -1 || echo "3479")
|
||||
echo " ✓ Coturn: running on port $TURN_PORT"
|
||||
else
|
||||
echo " - Coturn: not running (voice/video calls may not work behind NAT)"
|
||||
WARN=1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "[Database]"
|
||||
if systemctl is-active --quiet postgresql; then
|
||||
DB_SIZE=$(sudo -u postgres psql -t -c "SELECT pg_size_pretty(pg_database_size('synapse'));" 2>/dev/null | xargs)
|
||||
echo " ✓ PostgreSQL: running (synapse db: ${DB_SIZE:-unknown})"
|
||||
else
|
||||
echo " ✗ PostgreSQL: not running"
|
||||
FAILED=1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
if [ $FAILED -eq 0 ] && [ $WARN -eq 0 ]; then
|
||||
echo "✅ All checks passed!"
|
||||
elif [ $FAILED -eq 0 ]; then
|
||||
echo "⚠️ Passed with warnings"
|
||||
else
|
||||
echo "❌ Some checks failed"
|
||||
fi
|
||||
echo "=========================================="
|
||||
|
||||
exit $FAILED
|
||||
Reference in New Issue
Block a user