Einen Palaver-Server installieren
| Bestandteil | Zweck | Pfad unter chat.example.org |
|---|---|---|
| palaverd | Konten, Kanäle, Text | /api/ |
| LiveKit | Sprache, Bildschirmfreigabe | /livekit/ |
| Web-Client | App im Browser | / |
| nginx | TLS (Let's Encrypt), Reverse-Proxy | Ports 80, 443 |
| PostgreSQL | Daten | – |
Updates: Update-Anleitung
Platzhalter in den Befehlen:
| Platzhalter | Ersetzen durch |
|---|---|
chat.example.org |
deinen Domainnamen |
you@example.org |
E-Mail-Adresse für Let's Encrypt |
0.3.0 |
Palaver-Version |
https://<release host>/lasse-tech/palaver/releases/download |
Download-Adresse der Versionen; bis 1.0.0 nur im internen Forgejo des Projekts |
<livekit-key>, <livekit-secret> |
Ausgabe aus Schritt 6, „Erzeuge … für die LiveKit-API“ |
<cert-name> |
nur vorhandenes Zertifikat: sein Name |
vi |
Editor deiner Wahl |
1. Voraussetzungen
- System: Debian 13 oder ein Derivat auf Basis von Debian 13 oder Ubuntu 24.04+ (z. B. Ubuntu, Linux Mint 22)
- Architektur: amd64 (x86_64)
- öffentliche IPv4-Adresse
- Domainname mit A-Eintrag auf die öffentliche IPv4-Adresse des Servers, z. B.
chat.example.org - E-Mail-Adresse für Let's Encrypt
- Shell-Zugang mit
sudo - Grundkenntnisse in der Linux-Administration
| Gruppe | CPU | RAM | Platte |
|---|---|---|---|
| ein paar Freunde | 1 Kern | 2 GB | 20 GB |
| 20–30 Leute mit Bildschirmfreigabe | 2 Kerne | 4 GB | 40 GB |
- Bandbreite: ~1 Mbit/s pro Person im Sprachkanal, +3–4 Mbit/s pro Zuschauer einer 1080p-Bildschirmfreigabe
- Anhänge: je bis 25 MiB, in der Datenbank
Offene Ports zum Server:
| Port | Protokoll | Wofür |
|---|---|---|
| 80 | TCP | Let's Encrypt, Umleitung auf https |
| 443 | TCP | App, Web-Client, Verbindungsaufbau für Sprache |
| 7881 | TCP | Sprache, wenn UDP beim Nutzer gesperrt ist |
| 3478 | UDP | STUN/TURN |
| 30000–30100 | UDP | TURN-Relay |
| 50000–60000 | UDP | Sprache und Bildschirmfreigabe |
Prüfe das System.
. /etc/os-release; echo "$PRETTY_NAME | ${ID_LIKE:-$ID} | ${UBUNTU_CODENAME:-$VERSION_CODENAME} | $(uname -m)"
2. Pakete
| Paket | Anforderung |
|---|---|
| PostgreSQL | 16 oder neuer, beliebige Quelle |
| nginx | beliebige Quelle |
| certbot | beliebige Quelle (apt, snap) |
| curl, ca-certificates, openssl | beliebige Quelle |
Fehlende installieren:
sudo apt-get update
sudo apt-get install postgresql nginx certbot curl ca-certificates openssl
3. Benutzer und Verzeichnisse
Lege den Systembenutzer palaver an.
sudo useradd --system --home-dir /opt/palaver --no-create-home --shell /usr/sbin/nologin palaver
Lege die Verzeichnisse an; etc nur für palaver lesbar.
sudo install -d -o root -g root -m 755 /opt/palaver /opt/palaver/bin /opt/palaver/web
sudo install -d -o palaver -g palaver -m 700 /opt/palaver/etc
4. PostgreSQL
Starte PostgreSQL.
sudo systemctl enable --now postgresql
Lege die Datenbankrolle und die Datenbank palaver an; Unix-Socket, Peer-Authentifizierung, kein Passwort.
sudo -u postgres createuser palaver
sudo -u postgres createdb -O palaver palaver
5. Palaver herunterladen
Lade Server, Web-Client und Prüfsummen herunter.
curl -fLO "https://<release host>/lasse-tech/palaver/releases/download/v0.3.0/palaverd-0.3.0-linux-amd64"
curl -fLO "https://<release host>/lasse-tech/palaver/releases/download/v0.3.0/palaver-web-0.3.0.tar.gz"
curl -fLO "https://<release host>/lasse-tech/palaver/releases/download/v0.3.0/SHA256SUMS"
Prüfe beide Dateien; jede Zeile muss auf OK enden.
sha256sum -c --ignore-missing SHA256SUMS
6. palaverd
Installiere das Programm.
sudo install -m 755 palaverd-0.3.0-linux-amd64 /opt/palaver/bin/palaverd
Erzeuge den Schlüssel für die LiveKit-API (<livekit-key>).
echo "API$(openssl rand -hex 8)"
Erzeuge das Geheimnis für die LiveKit-API (<livekit-secret>).
openssl rand -base64 36 | tr -d '/+='
Öffne /opt/palaver/etc/palaverd.env in einem Editor.
sudo vi /opt/palaver/etc/palaverd.env
Inhalt (Referenz):
PALAVER_DATABASE_URL=postgres:///palaver?host=/var/run/postgresql
PALAVER_LISTEN=127.0.0.1:8090
PALAVER_PUBLIC_URL=https://chat.example.org
PALAVER_LIVEKIT_URL=wss://chat.example.org/livekit
PALAVER_LIVEKIT_API_URL=http://127.0.0.1:7880
PALAVER_LIVEKIT_API_KEY=<livekit-key>
PALAVER_LIVEKIT_API_SECRET=<livekit-secret>
PALAVER_OPEN_REGISTRATION=false
Mache sie nur für palaver lesbar.
sudo chown palaver:palaver /opt/palaver/etc/palaverd.env
sudo chmod 600 /opt/palaver/etc/palaverd.env
Öffne /etc/systemd/system/palaverd.service in einem Editor.
sudo vi /etc/systemd/system/palaverd.service
Inhalt:
[Unit]
Description=Palaver app server
After=network-online.target postgresql.service
Wants=network-online.target
[Service]
User=palaver
Group=palaver
EnvironmentFile=/opt/palaver/etc/palaverd.env
ExecStart=/opt/palaver/bin/palaverd serve
Restart=on-failure
RestartSec=2
LogNamespace=palaver
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
PrivateDevices=yes
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectControlGroups=yes
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
LockPersonality=yes
MemoryDenyWriteExecute=yes
[Install]
WantedBy=multi-user.target
7. LiveKit
Lade LiveKit 1.13.7 (getestet) von GitHub herunter und prüfe es; die Zeile muss auf OK enden.
curl -fLO https://github.com/livekit/livekit/releases/download/v1.13.7/livekit_1.13.7_linux_amd64.tar.gz
echo "6634aeeb2fb1366b6723708ae4320b9d5408106a4c63457c5e845ae3979c90e2 livekit_1.13.7_linux_amd64.tar.gz" | sha256sum -c
Entpacke und installiere das Programm.
tar -xzf livekit_1.13.7_linux_amd64.tar.gz livekit-server
sudo install -m 755 livekit-server /opt/palaver/bin/livekit-server
Öffne /opt/palaver/etc/livekit.yaml in einem Editor.
sudo vi /opt/palaver/etc/livekit.yaml
Inhalt; nur localhost, eingebautes TURN/STUN:
port: 7880
bind_addresses: ["127.0.0.1"]
rtc:
tcp_port: 7881
port_range_start: 50000
port_range_end: 60000
use_external_ip: false
# node_ip: 203.0.113.10 # behind NAT only: the public IPv4
turn:
enabled: true
domain: chat.example.org
udp_port: 3478
relay_range_start: 30000
relay_range_end: 30100
room:
empty_timeout: 300
keys:
<livekit-key>: <livekit-secret>
logging:
level: info
Mache sie nur für palaver lesbar.
sudo chown palaver:palaver /opt/palaver/etc/livekit.yaml
sudo chmod 600 /opt/palaver/etc/livekit.yaml
Öffne /etc/systemd/system/livekit.service in einem Editor.
sudo vi /etc/systemd/system/livekit.service
Inhalt:
[Unit]
Description=LiveKit media server for Palaver
After=network-online.target
Wants=network-online.target
[Service]
User=palaver
Group=palaver
ExecStart=/opt/palaver/bin/livekit-server --config /opt/palaver/etc/livekit.yaml
Restart=on-failure
RestartSec=2
LogNamespace=palaver
LimitNOFILE=65536
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
PrivateDevices=yes
[Install]
WantedBy=multi-user.target
8. Logs
Öffne /etc/systemd/journald@palaver.conf in einem Editor.
sudo vi /etc/systemd/journald@palaver.conf
Inhalt; bewahrt das Journal von palaverd und LiveKit (Namespace palaver) 14 Tage auf:
[Journal]
MaxRetentionSec=14day
Lege das Verzeichnis für die nginx-Logs der Site an.
sudo install -d -o www-data -g adm -m 750 /var/log/nginx/palaver
Öffne /etc/logrotate.d/palaver in einem Editor.
sudo vi /etc/logrotate.d/palaver
Inhalt; rotiert die Logs von nginx täglich, bewahrt 14 Tage auf:
/var/log/nginx/palaver/*.log {
daily
rotate 13
missingok
notifempty
compress
delaycompress
create 0640 www-data adm
sharedscripts
postrotate
invoke-rc.d nginx rotate >/dev/null 2>&1
endscript
}
9. Web-Client
Entpacke den Web-Client.
sudo tar -xzf palaver-web-0.3.0.tar.gz --no-same-owner -C /opt/palaver/web
sudo chmod -R u=rwX,go=rX /opt/palaver/web
Öffne /etc/nginx/snippets/palaver-web.conf in einem Editor.
sudo vi /etc/nginx/snippets/palaver-web.conf
Inhalt:
root /opt/palaver/web;
index index.html;
location / {
try_files $uri /index.html;
add_header Cache-Control "no-cache" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; worker-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; media-src 'self' blob: mediastream:; font-src 'self'; connect-src 'self' wss://chat.example.org; object-src 'none'; base-uri 'none'; form-action 'self'; frame-ancestors 'none'" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer" always;
add_header Permissions-Policy "camera=(), geolocation=(), payment=()" always;
add_header Strict-Transport-Security "max-age=31536000" always;
}
location /assets/ {
try_files $uri =404;
add_header Cache-Control "public, max-age=31536000, immutable" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; worker-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; media-src 'self' blob: mediastream:; font-src 'self'; connect-src 'self' wss://chat.example.org; object-src 'none'; base-uri 'none'; form-action 'self'; frame-ancestors 'none'" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Strict-Transport-Security "max-age=31536000" always;
}
10. nginx und Zertifikat
Starte nginx.
sudo systemctl enable --now nginx
Öffne /etc/nginx/sites-available/palaver in einem Editor.
sudo vi /etc/nginx/sites-available/palaver
Inhalt; vorläufige Port-80-Site für die Let's-Encrypt-Prüfung:
server {
listen 80;
listen [::]:80;
server_name chat.example.org;
location /.well-known/acme-challenge/ { root /var/www/html; }
location / { return 404; }
}
Aktiviere die Site, prüfe und lade sie.
sudo ln -sf /etc/nginx/sites-available/palaver /etc/nginx/sites-enabled/palaver
sudo nginx -t && sudo systemctl reload nginx
Hole das Zertifikat; automatische Erneuerung, lädt nginx neu.
sudo certbot certonly --webroot -w /var/www/html -d chat.example.org -m you@example.org \
--agree-tos --no-eff-email --non-interactive \
--deploy-hook "systemctl reload nginx"
Öffne /etc/nginx/sites-available/palaver in einem Editor.
sudo vi /etc/nginx/sites-available/palaver
Inhalt; vollständige Site:
server {
listen 80;
listen [::]:80;
server_name chat.example.org;
access_log /var/log/nginx/palaver/access.log;
error_log /var/log/nginx/palaver/error.log;
location /.well-known/acme-challenge/ {
root /var/www/html;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name chat.example.org;
ssl_certificate /etc/letsencrypt/live/chat.example.org/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/chat.example.org/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
access_log /var/log/nginx/palaver/access.log;
error_log /var/log/nginx/palaver/error.log;
client_max_body_size 64k;
# server push, one WebSocket per client
location = /api/events {
proxy_pass http://127.0.0.1:8090;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 1h;
proxy_send_timeout 1h;
}
# profile pictures, server icon: 5 MiB
location ~ ^/api/(me/avatar|server/icon)$ {
client_max_body_size 5m;
proxy_pass http://127.0.0.1:8090;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# attachments: 25 MiB
location ~ ^/api/channels/[0-9]+/attachments$ {
client_max_body_size 25m;
proxy_pass http://127.0.0.1:8090;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /api/ {
proxy_pass http://127.0.0.1:8090;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# LiveKit signalling; the trailing slash strips /livekit
location /livekit/ {
proxy_pass http://127.0.0.1:7880/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_read_timeout 1h;
proxy_send_timeout 1h;
}
include snippets/palaver-web.conf;
}
Prüfe und lade sie.
sudo nginx -t && sudo systemctl reload nginx
11. Starten
Lade die Units, starte LiveKit und palaverd; der erste Start legt die Datenbanktabellen an.
sudo systemctl daemon-reload
sudo systemctl enable --now livekit palaverd
Prüfe, ob palaverd antwortet; erwartet: JSON.
curl -fsS http://127.0.0.1:8090/api/registration
12. Erster Admin
Erzeuge einen Einladungscode für den ersten Admin; einmal nutzbar, 7 Tage gültig.
sudo -u palaver /opt/palaver/bin/palaverd -env /opt/palaver/etc/palaverd.env invite -role Admin -valid 168h
- Registrieren: Palaver-App oder
https://chat.example.orgim Browser → Serverhttps://chat.example.org→ Registrieren → Code - erster Admin = Eigentümer des Servers
- nach der ersten Anmeldung: Zustimmungsfrage für anonyme Zahlen an Dogan (Überwachung von Palaver-Servern); später unter Einstellungen › Server › Mitwirken
- andere einladen: Verwaltungsmodus an (Einstellungen › Allgemein › Verwaltung, pro Gerät) → Leute einladen in der Kanalliste
13. Prüfen
Führe doctor aus (Konfiguration, Datenbank, palaverd, LiveKit, öffentliche Adresse, Zertifikat); erwartet: ok in jeder Zeile.
sudo -u palaver /opt/palaver/bin/palaverd -env /opt/palaver/etc/palaverd.env doctor
- nicht geprüft: UDP-Ports; Sprache verbindet sich, bleibt aber stumm: Ports
Sicherung
- Datenbank: alle Daten; Nachrichten Ende-zu-Ende-verschlüsselt
/opt/palaver/etc: Konfiguration, LiveKit-Schlüssel
Sichere die Datenbank.
sudo -u palaver pg_dump -Fc palaver > "palaver-$(date +%F).dump"
Sichere die Konfiguration.
sudo tar -czf "palaver-etc-$(date +%F).tar.gz" -C /opt/palaver etc
Wiederherstellen
Voraussetzung: neuer Server, dieselbe Domain, Schritte 1–11.
Stelle die Konfiguration wieder her.
sudo tar -xzf palaver-etc-<date>.tar.gz -C /opt/palaver
sudo chown -R palaver:palaver /opt/palaver/etc
Halte palaverd an.
sudo systemctl stop palaverd
Destruktiv: Lösche die Datenbank des neuen Servers (alle seine Konten und Nachrichten).
sudo -u postgres dropdb palaver
Lege sie neu an und spiele die Sicherung ein.
sudo -u postgres createdb -O palaver palaver
sudo -u palaver pg_restore -d palaver palaver-<date>.dump
Starte alles.
sudo systemctl restart livekit palaverd
Deinstallieren
Halte die Dienste an und deaktiviere sie.
sudo systemctl disable --now palaverd livekit
Entferne die Units.
sudo rm /etc/systemd/system/palaverd.service /etc/systemd/system/livekit.service
sudo systemctl daemon-reload
Entferne die nginx-Site und lade nginx neu.
sudo rm /etc/nginx/sites-enabled/palaver /etc/nginx/sites-available/palaver /etc/nginx/snippets/palaver-web.conf
sudo nginx -t && sudo systemctl reload nginx
Entferne die Einstellungen für Journal und Logrotation.
sudo rm /etc/systemd/journald@palaver.conf /etc/logrotate.d/palaver
Entferne Programme und Web-Client.
sudo rm -r /opt/palaver/bin /opt/palaver/web
Destruktiv: Lösche die Datenbank und ihre Rolle (alle Konten, Nachrichten, Anhänge); nicht rückgängig zu machen.
sudo -u postgres dropdb palaver
sudo -u postgres dropuser palaver
Destruktiv: Lösche die Konfiguration (LiveKit-Schlüssel und -Geheimnis) und den Benutzer palaver.
sudo rm -r /opt/palaver/etc
sudo rmdir /opt/palaver
sudo userdel palaver
Destruktiv: Lösche das Zertifikat.
sudo certbot delete --cert-name chat.example.org
Destruktiv: Lösche die nginx-Logs der Site (/var/log/nginx/palaver); Journal-Namespace palaver läuft nach 14 Tagen aus.
sudo rm -r /var/log/nginx/palaver
Schließe die Ports in ufw; behalte 80 und 443, wenn andere Sites sie nutzen.
sudo ufw delete allow 80,443,7881/tcp
sudo ufw delete allow 3478,30000:30100,50000:60000/udp
Bleiben: Pakete postgresql, nginx, certbot.
Optional: vorhandenes Zertifikat
Für: Zertifikat, das schon in /etc/letsencrypt/live/<name>/ liegt (z. B. Wildcard über DNS-Prüfung), statt dem aus Schritt 10.
Zeige die Namen der Zertifikate an.
sudo certbot certificates
Schritt 10: Port-80-Site und certbot certonly überspringen.
Nach der vollständigen Site aus Schritt 10: öffne /etc/nginx/sites-available/palaver in einem Editor.
sudo vi /etc/nginx/sites-available/palaver
Ändere:
ssl_certificate,ssl_certificate_key:/etc/letsencrypt/live/chat.example.org/→/etc/letsencrypt/live/<cert-name>/
Hinter einem Heimrouter
- Router: öffentliche IPv4-Adresse, fest oder über dynamisches DNS; kein DS-Lite oder anderes Carrier-Grade-NAT
- alle Ports an den Server weiterleiten
/opt/palaver/etc/livekit.yaml: Zeile# node_ip:durchnode_ip: <public IPv4>ersetzen; bei jeder Adressänderung erneut
Starte LiveKit neu.
sudo systemctl restart livekit
- Prüfungen der öffentlichen Adresse in doctor schlagen ohne NAT-Loopback womöglich fehl; von einem anderen Gerät testen
Konfigurationsreferenz
- Datei:
/opt/palaver/etc/palaverd.env(KEY=VALUE, systemd-EnvironmentFile) - nach einer Änderung:
sudo systemctl restart palaverd
| Variable | Standard | Bedeutung |
|---|---|---|
PALAVER_DATABASE_URL |
– (Pflicht) | Verbindungszeichenfolge für PostgreSQL |
PALAVER_LISTEN |
127.0.0.1:8080 |
Adresse, auf der palaverd lauscht; diese Anleitung verwendet 127.0.0.1:8090 |
PALAVER_PUBLIC_URL |
Adresse, die der Client des Eigentümers verwendet hat | öffentliche Adresse (https://chat.example.org); doctor prüft sie |
PALAVER_LIVEKIT_URL |
– | LiveKit-Adresse für Clients (wss://chat.example.org/livekit) |
PALAVER_LIVEKIT_API_URL |
PALAVER_LIVEKIT_URL als http(s) |
LiveKit-API für palaverd |
PALAVER_LIVEKIT_API_KEY |
– | Schlüssel aus livekit.yaml |
PALAVER_LIVEKIT_API_SECRET |
– | Geheimnis aus livekit.yaml |
PALAVER_LIVEKIT_ROOM_PREFIX |
leer | Präfix der Raumnamen (a-z, 0-9, -) |
PALAVER_OPEN_REGISTRATION |
false |
true: Registrierung ohne Einladung; ein Admin lässt jedes Konto herein, bis dahin sieht es nur den Landekanal |
PALAVER_TRUSTED_PROXIES |
localhost | Adressen oder CIDR-Präfixe von Reverse-Proxys für X-Forwarded-For, durch Kommas getrennt |
PALAVER_AUDIT_DAYS |
14 |
Aufbewahrung des Audit-Logs (mit IP-Adressen) in Tagen |
PALAVER_WEB_URL |
– | Adresse des Web-Clients, wenn nicht / (derselbe Host wie PALAVER_PUBLIC_URL) |
PALAVER_DOGAN_URL |
https://www.lasse-tech.de/dogan |
Meldungen an Dogan; off: nie melden, der Eigentümer wird nicht gefragt |
PALAVER_DOGAN_ENROLL |
– | einmaliger Anmeldecode für Dogan; gilt als Zustimmung des Eigentümers |
PALAVER_CTL, PALAVER_UNIT, PALAVER_ENV_FILE |
der Befehl dieser Anleitung, palaverd, /opt/palaver/etc/palaverd.env |
was doctor in seinen Hinweisen nennt |
palaverd -env FILE <command>: lädt die Datei; schon in der Umgebung gesetzte Variablen haben Vorrang/opt/palaver/etc/livekit.yaml: Einstellungen von LiveKit (Dokumentation von LiveKit,config-sample.yamlin dessen Repository); nach einer Änderung:sudo systemctl restart livekit
Dateien
| Pfad | Inhalt |
|---|---|
/opt/palaver/bin/ |
palaverd, livekit-server |
/opt/palaver/web/ |
Web-Client |
/opt/palaver/etc/ |
palaverd.env, livekit.yaml (nur Benutzer palaver) |
/etc/systemd/system/palaverd.service, livekit.service |
Dienste |
/etc/systemd/journald@palaver.conf |
Aufbewahrung des Journals |
/etc/nginx/sites-available/palaver, /etc/nginx/snippets/palaver-web.conf |
nginx-Site |
/etc/logrotate.d/palaver, /var/log/nginx/palaver/ |
nginx-Logs |
Fehlersuche
doctor: welcher Teil fehlschlägt.
sudo -u palaver /opt/palaver/bin/palaverd -env /opt/palaver/etc/palaverd.env doctor
Was palaverd und LiveKit melden.
sudo journalctl --namespace=palaver -u palaverd -u livekit -n 100
Was nginx meldet.
sudo tail -n 50 /var/log/nginx/palaver/error.log
| Symptom | Ursache |
|---|---|
| certbot schlägt fehl | Port 80/TCP nicht erreichbar (Firewall des Hosters, Router) oder ein AAAA-Record, der woanders hinzeigt |
| Sprache verbindet sich, kein Ton | UDP-Ports (Voraussetzungen) |
could not change directory to "/home/…" von sudo -u postgres/sudo -u palaver |
harmlos (kein Zugriff auf dein Home-Verzeichnis) |
palaverd failed err="… PALAVER_DATABASE_URL is not set" |
-env /opt/palaver/etc/palaverd.env fehlt |
| Web-Client im Browser ohne Sprache | CSP: wss://chat.example.org fehlt im Snippet (doctor meldet es) |
Anfragen um Hilfe: Ausgabe aller drei anhängen.
Installing a Palaver server
| Component | Purpose | Path on chat.example.org |
|---|---|---|
| palaverd | accounts, channels, text | /api/ |
| LiveKit | voice, screen sharing | /livekit/ |
| web client | browser app | / |
| nginx | TLS (Let's Encrypt), reverse proxy | ports 80, 443 |
| PostgreSQL | data | – |
Updates: the update guide
Placeholders in the commands:
| Placeholder | Replace with |
|---|---|
chat.example.org |
your domain name |
you@example.org |
e-mail address for Let's Encrypt |
0.3.0 |
Palaver release |
https://<release host>/lasse-tech/palaver/releases/download |
release download location; until 1.0.0 on the project's internal Forgejo only |
<livekit-key>, <livekit-secret> |
output of step 6, "Generate the LiveKit API …" |
<cert-name> |
existing certificate only: its name |
vi |
editor of your choice |
1. Requirements
- OS: Debian 13 or a derivative based on Debian 13 or Ubuntu 24.04+ (e.g. Ubuntu, Linux Mint 22)
- architecture: amd64 (x86_64)
- public IPv4 address
- domain name with an A record to the server's public IPv4 address, e.g.
chat.example.org - e-mail address for Let's Encrypt
- shell access with
sudo - basic Linux administration skills
| Group | CPU | RAM | Disk |
|---|---|---|---|
| a few friends | 1 core | 2 GB | 20 GB |
| 20–30 people with screen sharing | 2 cores | 4 GB | 40 GB |
- bandwidth: ~1 Mbit/s per person in voice, +3–4 Mbit/s per viewer of a 1080p screen share
- attachments: up to 25 MiB each, stored in the database
Open ports to the server:
| Port | Protocol | For |
|---|---|---|
| 80 | TCP | Let's Encrypt, redirect to https |
| 443 | TCP | app, web client, voice signalling |
| 7881 | TCP | voice when UDP is blocked on the user's side |
| 3478 | UDP | STUN/TURN |
| 30000–30100 | UDP | TURN relay |
| 50000–60000 | UDP | voice and screen sharing |
Check the system.
. /etc/os-release; echo "$PRETTY_NAME | ${ID_LIKE:-$ID} | ${UBUNTU_CODENAME:-$VERSION_CODENAME} | $(uname -m)"
2. Packages
| Package | Requirement |
|---|---|
| PostgreSQL | 16 or newer, any source |
| nginx | any source |
| certbot | any source (apt, snap) |
| curl, ca-certificates, openssl | any source |
Install missing:
sudo apt-get update
sudo apt-get install postgresql nginx certbot curl ca-certificates openssl
3. User and directories
Create the system user palaver.
sudo useradd --system --home-dir /opt/palaver --no-create-home --shell /usr/sbin/nologin palaver
Create the directories; etc readable by palaver only.
sudo install -d -o root -g root -m 755 /opt/palaver /opt/palaver/bin /opt/palaver/web
sudo install -d -o palaver -g palaver -m 700 /opt/palaver/etc
4. PostgreSQL
Start PostgreSQL.
sudo systemctl enable --now postgresql
Create the database role and the database palaver; Unix socket, peer authentication, no password.
sudo -u postgres createuser palaver
sudo -u postgres createdb -O palaver palaver
5. Download Palaver
Download the server, the web client and the checksums.
curl -fLO "https://<release host>/lasse-tech/palaver/releases/download/v0.3.0/palaverd-0.3.0-linux-amd64"
curl -fLO "https://<release host>/lasse-tech/palaver/releases/download/v0.3.0/palaver-web-0.3.0.tar.gz"
curl -fLO "https://<release host>/lasse-tech/palaver/releases/download/v0.3.0/SHA256SUMS"
Verify both files; each line must end in OK.
sha256sum -c --ignore-missing SHA256SUMS
6. palaverd
Install the binary.
sudo install -m 755 palaverd-0.3.0-linux-amd64 /opt/palaver/bin/palaverd
Generate the LiveKit API key (<livekit-key>).
echo "API$(openssl rand -hex 8)"
Generate the LiveKit API secret (<livekit-secret>).
openssl rand -base64 36 | tr -d '/+='
Open /opt/palaver/etc/palaverd.env in an editor.
sudo vi /opt/palaver/etc/palaverd.env
Content (reference):
PALAVER_DATABASE_URL=postgres:///palaver?host=/var/run/postgresql
PALAVER_LISTEN=127.0.0.1:8090
PALAVER_PUBLIC_URL=https://chat.example.org
PALAVER_LIVEKIT_URL=wss://chat.example.org/livekit
PALAVER_LIVEKIT_API_URL=http://127.0.0.1:7880
PALAVER_LIVEKIT_API_KEY=<livekit-key>
PALAVER_LIVEKIT_API_SECRET=<livekit-secret>
PALAVER_OPEN_REGISTRATION=false
Make it readable by palaver only.
sudo chown palaver:palaver /opt/palaver/etc/palaverd.env
sudo chmod 600 /opt/palaver/etc/palaverd.env
Open /etc/systemd/system/palaverd.service in an editor.
sudo vi /etc/systemd/system/palaverd.service
Content:
[Unit]
Description=Palaver app server
After=network-online.target postgresql.service
Wants=network-online.target
[Service]
User=palaver
Group=palaver
EnvironmentFile=/opt/palaver/etc/palaverd.env
ExecStart=/opt/palaver/bin/palaverd serve
Restart=on-failure
RestartSec=2
LogNamespace=palaver
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
PrivateDevices=yes
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectControlGroups=yes
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
LockPersonality=yes
MemoryDenyWriteExecute=yes
[Install]
WantedBy=multi-user.target
7. LiveKit
Download LiveKit 1.13.7 (tested) from GitHub and verify it; the line must end in OK.
curl -fLO https://github.com/livekit/livekit/releases/download/v1.13.7/livekit_1.13.7_linux_amd64.tar.gz
echo "6634aeeb2fb1366b6723708ae4320b9d5408106a4c63457c5e845ae3979c90e2 livekit_1.13.7_linux_amd64.tar.gz" | sha256sum -c
Unpack and install the binary.
tar -xzf livekit_1.13.7_linux_amd64.tar.gz livekit-server
sudo install -m 755 livekit-server /opt/palaver/bin/livekit-server
Open /opt/palaver/etc/livekit.yaml in an editor.
sudo vi /opt/palaver/etc/livekit.yaml
Content; localhost only, built-in TURN/STUN:
port: 7880
bind_addresses: ["127.0.0.1"]
rtc:
tcp_port: 7881
port_range_start: 50000
port_range_end: 60000
use_external_ip: false
# node_ip: 203.0.113.10 # behind NAT only: the public IPv4
turn:
enabled: true
domain: chat.example.org
udp_port: 3478
relay_range_start: 30000
relay_range_end: 30100
room:
empty_timeout: 300
keys:
<livekit-key>: <livekit-secret>
logging:
level: info
Make it readable by palaver only.
sudo chown palaver:palaver /opt/palaver/etc/livekit.yaml
sudo chmod 600 /opt/palaver/etc/livekit.yaml
Open /etc/systemd/system/livekit.service in an editor.
sudo vi /etc/systemd/system/livekit.service
Content:
[Unit]
Description=LiveKit media server for Palaver
After=network-online.target
Wants=network-online.target
[Service]
User=palaver
Group=palaver
ExecStart=/opt/palaver/bin/livekit-server --config /opt/palaver/etc/livekit.yaml
Restart=on-failure
RestartSec=2
LogNamespace=palaver
LimitNOFILE=65536
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
PrivateDevices=yes
[Install]
WantedBy=multi-user.target
8. Logs
Open /etc/systemd/journald@palaver.conf in an editor.
sudo vi /etc/systemd/journald@palaver.conf
Content; keeps the journal of palaverd and LiveKit (namespace palaver) for 14 days:
[Journal]
MaxRetentionSec=14day
Create the directory for nginx's logs of the site.
sudo install -d -o www-data -g adm -m 750 /var/log/nginx/palaver
Open /etc/logrotate.d/palaver in an editor.
sudo vi /etc/logrotate.d/palaver
Content; rotates nginx's logs daily, keeps 14 days:
/var/log/nginx/palaver/*.log {
daily
rotate 13
missingok
notifempty
compress
delaycompress
create 0640 www-data adm
sharedscripts
postrotate
invoke-rc.d nginx rotate >/dev/null 2>&1
endscript
}
9. Web client
Unpack the web client.
sudo tar -xzf palaver-web-0.3.0.tar.gz --no-same-owner -C /opt/palaver/web
sudo chmod -R u=rwX,go=rX /opt/palaver/web
Open /etc/nginx/snippets/palaver-web.conf in an editor.
sudo vi /etc/nginx/snippets/palaver-web.conf
Content:
root /opt/palaver/web;
index index.html;
location / {
try_files $uri /index.html;
add_header Cache-Control "no-cache" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; worker-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; media-src 'self' blob: mediastream:; font-src 'self'; connect-src 'self' wss://chat.example.org; object-src 'none'; base-uri 'none'; form-action 'self'; frame-ancestors 'none'" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer" always;
add_header Permissions-Policy "camera=(), geolocation=(), payment=()" always;
add_header Strict-Transport-Security "max-age=31536000" always;
}
location /assets/ {
try_files $uri =404;
add_header Cache-Control "public, max-age=31536000, immutable" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; worker-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; media-src 'self' blob: mediastream:; font-src 'self'; connect-src 'self' wss://chat.example.org; object-src 'none'; base-uri 'none'; form-action 'self'; frame-ancestors 'none'" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Strict-Transport-Security "max-age=31536000" always;
}
10. nginx and certificate
Start nginx.
sudo systemctl enable --now nginx
Open /etc/nginx/sites-available/palaver in an editor.
sudo vi /etc/nginx/sites-available/palaver
Content; temporary port-80 site for the Let's Encrypt challenge:
server {
listen 80;
listen [::]:80;
server_name chat.example.org;
location /.well-known/acme-challenge/ { root /var/www/html; }
location / { return 404; }
}
Enable the site, check and load it.
sudo ln -sf /etc/nginx/sites-available/palaver /etc/nginx/sites-enabled/palaver
sudo nginx -t && sudo systemctl reload nginx
Get the certificate; automatic renewal, reloads nginx.
sudo certbot certonly --webroot -w /var/www/html -d chat.example.org -m you@example.org \
--agree-tos --no-eff-email --non-interactive \
--deploy-hook "systemctl reload nginx"
Open /etc/nginx/sites-available/palaver in an editor.
sudo vi /etc/nginx/sites-available/palaver
Content; full site:
server {
listen 80;
listen [::]:80;
server_name chat.example.org;
access_log /var/log/nginx/palaver/access.log;
error_log /var/log/nginx/palaver/error.log;
location /.well-known/acme-challenge/ {
root /var/www/html;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name chat.example.org;
ssl_certificate /etc/letsencrypt/live/chat.example.org/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/chat.example.org/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
access_log /var/log/nginx/palaver/access.log;
error_log /var/log/nginx/palaver/error.log;
client_max_body_size 64k;
# server push, one WebSocket per client
location = /api/events {
proxy_pass http://127.0.0.1:8090;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 1h;
proxy_send_timeout 1h;
}
# profile pictures, server icon: 5 MiB
location ~ ^/api/(me/avatar|server/icon)$ {
client_max_body_size 5m;
proxy_pass http://127.0.0.1:8090;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# attachments: 25 MiB
location ~ ^/api/channels/[0-9]+/attachments$ {
client_max_body_size 25m;
proxy_pass http://127.0.0.1:8090;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /api/ {
proxy_pass http://127.0.0.1:8090;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# LiveKit signalling; the trailing slash strips /livekit
location /livekit/ {
proxy_pass http://127.0.0.1:7880/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_read_timeout 1h;
proxy_send_timeout 1h;
}
include snippets/palaver-web.conf;
}
Check and load it.
sudo nginx -t && sudo systemctl reload nginx
11. Start
Load the units, start LiveKit and palaverd; the first start creates the database tables.
sudo systemctl daemon-reload
sudo systemctl enable --now livekit palaverd
Check that palaverd answers; expected: JSON.
curl -fsS http://127.0.0.1:8090/api/registration
12. First admin
Create an invite code for the first admin; single use, valid 7 days.
sudo -u palaver /opt/palaver/bin/palaverd -env /opt/palaver/etc/palaverd.env invite -role Admin -valid 168h
- register: Palaver app or
https://chat.example.orgin a browser → serverhttps://chat.example.org→ Register → code - first admin = server owner
- after the first sign-in: consent prompt for anonymous figures to Dogan (monitoring of Palaver servers); later under Settings › Server › Contribute
- invite others: Administration mode on (Settings › General › Administration, per device) → Invite people in the channel list
13. Check
Run doctor (configuration, database, palaverd, LiveKit, public address, certificate); expected: ok on every line.
sudo -u palaver /opt/palaver/bin/palaverd -env /opt/palaver/etc/palaverd.env doctor
- not checked: UDP ports; voice connects but stays silent: ports
Backup
- database: all data; messages end-to-end encrypted
/opt/palaver/etc: configuration, LiveKit key
Dump the database.
sudo -u palaver pg_dump -Fc palaver > "palaver-$(date +%F).dump"
Save the configuration.
sudo tar -czf "palaver-etc-$(date +%F).tar.gz" -C /opt/palaver etc
Restore
Prerequisite: new server, same domain, steps 1–11.
Restore the configuration.
sudo tar -xzf palaver-etc-<date>.tar.gz -C /opt/palaver
sudo chown -R palaver:palaver /opt/palaver/etc
Stop palaverd.
sudo systemctl stop palaverd
Destructive: delete the database of the new server (all its accounts and messages).
sudo -u postgres dropdb palaver
Create it again and load the dump.
sudo -u postgres createdb -O palaver palaver
sudo -u palaver pg_restore -d palaver palaver-<date>.dump
Start everything.
sudo systemctl restart livekit palaverd
Uninstall
Stop and disable the services.
sudo systemctl disable --now palaverd livekit
Remove the units.
sudo rm /etc/systemd/system/palaverd.service /etc/systemd/system/livekit.service
sudo systemctl daemon-reload
Remove the nginx site and reload nginx.
sudo rm /etc/nginx/sites-enabled/palaver /etc/nginx/sites-available/palaver /etc/nginx/snippets/palaver-web.conf
sudo nginx -t && sudo systemctl reload nginx
Remove the journal and log rotation settings.
sudo rm /etc/systemd/journald@palaver.conf /etc/logrotate.d/palaver
Remove programs and web client.
sudo rm -r /opt/palaver/bin /opt/palaver/web
Destructive: delete the database and its role (all accounts, messages, attachments); cannot be undone.
sudo -u postgres dropdb palaver
sudo -u postgres dropuser palaver
Destructive: delete the configuration (LiveKit key and secret) and the user palaver.
sudo rm -r /opt/palaver/etc
sudo rmdir /opt/palaver
sudo userdel palaver
Destructive: delete the certificate.
sudo certbot delete --cert-name chat.example.org
Destructive: delete the site's nginx logs (/var/log/nginx/palaver); journal namespace palaver expires after 14 days.
sudo rm -r /var/log/nginx/palaver
Close the ports in ufw; keep 80 and 443 if other sites use them.
sudo ufw delete allow 80,443,7881/tcp
sudo ufw delete allow 3478,30000:30100,50000:60000/udp
Kept: packages postgresql, nginx, certbot.
Optional: existing certificate
For: certificate already in /etc/letsencrypt/live/<name>/ (e.g. wildcard via DNS challenge) instead of step 10's.
List the certificate names.
sudo certbot certificates
Step 10: skip the port-80 site and certbot certonly.
After step 10's full site: open /etc/nginx/sites-available/palaver in an editor.
sudo vi /etc/nginx/sites-available/palaver
Change:
ssl_certificate,ssl_certificate_key:/etc/letsencrypt/live/chat.example.org/→/etc/letsencrypt/live/<cert-name>/
Behind a home router
- router: public IPv4 address, static or via dynamic DNS; no DS-Lite or other carrier-grade NAT
- forward all ports to the server
/opt/palaver/etc/livekit.yaml: replace the# node_ip:line withnode_ip: <public IPv4>; again on every address change
Restart LiveKit.
sudo systemctl restart livekit
- doctor's public-address checks may fail without NAT loopback; test from another device
Configuration reference
- file:
/opt/palaver/etc/palaverd.env(KEY=VALUE, systemd EnvironmentFile) - after a change:
sudo systemctl restart palaverd
| Variable | Default | Meaning |
|---|---|---|
PALAVER_DATABASE_URL |
– (required) | PostgreSQL connection string |
PALAVER_LISTEN |
127.0.0.1:8080 |
listen address; this guide uses 127.0.0.1:8090 |
PALAVER_PUBLIC_URL |
address the owner's client used | public address (https://chat.example.org); doctor checks it |
PALAVER_LIVEKIT_URL |
– | LiveKit URL for clients (wss://chat.example.org/livekit) |
PALAVER_LIVEKIT_API_URL |
PALAVER_LIVEKIT_URL as http(s) |
LiveKit API for palaverd |
PALAVER_LIVEKIT_API_KEY |
– | key from livekit.yaml |
PALAVER_LIVEKIT_API_SECRET |
– | secret from livekit.yaml |
PALAVER_LIVEKIT_ROOM_PREFIX |
empty | room name prefix (a-z, 0-9, -) |
PALAVER_OPEN_REGISTRATION |
false |
true: sign-up without invite; an admin lets each account in, until then it sees the landing channel only |
PALAVER_TRUSTED_PROXIES |
localhost | addresses or CIDR prefixes of reverse proxies for X-Forwarded-For, comma-separated |
PALAVER_AUDIT_DAYS |
14 |
retention of the audit log (with IP addresses) in days |
PALAVER_WEB_URL |
– | web client address if not / (same host as PALAVER_PUBLIC_URL) |
PALAVER_DOGAN_URL |
https://www.lasse-tech.de/dogan |
Dogan reporting; off: never report, the owner is not asked |
PALAVER_DOGAN_ENROLL |
– | one-time Dogan enrollment code; counts as the owner's consent |
PALAVER_CTL, PALAVER_UNIT, PALAVER_ENV_FILE |
this guide's command, palaverd, /opt/palaver/etc/palaverd.env |
what doctor names in its hints |
palaverd -env FILE <command>: loads the file; variables already in the environment take precedence/opt/palaver/etc/livekit.yaml: LiveKit settings (LiveKit documentation,config-sample.yamlin its repository); after a change:sudo systemctl restart livekit
Files
| Path | Content |
|---|---|
/opt/palaver/bin/ |
palaverd, livekit-server |
/opt/palaver/web/ |
web client |
/opt/palaver/etc/ |
palaverd.env, livekit.yaml (user palaver only) |
/etc/systemd/system/palaverd.service, livekit.service |
services |
/etc/systemd/journald@palaver.conf |
journal retention |
/etc/nginx/sites-available/palaver, /etc/nginx/snippets/palaver-web.conf |
nginx site |
/etc/logrotate.d/palaver, /var/log/nginx/palaver/ |
nginx logs |
Troubleshooting
Doctor: which part fails.
sudo -u palaver /opt/palaver/bin/palaverd -env /opt/palaver/etc/palaverd.env doctor
What palaverd and LiveKit say.
sudo journalctl --namespace=palaver -u palaverd -u livekit -n 100
What nginx says.
sudo tail -n 50 /var/log/nginx/palaver/error.log
| Symptom | Cause |
|---|---|
| certbot fails | port 80/TCP not reachable (hoster's firewall, router), or an AAAA record pointing elsewhere |
| voice connects, no sound | UDP ports (requirements) |
could not change directory to "/home/…" from sudo -u postgres/sudo -u palaver |
harmless (no access to your home directory) |
palaverd failed err="… PALAVER_DATABASE_URL is not set" |
-env /opt/palaver/etc/palaverd.env missing |
| web client without voice in the browser | CSP: wss://chat.example.org missing in the snippet (doctor reports it) |
Help requests: attach the output of all three.