Second pass on docs/ cleanup (item #15 in STATUS.md): - pfi/chromadb-setup.md: deleted. References configs/pfi-ana/... and scripts/setup-chromadb.sh, neither of which exist in this repo (artifacts of an earlier project layout). ChromaDB is already live per docker-stack.md; the operational truth lives there. - pfi/docker-stack.md: removed the cross-link to the deleted file and pulled the bit of useful content from it (auth-token generation + client Settings example) into the inline ChromaDB section. - pfi/vm-102-matrix-{synapse,appservice}.md: stripped the YAML frontmatter. The `path:` values pointed at docs/pfi-ana/... which doesn't exist in this repo; no toolchain consumed the metadata. - README.md: tree updated to reflect the deletion. VM-102 docs kept separate by design — each is right-sized; merging would push past the ~500-line guideline.
9.9 KiB
VM 102 — Matrix Synapse Deployment
Overview
Matrix (Synapse) is deployed on VM 102 (PFI-ANA-Docker, 10.250.50.70) as the primary
human-to-agent communication channel for AIPA. The stack consists of:
- Synapse — Matrix homeserver (event routing, auth, persistence)
- PostgreSQL 16 — Synapse database backend
- Element Web — Web client for users
Federation is disabled (internal-only deployment). Registration is disabled (admin-created accounts only).
Architecture
User (Element client)
│ m.room.message events
▼
┌──────────────────────┐
│ Synapse │ Matrix homeserver — event routing, auth, persistence
│ (homeserver) │ Port 8008 (Client-Server API)
└──────────┬───────────┘
│ Appservice push PUT /_matrix/app/v1/transactions/{txnId}
▼
┌──────────────────────────────────────────┐
│ AIPA Matrix Bridge (core/matrix_bridge.py) │
│ Port 8009 │
└──────────────────────────────────────────┘
Full appservice bridge details: VM 102 — Matrix Appservice Configuration
Components
| Component | Image | Port | Purpose |
|---|---|---|---|
synapse |
matrixdotorg/synapse:latest |
8008 | Matrix homeserver (Client-Server API) |
synapse-db |
postgres:16 |
— | Synapse database |
element-web |
vectorim/element-web:latest |
8080 | Web client for users |
Storage Paths
| Host Path | Purpose |
|---|---|
/opt/docker/compose/synapse/ |
Compose file (managed by Dockge) |
/opt/docker/conf/synapse/ |
Configuration files |
/opt/docker/data/synapse/ |
Synapse data (homeserver.yaml, signing keys, appservice reg) |
/opt/docker/conf/synapse/element-config.json |
Element Web client config |
Follows the VM 102 convention: compose in
/opt/docker/compose/<service>/, config in/opt/docker/conf/<service>/.
Volumes
| Volume / Path | Container Path | Purpose |
|---|---|---|
/opt/docker/data/synapse |
/data |
Synapse config, signing keys, media store |
synapse-db-data (named vol) |
/var/lib/postgresql/data |
PostgreSQL persistent data |
Step 1 — Create Directory Structure
mkdir -p /opt/docker/data/synapse
mkdir -p /opt/docker/conf/synapse
mkdir -p /opt/docker/compose/synapse
Step 2 — Generate Synapse Config
docker run --rm \
-v /opt/docker/data/synapse:/data \
-e SYNAPSE_SERVER_NAME=matrix.pfi.local \
-e SYNAPSE_REPORT_STATS=no \
matrixdotorg/synapse:latest generate
This writes /opt/docker/data/synapse/homeserver.yaml and
/opt/docker/data/synapse/matrix.pfi.local.signing.key.
Do not modify server_name after generation — it is permanent.
Step 3 — Edit homeserver.yaml
Open /opt/docker/data/synapse/homeserver.yaml and apply:
# Use PostgreSQL instead of SQLite (required for production)
database:
name: psycopg2
args:
user: synapse
password: synapse_db_password # match POSTGRES_PASSWORD in compose
database: synapse
host: synapse-db
cp_min: 5
cp_max: 10
# Disable open registration — accounts are created by admin only
enable_registration: false
# Disable federation (internal deployment only)
federation_domain_whitelist: []
# Allow the application service to be registered (add AFTER generating the AS file)
app_service_config_files:
- /data/aipa_appservice.yaml
Step 4 — Docker Compose
File: /opt/docker/compose/synapse/docker-compose.yml
---
# =============================================================================
# Synapse Matrix Homeserver — AIPA internal deployment on VM 102
# =============================================================================
#
# Conventions:
# - Config: /opt/docker/conf/synapse/
# - Data: /opt/docker/data/synapse/ (bind mount) + synapse-db-data (named vol)
# - Compose: /opt/docker/compose/synapse/
# - Network: synapse-net (dedicated, not on traefik-net)
#
# Notes:
# - Federation disabled (internal only)
# - Port 8448 (federation) commented out
# - Resource limits set for VM 102 (8 vCPU, 16 GB RAM)
services:
synapse-db:
image: postgres:16
container_name: synapse-db
restart: unless-stopped
environment:
POSTGRES_USER: synapse
POSTGRES_PASSWORD: synapse_db_password
POSTGRES_DB: synapse
POSTGRES_INITDB_ARGS: "--encoding=UTF-8 --lc-collate=C --lc-ctype=C"
volumes:
- synapse-db-data:/var/lib/postgresql/data
networks:
- synapse-net
healthcheck:
test: ["CMD-SHELL", "pg_isready -U synapse"]
interval: 10s
timeout: 5s
retries: 5
synapse:
image: matrixdotorg/synapse:latest
container_name: synapse
restart: unless-stopped
depends_on:
synapse-db:
condition: service_healthy
ports:
- "8008:8008" # Client-Server API (HTTP)
# - "8448:8448" # Server-Server API (federation) — disabled for internal use
volumes:
- /opt/docker/data/synapse:/data
networks:
- synapse-net
deploy:
resources:
limits:
memory: 1G
cpus: "2.0"
reservations:
memory: 256M
healthcheck:
test: ["CMD-SHELL", "curl -fsS http://localhost:8008/health || exit 1"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
element-web:
image: vectorim/element-web:latest
container_name: element-web
restart: unless-stopped
volumes:
- /opt/docker/conf/synapse/element-config.json:/app/config.json:ro
ports:
- "8080:80"
networks:
- synapse-net
volumes:
synapse-db-data:
networks:
synapse-net:
name: synapse-net
Start
cd /opt/docker/compose/synapse
docker compose up -d
Verify
docker compose ps
curl http://localhost:8008/health
Step 5 — Element Web Configuration
File: /opt/docker/conf/synapse/element-config.json
{
"default_server_config": {
"m.homeserver": {
"base_url": "http://10.250.50.70:8008",
"server_name": "matrix.pfi.local"
}
},
"brand": "AIPA",
"default_theme": "dark",
"disable_guests": true,
"disable_login_language_selector": true
}
Step 6 — Create Admin User
docker exec -it synapse register_new_matrix_user \
-u admin \
-p 'yourpassword' \
-a \
http://localhost:8008
The
-aflag makes the user an admin. Omit for regular users.
Agent users (@atlas, @linus, @hermione) are virtual — managed by the
appservice. Do not register them as real accounts.
Port Allocation
| Port | Service | Purpose | Protocol |
|---|---|---|---|
| 8008 | Synapse | Client-Server API | HTTP |
| 8080 | Element Web | Web client | HTTP |
| 8009 | AIPA Bridge | Appservice endpoint | HTTP |
See docker-stack.md for the full VM 102 port allocation table.
Network
This deployment uses a dedicated synapse-net network (not traefik-net), because:
- Synapse is accessed directly by IP (no public domain routing needed)
- The AIPA bridge connects to Synapse at
http://localhost:8008from the host - Element Web connects at the VM IP:8008 from the browser
If TLS/reverse proxy is added later, join traefik-net and add Traefik labels.
Security Notes
- Synapse is exposed on port 8008 (HTTP). For any externally accessible deployment, put it behind a TLS-terminating reverse proxy (Traefik/nginx) and restrict 8009 to internal access only.
- Registration is disabled (
enable_registration: false) — accounts created by admin only. - Federation is disabled (
federation_domain_whitelist: []) — internal use only. - The
as_tokenandhs_tokenin the appservice registration are secrets equivalent to admin credentials. Store inenv.sh(gitignored), never commit.
Troubleshooting
| Symptom | Likely Cause | Fix |
|---|---|---|
| Bridge starts but Synapse doesn't push events | Appservice URL wrong in registration YAML | Verify url: is reachable from the Synapse container; check docker inspect synapse network |
| 401 errors from Synapse | as_token mismatch |
Verify token in aipa_appservice.yaml matches MATRIX_AS_TOKEN env var |
| Element can't connect to homeserver | Wrong base_url in element-config.json |
Must be the IP/hostname Element's browser can reach, not the Docker container name |
| Synapse won't start | Database connection failure | Verify synapse-db is healthy first; check password matches in homeserver.yaml and compose |
Next Steps
After Synapse is running and healthy, configure the AIPA appservice bridge: → VM 102 — Matrix Appservice Configuration
Sources
- Source deployment guide:
projects/matrix/matrix-deployment.md(2026-04-11) - VM 102 Proxmox config:
configs/pfi-ana/proxmox/vm-102.conf - Docker Stack conventions:
docs/pfi-ana/docker-stack.md - Matrix Protocol Reference:
infrastructure/matrix-docker-deployment.md(KB)