coturn stages the cert at start, so a renewal needs a container restart. Record that the certbot deploy hook (which lives outside this repo) now restarts coturn alongside prosody-xmpp. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
162 lines
5.3 KiB
Markdown
162 lines
5.3 KiB
Markdown
# Prosody XMPP Server
|
|
|
|
Dockerized Prosody XMPP server with MySQL backend.
|
|
|
|
## Prerequisites
|
|
|
|
- Docker and Docker Compose
|
|
- External MySQL network: `mysqlgit_mysql_network`
|
|
- Environment variables configuration (see Configuration section)
|
|
|
|
## Configuration
|
|
|
|
This setup uses environment variables for configuration. Create a `.env` file in the project root with:
|
|
|
|
```env
|
|
# XMPP Configuration
|
|
XMPP_DOMAIN=xmpp.guschin.info
|
|
XMPP_USER=mish
|
|
XMPP_PASSWORD=your_password
|
|
|
|
# MySQL Configuration
|
|
MYSQL_HOST=mysql
|
|
MYSQL_USER=prosody
|
|
MYSQL_PASSWORD=your_mysql_password
|
|
MYSQL_DATABASE=prosody
|
|
```
|
|
|
|
## Starting the Server
|
|
|
|
Run from the project directory:
|
|
|
|
```bash
|
|
docker-compose up -d
|
|
```
|
|
|
|
This will:
|
|
- Build and start the Prosody container
|
|
- Connect to external MySQL network (`mysqlgit_mysql_network`)
|
|
- Wait for MySQL to be ready
|
|
- Generate self-signed SSL/TLS certificates (if not present)
|
|
- Configure Prosody with MySQL backend
|
|
|
|
## Access Points
|
|
|
|
| Service | Port | Description |
|
|
|---------|------|-------------|
|
|
| C2S (Client to Server) | 5222 | XMPP client connections |
|
|
| S2S (Server to Server) | 5269 | XMPP federation |
|
|
| Component Protocol | 5347 | External components |
|
|
| HTTP/BOSH/WebSocket | 5280 | Web-based connections |
|
|
| HTTPS | 5281 | Secure web connections |
|
|
| STUN/TURN | 3478 (UDP+TCP) | NAT traversal for audio/video calls |
|
|
| STUN/TURN over TLS | 5349 (UDP+TCP) | Encrypted TURN (`turns:`) |
|
|
| TURN relay range | 49160-49200 (UDP) | Media relay ports |
|
|
|
|
## Features
|
|
|
|
- **Virtual Host**: `xmpp.guschin.info`
|
|
- **Multi-User Chat (MUC)**: `muc.xmpp.guschin.info`
|
|
- **Storage**: MySQL backend with SQL storage
|
|
- **Admin User**: `admin@guschin.info`
|
|
- **Health Checks**: Automatic container health monitoring
|
|
- **Memory Limit**: 200M
|
|
- **Auto-restart**: Container restarts unless stopped
|
|
|
|
## Enabled Modules
|
|
|
|
Core modules: roster, saslauth, tls, dialback, disco, carbons, pep, private, blocking, vcard, version, uptime, time, ping, register, last_activity, admin_adhoc, muc_mam
|
|
|
|
## Data Persistence
|
|
|
|
Volumes are mounted to persist data:
|
|
- `./data/prosody` → `/var/lib/prosody`
|
|
- `./logs/prosody` → `/var/log/prosody`
|
|
- `./data/prosody/configuration` → `/etc/prosody/conf.d`
|
|
|
|
## Connecting Clients
|
|
|
|
Use any XMPP client with:
|
|
- **Server**: xmpp.guschin.info
|
|
- **Port**: 5222
|
|
- **Username**: your configured user
|
|
- **Domain**: xmpp.guschin.info
|
|
|
|
## Audio/Video Calls (Jingle)
|
|
|
|
Voice and video calls use Jingle (XEP-0166/0167/0176). Prosody only carries the
|
|
signalling; media flows directly between clients, falling back to a TURN relay
|
|
when NAT prevents a direct path.
|
|
|
|
Two pieces make this work:
|
|
|
|
- **coturn** (`coturn` container) — the STUN/TURN server. Runs with host
|
|
networking because a relay needs its whole UDP port range reachable.
|
|
- **`mod_turn_external`** in Prosody — advertises coturn to clients over
|
|
XEP-0215 and issues time-limited TURN credentials.
|
|
|
|
### Configuration
|
|
|
|
`TURN_SECRET` in `.env` must match `static-auth-secret` in
|
|
[coturn/turnserver.conf](coturn/turnserver.conf). `.env` is gitignored, so
|
|
these values are set per-deployment and not committed:
|
|
|
|
```env
|
|
TURN_HOST=guschin.info
|
|
TURN_SECRET=<same value as static-auth-secret>
|
|
```
|
|
|
|
`TURN_HOST` is `guschin.info`, not `turn.guschin.info`: `turns:` (TLS) clients
|
|
validate the hostname against the certificate, and only `guschin.info` is in
|
|
the current cert's SANs. To use `turn.guschin.info` instead, reissue the
|
|
certificate with that name added and update both `TURN_HOST` and the
|
|
`external-ip`/`cert` settings accordingly.
|
|
|
|
`turnserver.conf` pins the server's public address in three places:
|
|
`listening-ip`, `relay-ip`, and `external-ip`. **Update all three if the
|
|
server IP changes**, otherwise coturn advertises relay candidates that peers
|
|
cannot reach. Pinning them also stops coturn from auto-discovering the Docker
|
|
bridge interfaces and relaying on unreachable private addresses.
|
|
|
|
### Verifying
|
|
|
|
Check that Prosody advertises the service and coturn answers:
|
|
|
|
```bash
|
|
docker logs coturn # should show listeners on 3478/5349
|
|
docker exec prosody-xmpp prosodyctl check config
|
|
```
|
|
|
|
From a client, place a call between two accounts. Clients that support Jingle
|
|
audio/video include Conversations (Android), Dino, Gajim, and Monal (iOS).
|
|
Note that Jingle A/V is client-to-client — both parties need a client that
|
|
supports it.
|
|
|
|
### Certificate renewal
|
|
|
|
`coturn/entrypoint.sh` copies the certificate at container start, because
|
|
coturn runs as `nobody` and cannot read Let's Encrypt's root-only
|
|
`privkey.pem` directly. A renewal therefore needs a container restart, which
|
|
the certbot deploy hook on the server handles (outside this repo):
|
|
|
|
```
|
|
/etc/letsencrypt/renewal-hooks/deploy/restart-prosody.sh
|
|
```
|
|
|
|
It restarts both `prosody-xmpp` and `coturn` when the `guschin.info` or
|
|
`xmpp.guschin.info` lineage is renewed. Without the coturn restart, `turns:`
|
|
on 5349 would keep serving the old certificate until the next restart.
|
|
|
|
### Firewall
|
|
|
|
Ports 3478 and 5349 (both UDP and TCP) plus the UDP relay range 49160-49200
|
|
must be reachable from the internet. The host has no local firewall
|
|
(`iptables` INPUT policy is ACCEPT), but any provider-level firewall needs
|
|
these opened.
|
|
|
|
## Notes
|
|
|
|
- TLS encryption is not required by default (configurable in [prosody.cfg.lua](data/prosody/configuration/prosody.cfg.lua))
|
|
- Self-signed certificates are auto-generated on first run
|
|
- The container depends on an external MySQL network named `mysqlgit_mysql_network`
|