# Ubuntu VM Homelab

Self-hosted communication platform with Mastodon, Mattermost, and Matrix/Element on a single Ubuntu VM sharing PostgreSQL.

## Current Deployment Status

| Service | Status | Domain | Internal Port | Nginx Port |
|---------|--------|--------|---------------|------------|
| ✅ Mastodon | Running | mastodon.vish.gg | 3000, 4000 | 8082 |
| ✅ Mattermost | Running | mm.crista.love | 8065 | 8081 |
| ✅ Matrix (mx.vish.gg) | Running | mx.vish.gg | 8018 | 8082 |
| ✅ Matrix (vish - legacy) | Running | matrix.thevish.io | 8008 | 8081 |
| ✅ PostgreSQL | Running | - | 5432 | - |
| ✅ Redis | Running | - | 6379 | - |
| ✅ TURN (coturn) | Running | mx.vish.gg:3479 | 3479 | - |

## VM Specifications

- **OS**: Ubuntu 24.04.4 LTS (x86_64)
- **Hostname**: matrix-ubuntu
- **LAN IP**: 192.168.0.154 (static) — `ssh ubuntu-matrix`
- **Tailscale IP**: 100.85.21.51
- **SSH user**: test
- **RAM**: 7.7 GB
- **CPU**: 4 cores
- **Storage**: 96 GB
- **Network**: Static IP set via netplan (`/etc/netplan/99-static.yaml`), cloud-init network management disabled

## Architecture

```
┌─────────────────────────────────────────────────────────────┐
│                    Cloudflare Proxy                          │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                         Nginx                                │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐          │
│  │ :8080       │  │ :8081       │  │ :8082       │          │
│  │ Matrix      │  │ Mattermost  │  │ Mastodon    │          │
│  └─────────────┘  └─────────────┘  └─────────────┘          │
└─────────────────────────────────────────────────────────────┘
         │                   │                  │
         ▼                   ▼                  ▼
┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│  Synapse    │     │ Mattermost  │     │  Mastodon   │
│  :8008      │     │   Docker    │     │   Docker    │
│  + Element  │     │   :8065     │     │   :3000     │
└─────────────┘     └─────────────┘     │   :4000     │
         │                   │          └─────────────┘
         │                   │                  │
         └───────────────────┴──────────────────┘
                              │
                              ▼
                    ┌─────────────────┐
                    │   PostgreSQL    │
                    │     :5432       │
                    │                 │
                    │  - synapse      │
                    │  - mattermost   │
                    │  - mastodon     │
                    └─────────────────┘
```

## Databases

All services share the same PostgreSQL 16 server:

| Database | User | Purpose |
|----------|------|---------|
| synapse | synapse | Matrix homeserver (vish - legacy) |
| synapse_mx | synapse_mx | Matrix homeserver (mx.vish.gg - federated) |
| mattermost | mmuser | Mattermost |
| mastodon_production | mastodon | Mastodon |

## Docker Containers

```
NAMES                  IMAGE                                        STATUS
mastodon-streaming-1   ghcr.io/mastodon/mastodon-streaming:v4.5.7   Up
mastodon-web-1         ghcr.io/mastodon/mastodon:v4.5.7             Up
mastodon-sidekiq-1     ghcr.io/mastodon/mastodon:v4.5.7             Up
mastodon-redis-1       redis:7-alpine                               Up
mattermost             mattermost/mattermost-team-edition:11.4      Up (healthy)
```

## Systemd Services (bare-metal)

```
UNIT                SERVICE            VERSION
synapse.service     Synapse (legacy)   1.148.0  — /opt/synapse, port 8008
synapse-mx.service  Synapse (primary)  1.148.0  — /opt/synapse-mx, port 8018
```

Both Synapse instances share the venv at `/opt/synapse/venv/`.

## Quick Start

1. Clone this repo to your VM
2. Copy environment templates and edit with your values
3. Run the setup script

```bash
git clone https://git.vish.gg/Vish/Ubuntu-vm-homelab.git
cd Ubuntu-vm-homelab
./scripts/setup.sh
```

## Directory Structure

```
Ubuntu-vm-homelab/
├── mastodon/
│   ├── docker-compose.yml
│   └── .env.production.template
├── mattermost/
│   ├── docker-compose.yml
│   └── config.json.template
├── matrix-element/
│   ├── homeserver.yaml.template
│   └── element-config.json.template
├── nginx/
│   ├── mastodon.conf
│   ├── mattermost.conf
│   └── matrix.conf
├── scripts/
│   ├── setup.sh
│   ├── backup.sh
│   └── update.sh
└── README.md
```

## Credentials

Stored securely on the server:
- `/opt/mastodon/.env.production` - Mastodon secrets
- `/opt/mattermost/config/config.json` - Mattermost config
- `/opt/synapse/homeserver.yaml` - Matrix config

## Cloudflare Setup

Each service requires a DNS record pointing to the VM's public IP with Cloudflare proxy enabled.
Configure origin rules to route to the correct nginx port.

## Maintenance

### Backup
```bash
./scripts/backup.sh
```

