update docs
This commit is contained in:
parent
97a50e29f9
commit
ce308776cd
2 changed files with 211 additions and 155 deletions
|
|
@ -9,12 +9,22 @@ Value proposition: "Telegram works without VPN" — the server runs a mautrix-te
|
|||
## Infrastructure
|
||||
|
||||
- **Domain**: vojo.chat
|
||||
- **Server**: Yandex Cloud VPS, Ubuntu 24.04
|
||||
- **Homeserver**: Synapse (Matrix) + PostgreSQL + Caddy (reverse proxy)
|
||||
- **Bridges**: mautrix-telegram v0.15.3 (Python, SOCKS5 proxy for Telegram)
|
||||
- **Client**: this repo — deployed as static files via Caddy
|
||||
- **Server**: Hostinger VPS `187.127.77.124` (hostname `srv1638609`), Ubuntu 24.04, user `vojo-superuser` (in groups `sudo`, `docker`, `docker-mautrix` GID 1337)
|
||||
- **Homeserver**: Synapse (Matrix) + PostgreSQL 16 + Caddy 2 (reverse proxy, Let's Encrypt)
|
||||
- **Bridges** (all `dock.mau.dev/mautrix/*` images, each with its own Postgres role + DB):
|
||||
- `telegram` — bridgev2 (Go) v26.04
|
||||
- `discord` — legacy (Go) v0.7.6+dev (image tag v0.7.5; bridgev2 rewrite ETA late 2026)
|
||||
- `whatsapp` — bridgev2 (Go) v26.04+dev (image v0.12.4)
|
||||
- Passive `doublepuppet` appservice (no `url`, non-exclusive `@.*:vojo.chat`) — one AS-token shared by all three bridges for double puppeting per megabridge spec. Legacy `synapse-shared-secret-auth` is gone; the `as_token:` prefix in each bridge's `secrets:` / `login_shared_secret_map:` is mandatory.
|
||||
- **RTC**: LiveKit + `livekit-jwt-service` (Element Call backend; federation gated to `vojo.chat` via `LIVEKIT_FULL_ACCESS_HOMESERVERS` — see `desired_features.md` §5)
|
||||
- **Push**: Sygnal (FCM + VAPID)
|
||||
- **TURN**: coturn (host network mode)
|
||||
- **Observability**: Prometheus + Grafana
|
||||
- **Synapse modules**: in-tree `username_blocklist.py` bind-mounted into the Synapse image (`synapse/modules/`)
|
||||
- **Client**: this repo — built and deployed as static files via Caddy
|
||||
- **Bot widgets**: three Preact apps in `apps/widget-{telegram,discord,whatsapp}/`, built independently and deployed to `~/vojo/widgets/{telegram,discord,whatsapp}/` for BotShell to embed
|
||||
|
||||
Client source on server: `~/vojo/cinny/`. Caddy serves it at `https://vojo.chat` (via `/var/www/cinny` symlink to `~/vojo/cinny`).
|
||||
Server filesystem under `~/vojo/`: `caddy/`, `synapse/`, `postgres/`, `coturn/`, `livekit/`, `sygnal/`, `prometheus/`, `grafana/`, `bridges/{telegram,discord,whatsapp}/`, `widgets/{telegram,discord,whatsapp}/`, `cinny/`, `docker-compose.yml`. Caddy serves the client at `https://vojo.chat` with the host's `cinny/` directory bind-mounted into the container as `/var/www/cinny`.
|
||||
|
||||
## Branding
|
||||
|
||||
|
|
@ -29,10 +39,10 @@ All configs must point to `vojo.chat` as the default and only homeserver. Hide h
|
|||
```bash
|
||||
npm ci
|
||||
npm run build
|
||||
scp -r dist/* vojo-superuser@111.88.146.156:~/vojo/cinny/
|
||||
rsync -avz --delete dist/ vojo-superuser@187.127.77.124:~/vojo/cinny/
|
||||
```
|
||||
|
||||
VSCode task `Deploy to vojo.chat` (Ctrl+Shift+D) automates this. Android build/deploy is covered in [android.md](android.md).
|
||||
VSCode task `Deploy to vojo.chat` (Ctrl+Shift+D) automates this. The companion task `Deploy widgets` builds and rsyncs the three Preact widget apps under `apps/widget-{telegram,discord,whatsapp}/` to `~/vojo/widgets/<bridge>/` in parallel. Android build/deploy is covered in [android.md](android.md).
|
||||
|
||||
## Developer profile
|
||||
|
||||
|
|
|
|||
|
|
@ -1,94 +1,161 @@
|
|||
folders on server:
|
||||
caddy cinny coturn docker-compose.yml element-releases grafana mautrix-telegram mautrix-telegram-config.yaml.go-backup postgres prometheus sygnal synapse
|
||||
# Server-side configs
|
||||
|
||||
docker-compose.yml
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:16
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
POSTGRES_USER: synapse
|
||||
POSTGRES_PASSWORD: pass
|
||||
POSTGRES_DB: synapse
|
||||
POSTGRES_INITDB_ARGS: "--encoding=UTF8 --lc-collate=C --lc-ctype=C"
|
||||
volumes:
|
||||
- ./postgres:/var/lib/postgresql/data
|
||||
This file is a snapshot of the server-side layout for context, not the source of truth — if
|
||||
you're touching server config, SSH to the box and read the live file. Last refreshed
|
||||
2026-05-06 from a directory walk + the 2026-05-05 handoff. Sections explicitly marked
|
||||
**(not on hand)** weren't dumped at refresh time and may have drifted.
|
||||
|
||||
synapse:
|
||||
image: matrixdotorg/synapse:latest
|
||||
## Top-level layout: `~/vojo/`
|
||||
|
||||
```
|
||||
~/vojo/
|
||||
├── docker-compose.yml
|
||||
├── caddy/ # Caddyfile + ACME state (./data, ./config)
|
||||
├── synapse/
|
||||
│ ├── homeserver.yaml
|
||||
│ ├── doublepuppet.yaml # passive AS for double puppeting (no url)
|
||||
│ ├── telegram-registration.yaml # bind-mounted from bridges/telegram/registration.yaml
|
||||
│ ├── discord-registration.yaml # bind-mounted from bridges/discord/registration.yaml
|
||||
│ ├── whatsapp-registration.yaml # bind-mounted from bridges/whatsapp/registration.yaml
|
||||
│ ├── modules/ # username_blocklist.py + blocked_usernames.txt + blocked_patterns.txt
|
||||
│ ├── media_store/
|
||||
│ ├── vojo.chat.log.config
|
||||
│ └── vojo.chat.signing.key
|
||||
├── postgres/ # data dir (root-owned, 700)
|
||||
├── coturn/turnserver.conf
|
||||
├── livekit/ # livekit.yaml + secrets/ (LiveKit + livekit-jwt-service)
|
||||
├── sygnal/ # sygnal.yaml + fcm-service-account.json + vapid_private_key
|
||||
├── prometheus/ # prometheus.yml + data/
|
||||
├── grafana/ # grafana.db + plugins/ + report dirs
|
||||
├── widgets/ # static widget bundles served by Caddy
|
||||
│ ├── telegram/
|
||||
│ ├── discord/
|
||||
│ └── whatsapp/
|
||||
├── bridges/ # mautrix bridge configs + per-bridge state
|
||||
│ ├── telegram/ (config.yaml, registration.yaml, logs/)
|
||||
│ ├── discord/ (config.yaml, registration.yaml, logs/)
|
||||
│ └── whatsapp/ (config.yaml, registration.yaml, logs/)
|
||||
└── cinny/ # static client bundle (rsync target)
|
||||
```
|
||||
|
||||
## Postgres roles & databases
|
||||
|
||||
`synapse` is the historical superuser. Each bridge has its own role + DB with a 32-char
|
||||
`openssl rand -base64 32 | tr -d '/+=' | head -c 32` password.
|
||||
|
||||
| Role | Database | Used by |
|
||||
|---|---|---|
|
||||
| `synapse` | `synapse` | Synapse homeserver |
|
||||
| `mautrix_telegram` | `mautrix_telegram` | Telegram bridge |
|
||||
| `mautrix_discord` | `mautrix_discord` | Discord bridge |
|
||||
| `mautrix_whatsapp` | `mautrix_whatsapp` | WhatsApp bridge |
|
||||
|
||||
## `~/vojo/synapse/homeserver.yaml` — relevant slices
|
||||
|
||||
```yaml
|
||||
server_name: "vojo.chat"
|
||||
listeners:
|
||||
- port: 8008
|
||||
type: http
|
||||
tls: false
|
||||
x_forwarded: true
|
||||
resources:
|
||||
- names: [client, federation]
|
||||
compress: false
|
||||
- port: 9000
|
||||
type: metrics
|
||||
bind_addresses: ['0.0.0.0']
|
||||
|
||||
database:
|
||||
name: psycopg2
|
||||
args:
|
||||
user: synapse
|
||||
password: <redacted>
|
||||
database: synapse
|
||||
host: postgres
|
||||
cp_min: 5
|
||||
cp_max: 10
|
||||
|
||||
push:
|
||||
enabled: true
|
||||
include_content: true
|
||||
|
||||
app_service_config_files:
|
||||
- /data/telegram-registration.yaml
|
||||
- /data/doublepuppet.yaml
|
||||
- /data/discord-registration.yaml
|
||||
- /data/whatsapp-registration.yaml
|
||||
|
||||
# (also: media_store_path, signing_key_path, turn_*, encryption_enabled_by_default_for_room_type: "off",
|
||||
# trusted_key_servers, enable_metrics, federation_ip_range_whitelist, ip_range_whitelist; unchanged from earlier snapshot)
|
||||
```
|
||||
|
||||
## `~/vojo/synapse/doublepuppet.yaml` — passive AS for double puppeting
|
||||
|
||||
One non-exclusive AS, no `url:` (so Synapse never pushes events to it), shared by all three
|
||||
bridges. The `as_token` here is the value each bridge config references with the
|
||||
`as_token:<token>` prefix in its `double_puppet.secrets` (bridgev2) or
|
||||
`bridge.login_shared_secret_map` (legacy mautrix-discord).
|
||||
|
||||
```yaml
|
||||
id: doublepuppet
|
||||
url:
|
||||
as_token: <hex 64>
|
||||
hs_token: <hex 64>
|
||||
sender_localpart: doublepuppet33ef71bf
|
||||
rate_limited: false
|
||||
namespaces:
|
||||
users:
|
||||
- regex: '@.*:vojo\.chat'
|
||||
exclusive: false
|
||||
```
|
||||
|
||||
## `~/vojo/docker-compose.yml` — service map
|
||||
|
||||
The full file is not committed to this repo. Below are the service names, images, and
|
||||
non-default details captured at refresh time. Expect minor drift — read the live file when
|
||||
in doubt.
|
||||
|
||||
| Service | Image | Notes |
|
||||
|---|---|---|
|
||||
| `postgres` | `postgres:16` | `POSTGRES_INITDB_ARGS: "--encoding=UTF8 --lc-collate=C --lc-ctype=C"` |
|
||||
| `synapse` | `matrixdotorg/synapse:latest` | Bind-mounts: `./synapse:/data` plus three module mounts (`username_blocklist.py`, `blocked_usernames.txt`, `blocked_patterns.txt` → `/usr/local/lib/python3.13/site-packages/`), and four registration mounts (`bridges/telegram/registration.yaml`, `synapse/doublepuppet.yaml`, `bridges/discord/registration.yaml`, `bridges/whatsapp/registration.yaml`) into `/data/*-registration.yaml`. Exposes 8008. |
|
||||
| `caddy` | `caddy:2` | Ports 80/443/8448. Bind-mounts `./caddy/Caddyfile`, `./caddy/data`, `./caddy/config`, `./cinny:/var/www/cinny`, **and the three `widgets/<bridge>` directories** (Caddy serves them at the bot widget origins). |
|
||||
| `coturn` | `coturn/coturn:latest` | `network_mode: host`; `./coturn/turnserver.conf` mounted read-only at `/etc/coturn/turnserver.conf`. |
|
||||
| `livekit` | LiveKit server image | Backed by `./livekit/livekit.yaml` + `./livekit/secrets`. Element Call backend. **(env / image tag not on hand — read the file)** |
|
||||
| `livekit-jwt` | `livekit-jwt-service` | Issues JWTs for Element Call widget; env includes `LIVEKIT_FULL_ACCESS_HOMESERVERS=vojo.chat` (see `desired_features.md` §5). **(rest not on hand)** |
|
||||
| `sygnal` | `matrixdotorg/sygnal:latest` | Mounts `sygnal.yaml`, `fcm-service-account.json`, `vapid_private_key`. `healthcheck: disable: true`. |
|
||||
| `prometheus` | `prom/prometheus:latest` | `--storage.tsdb.retention.time=30d` |
|
||||
| `grafana` | `grafana/grafana:latest` | Port 3000 |
|
||||
| `telegram-bridge` | `dock.mau.dev/mautrix/telegram:<v26.04 bridgev2 tag>` | `./bridges/telegram:/data` |
|
||||
| `discord-bridge` | `dock.mau.dev/mautrix/discord:v0.7.5` | `./bridges/discord:/data` (legacy bridge — runtime reports `0.7.6+dev`) |
|
||||
| `whatsapp-bridge` | `dock.mau.dev/mautrix/whatsapp:v0.12.4` | `./bridges/whatsapp:/data` |
|
||||
|
||||
### Bridge service stanza (template)
|
||||
|
||||
All three mautrix bridges share the same shape:
|
||||
|
||||
```yaml
|
||||
<bridge>-bridge:
|
||||
image: dock.mau.dev/mautrix/<bridge>:<tag>
|
||||
container_name: vojo-<bridge>-bridge
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- postgres
|
||||
- synapse
|
||||
volumes:
|
||||
- ./synapse:/data
|
||||
ports:
|
||||
- "8008:8008"
|
||||
- ./bridges/<bridge>:/data
|
||||
```
|
||||
|
||||
caddy:
|
||||
image: caddy:2
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
- "8448:8448"
|
||||
volumes:
|
||||
- ./caddy/Caddyfile:/etc/caddy/Caddyfile
|
||||
- ./caddy/data:/data
|
||||
- ./caddy/config:/config
|
||||
- ./cinny:/var/www/cinny
|
||||
## Caddy — `~/vojo/caddy/Caddyfile`
|
||||
|
||||
prometheus:
|
||||
image: prom/prometheus:latest
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
|
||||
- ./prometheus/data:/prometheus
|
||||
command:
|
||||
- '--config.file=/etc/prometheus/prometheus.yml'
|
||||
- '--storage.tsdb.retention.time=30d'
|
||||
**(not on hand at refresh time — the snippet below is the pre-bots single-domain config; the live
|
||||
Caddyfile additionally serves the three widget origins from `~/vojo/widgets/<bridge>/`).**
|
||||
|
||||
grafana:
|
||||
image: grafana/grafana:latest
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "3000:3000"
|
||||
environment:
|
||||
- GF_SECURITY_ADMIN_PASSWORD=
|
||||
volumes:
|
||||
- ./grafana:/var/lib/grafana
|
||||
|
||||
coturn:
|
||||
image: coturn/coturn:latest
|
||||
restart: unless-stopped
|
||||
network_mode: host
|
||||
volumes:
|
||||
- ./coturn/turnserver.conf:/etc/coturn/turnserver.conf
|
||||
|
||||
telegram-bridge:
|
||||
image: dock.mau.dev/mautrix/telegram:v0.15.3
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- ./mautrix-telegram:/data
|
||||
|
||||
sygnal:
|
||||
image: matrixdotorg/sygnal:latest
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
disable: true
|
||||
volumes:
|
||||
- ./sygnal/sygnal.yaml:/sygnal.yaml
|
||||
- ./sygnal/fcm-service-account.json:/fcm-service-account.json
|
||||
- ./sygnal/vapid_private_key:/vapid_private_key
|
||||
command: ["python", "-m", "sygnal", "-c", "/sygnal.yaml"]
|
||||
|
||||
caddy/Caddyfile
|
||||
```caddy
|
||||
vojo.chat {
|
||||
handle /_matrix/* {
|
||||
reverse_proxy synapse:8008
|
||||
}
|
||||
handle /_synapse/* {
|
||||
reverse_proxy synapse:8008
|
||||
}
|
||||
handle /_matrix/* { reverse_proxy synapse:8008 }
|
||||
handle /_synapse/* { reverse_proxy synapse:8008 }
|
||||
handle /.well-known/matrix/server {
|
||||
respond `{"m.server": "vojo.chat:443"}`
|
||||
header Content-Type application/json
|
||||
|
|
@ -107,71 +174,50 @@ vojo.chat {
|
|||
}
|
||||
}
|
||||
|
||||
vojo.chat:8448 {
|
||||
reverse_proxy synapse:8008
|
||||
}
|
||||
vojo.chat:8448 { reverse_proxy synapse:8008 }
|
||||
```
|
||||
|
||||
synapse/homeserver.yaml
|
||||
# Configuration file for Synapse.
|
||||
#
|
||||
# This is a YAML file: see [1] for a quick introduction. Note in particular
|
||||
# that *indentation is important*: all the elements of a list or dictionary
|
||||
# should have the same indentation.
|
||||
#
|
||||
# [1] https://docs.ansible.com/ansible/latest/reference_appendices/YAMLSyntax.html
|
||||
#
|
||||
# For more information on how to configure Synapse, including a complete accounting of
|
||||
# each option, go to docs/usage/configuration/config_documentation.md or
|
||||
# https://element-hq.github.io/synapse/latest/usage/configuration/config_documentation.html
|
||||
server_name: "vojo.chat"
|
||||
pid_file: /data/homeserver.pid
|
||||
listeners:
|
||||
- port: 8008
|
||||
resources:
|
||||
- compress: false
|
||||
names:
|
||||
- client
|
||||
- federation
|
||||
tls: false
|
||||
type: http
|
||||
x_forwarded: true
|
||||
- port: 9000
|
||||
type: metrics
|
||||
bind_addresses: ['0.0.0.0']
|
||||
database:
|
||||
name: psycopg2
|
||||
args:
|
||||
user: synapse
|
||||
password: DfgoeFDgr12
|
||||
database: synapse
|
||||
host: postgres
|
||||
cp_min: 5
|
||||
cp_max: 10
|
||||
push:
|
||||
enabled: true
|
||||
include_content: true
|
||||
log_config: "/data/vojo.chat.log.config"
|
||||
media_store_path: /data/media_store
|
||||
registration_shared_secret: ""
|
||||
report_stats: false
|
||||
macaroon_secret_key: ""
|
||||
form_secret: ""
|
||||
signing_key_path: "/data/vojo.chat.signing.key"
|
||||
trusted_key_servers:
|
||||
- server_name: "matrix.org"
|
||||
enable_registration: true
|
||||
enable_registration_without_verification: true
|
||||
enable_metrics: true
|
||||
turn_uris:
|
||||
- "turn:vojo.chat:3478?transport=udp"
|
||||
- "turn:vojo.chat:3478?transport=tcp"
|
||||
turn_shared_secret: ""
|
||||
turn_user_lifetime: 86400000
|
||||
turn_allow_guests: false
|
||||
encryption_enabled_by_default_for_room_type: "off"
|
||||
app_service_config_files:
|
||||
- /data/telegram-registration.yaml
|
||||
federation_ip_range_whitelist:
|
||||
- '172.18.0.0/16'
|
||||
ip_range_whitelist:
|
||||
- '172.18.0.0/16'
|
||||
The `.well-known/matrix/client` block also advertises an `org.matrix.msc4143.rtc_foci`
|
||||
entry pointing at the LiveKit JWT service — see `desired_features.md` §6 for the planned
|
||||
stable-prefix migration.
|
||||
|
||||
## Operational gotchas (preserve when refreshing)
|
||||
|
||||
These bit us during the 2026-05 bridge migration; keep them in mind when editing
|
||||
configs:
|
||||
|
||||
1. **`appservice.address` must use the Docker service name**, not `localhost`. From
|
||||
inside a bridge container, `localhost` resolves to the bridge itself, not Synapse.
|
||||
Use `http://<service-name>:<port>`.
|
||||
2. **`appservice.hostname: 0.0.0.0`** in `whatsapp/config.yaml` (the default `127.0.0.1`
|
||||
binds inside the container only and Synapse can't reach it).
|
||||
3. **Synapse caches appservice configs in memory** at startup. After editing any
|
||||
`*-registration.yaml`, `restart synapse` — restarting only the bridge does not
|
||||
invalidate the cache.
|
||||
4. **Bridge containers chown `/data/config.yaml` to root on first run.** Fix with
|
||||
`sudo chown 1337:docker-mautrix && chmod 660` so the host user (in the
|
||||
`docker-mautrix` group) can edit again. POSIX ACL via `setfacl -m g:docker-mautrix:rw`
|
||||
would survive the chmod-inside-container quirk; not yet applied.
|
||||
5. **Legacy `mautrix-discord -g`** writes the registration but does **not** mirror the
|
||||
generated `as_token`/`hs_token` back into `config.yaml`. Copy them by hand from
|
||||
`registration.yaml`. (bridgev2 — telegram/whatsapp — does this correctly.)
|
||||
6. **Double puppeting secret prefix `as_token:` is mandatory.** Without it, the bridge
|
||||
tries to find the deprecated `synapse-shared-secret-auth` Synapse module.
|
||||
|
||||
## Refresh procedure
|
||||
|
||||
To regenerate this file with current state, on the server:
|
||||
|
||||
```bash
|
||||
cd ~/vojo
|
||||
sudo cat docker-compose.yml > /tmp/dump-compose.yml
|
||||
sudo cat synapse/homeserver.yaml > /tmp/dump-homeserver.yaml
|
||||
sudo cat synapse/doublepuppet.yaml > /tmp/dump-doublepuppet.yaml
|
||||
sudo cat caddy/Caddyfile > /tmp/dump-caddyfile
|
||||
docker compose ps > /tmp/dump-ps.txt
|
||||
docker compose exec -T postgres psql -U synapse -d postgres -c "\du" > /tmp/dump-roles.txt
|
||||
tar czf /tmp/vojo-configs-$(date +%Y%m%d).tar.gz -C /tmp dump-*
|
||||
```
|
||||
|
||||
Hand the tarball to the AI session refreshing this doc — it has enough to bring every
|
||||
section back in sync without `(not on hand)` placeholders.
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue