Dokumentation aus dem Wiki uebernommen und um die Dienste auf dem Server
erweitert. Alle Anleitungen sind so geschrieben, dass sich der jeweilige
Dienst allein daraus neu aufsetzen laesst.
docs/ Dienste im Heimnetz (aus dem Wiki, anonymisiert)
services/ Dienste auf dem Server mit Konfigurationsvorlagen
- matrix-synapse: Homeserver, Postgres, Well-Known-Delegation
- coturn: TURN-Relay fuer Anrufe
- element-web: Web-Client
- wikijs, gitea, nginx
Durchgehend anonymisiert: echte Domain durch example.com ersetzt, IP-Adressen
und E-Mail-Adressen durch Platzhalter. Konfigurationsdateien liegen nur als
.example mit Platzhaltern statt echter Secrets vor.
Die Anleitungen halten die Stolpersteine fest, die beim Aufbau tatsaechlich
aufgetreten sind, unter anderem:
- Synapse verlangt LC_COLLATE=C, sonst startet es nicht
- server_name ist nachtraeglich nicht aenderbar -> Delegation noetig
- register_new_matrix_user liest conf.d nicht, Secret muss per -k kommen
- coturn braucht external-ip, sonst kommen keine Medien durch
- Gruppenmitgliedschaft fuer den Zertifikatszugriff wirkt erst beim Neustart
- nginx vererbt add_header nicht in location-Bloecke mit eigenen Direktiven
3.6 KiB
nginx und TLS
nginx ist der einzige Dienst, der von außen erreichbar ist. Alle Anwendungen
lauschen nur auf 127.0.0.1 und werden von hier weitergereicht.
Aufteilung
| Domain | Ziel |
|---|---|
example.com |
statische Seite + Matrix-Well-Known |
matrix.example.com |
Synapse auf 127.0.0.1:8008 |
element.example.com |
statische Dateien /var/www/element |
wiki.example.com |
Wiki.js auf 127.0.0.1:3000 |
git.example.com |
Gitea auf 127.0.0.1:3001 |
turn.example.com |
kein vHost – coturn nutzt das Zertifikat direkt |
turn.example.com läuft bewusst nicht über nginx. coturn spricht kein HTTP; es
braucht nur ein gültiges Zertifikat für Port 5349. Der Name muss trotzdem in
einem Zertifikat stehen, deshalb wird er beim Ausstellen mit angegeben.
Zertifikate
Ein Zertifikat für mehrere Namen:
sudo certbot certonly --webroot -w /var/www/html \
-d matrix.example.com -d element.example.com -d turn.example.com
Für die Erstausstellung muss Port 80 die ACME-Anfrage beantworten können:
server {
listen 80;
server_name matrix.example.com element.example.com turn.example.com;
root /var/www/html;
location /.well-known/acme-challenge/ { allow all; }
}
Enthaltene Namen prüfen:
sudo openssl x509 -in /etc/letsencrypt/live/matrix.example.com/fullchain.pem \
-noout -ext subjectAltName
Erneuerung
certbot erneuert automatisch. Dienste, die das Material selbst lesen (hier
coturn), merken das nicht – sie halten es seit dem Start im Speicher. Deshalb
ein Deploy-Hook nach
/etc/letsencrypt/renewal-hooks/deploy/10-reload-services.sh:
#!/bin/sh
set -e
chgrp -R ssl-cert /etc/letsencrypt/live /etc/letsencrypt/archive || true
chmod -R g+rX /etc/letsencrypt/live /etc/letsencrypt/archive || true
find /etc/letsencrypt/archive -name 'privkey*.pem' -exec chmod 640 {} \; || true
systemctl reload nginx || true
systemctl restart coturn || true
Trockenlauf:
sudo certbot renew --dry-run
Zertifikate für Nicht-HTTP-Dienste freigeben
Standardmäßig darf nur root den privaten Schlüssel lesen. Statt die Rechte
global zu öffnen, eine Gruppe verwenden und nur die betroffenen Dienstbenutzer
aufnehmen:
sudo groupadd -f ssl-cert
sudo usermod -aG ssl-cert turnserver
sudo chgrp -R ssl-cert /etc/letsencrypt/live /etc/letsencrypt/archive
sudo chmod -R g+rX /etc/letsencrypt/live /etc/letsencrypt/archive
sudo find /etc/letsencrypt/archive -name 'privkey*.pem' -exec chmod 640 {} \;
Gruppenmitgliedschaften wirken erst beim Start eines Prozesses – danach ist ein
restart nötig, kein reload.
Zwei wiederkehrende Fallstricke
add_header wird nicht vererbt. Sobald ein location-Block eine eigene
add_header-Direktive enthält, verliert er alle geerbten. Sicherheitsheader
gehören deshalb in ein Snippet, das in jeden betroffenen Block eingebunden wird:
include /etc/nginx/snippets/element-security.conf;
Zeitüberschreitungen bei Long-Polling. Matrix-Clients halten /sync offen.
Mit dem Standardwert von 60 Sekunden bricht die Verbindung ständig ab:
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
proxy_buffering off;
Prüfen
sudo nginx -t
sudo systemctl reload nginx
curl -s -o /dev/null -w "%{http_code}\n" https://example.com/
curl -s -o /dev/null -D - https://element.example.com/ | grep -iE '^x-|^strict'
Firewall
Freizugeben: 80 und 443 TCP, dazu für coturn 3478 und 5349 (je TCP und UDP) sowie 49152–65535 UDP.
sudo ufw allow 80,443/tcp
sudo ufw allow 3478,5349/tcp
sudo ufw allow 3478,5349/udp
sudo ufw allow 49152:65535/udp