### View Logs
```bash
# Mastodon
cd /opt/mastodon && docker compose logs -f

# Mattermost
docker logs -f mattermost

# Matrix (mx.vish.gg)
tail -f /opt/synapse-mx/homeserver.log

# Matrix (legacy vish)
tail -f /opt/synapse/homeserver.log
```

---

## Updating Services

### Update Mastodon

```bash
cd /opt/mastodon

# Pull latest images
docker compose pull

# Stop services
docker compose down

# Run database migrations
docker compose run --rm web bundle exec rails db:migrate

# Precompile assets (if needed)
docker compose run --rm web bundle exec rails assets:precompile

# Start services
docker compose up -d

# Verify
docker compose ps
```

**Check for release notes:** https://github.com/mastodon/mastodon/releases

### Update Mattermost

```bash
cd /opt/mattermost

# Check current version
docker exec mattermost mattermost version

# Pull latest image
docker compose pull

# Stop and restart
docker compose down
docker compose up -d

# Verify
docker logs mattermost | head -20
```

**Check for release notes:** https://docs.mattermost.com/about/mattermost-server-releases.html

### Update Matrix Synapse (both instances share the same venv)

Both instances use `/opt/synapse/venv/` — upgrade once, restart both.

```bash
# Check current version
curl -s http://localhost:8018/_synapse/admin/v1/server_version

# Upgrade (pin to a specific version, e.g. 1.148.0)
sudo /opt/synapse/venv/bin/pip install 'matrix-synapse==1.148.0'

# Restart both services
sudo systemctl restart synapse synapse-mx

# Verify
curl -s http://localhost:8008/_synapse/admin/v1/server_version  # legacy
curl -s http://localhost:8018/_synapse/admin/v1/server_version  # mx
```

**Check for release notes:** https://github.com/element-hq/synapse/releases

> **Note:** If startup fails with `InsufficientPrivilege: must be owner of table`, see
> the DB ownership fix in `docs/MATRIX.md#db-ownership-fix`.

### Update Element Web

```bash
# Check latest version at https://github.com/element-hq/element-web/releases
ELEMENT_VERSION="v1.12.11"  # Change to latest version

# Download and extract
cd /tmp
wget https://github.com/element-hq/element-web/releases/download/${ELEMENT_VERSION}/element-${ELEMENT_VERSION}.tar.gz
tar -xzf element-${ELEMENT_VERSION}.tar.gz

# Backup current config
cp /opt/element/web/config.json /tmp/element-config-backup.json

# Back up configs
cp /opt/element/web/config.json /tmp/element-config-web.json
cp /opt/element/web-thevish/config.json /tmp/element-config-thevish.json

# Replace files (both installs share the same release)
sudo rm -rf /opt/element/web/* /opt/element/web-thevish/*
sudo cp -r element-${ELEMENT_VERSION}/* /opt/element/web/
sudo cp -r element-${ELEMENT_VERSION}/* /opt/element/web-thevish/

# Restore configs
sudo cp /tmp/element-config-web.json /opt/element/web/config.json
sudo cp /tmp/element-config-thevish.json /opt/element/web-thevish/config.json

# Verify (nginx serves static files, no restart needed)
cat /opt/element/web/version
cat /opt/element/web-thevish/version

# Cleanup
rm -rf /tmp/element-${ELEMENT_VERSION}* /tmp/element-config-*.json
```

### Update TURN Server (coturn)

```bash
# Update via apt
sudo apt update
sudo apt upgrade coturn

# Restart
sudo systemctl restart coturn

# Verify
sudo systemctl status coturn
```

### Update All Services (Quick Script)

```bash
#!/bin/bash
# Save as /opt/scripts/update-all.sh

echo "=== Updating Mastodon ==="
cd /opt/mastodon
docker compose pull
docker compose down
docker compose run --rm web bundle exec rails db:migrate
docker compose up -d

echo "=== Updating Mattermost ==="
cd /opt/mattermost
docker compose pull
docker compose down
docker compose up -d

echo "=== Updating Synapse ==="
cd /opt/synapse
source venv/bin/activate
pip install --upgrade matrix-synapse
pkill -f 'synapse.app.homeserver'
sleep 2
sudo -u synapse /opt/synapse/venv/bin/python -m synapse.app.homeserver \
  --config-path=/opt/synapse-mx/homeserver.yaml --daemonize
sudo -u synapse /opt/synapse/venv/bin/python -m synapse.app.homeserver \
  --config-path=/opt/synapse/homeserver.yaml --daemonize

echo "=== Updating System Packages ==="
sudo apt update && sudo apt upgrade -y

echo "=== Done! ==="
```

---

## Federation Status

| Service | Protocol | Federation |
|---------|----------|------------|
| Matrix (mx.vish.gg) | Matrix | ✅ Enabled |
| Matrix (vish) | Matrix | ❌ Disabled (invalid server_name) |
| Mastodon | ActivityPub | ✅ Enabled |
| Mattermost | Shared Channels | ❌ Enterprise only |

## License

MIT
