feat: add universal Synapse install.sh for bare-metal/Proxmox-LXC
Own installer instead of relying only on the external bashclub script: builds homeserver.yaml straight from our homeserver.yaml.sample (so it inherits TalkTime's security defaults — no federation, no public registration — automatically), sets up Postgres, a systemd service, and prints the admin token ready to paste into backend/.env. Works identically in a Proxmox LXC and on bare metal (both are just a Debian userland). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TBf3yfnnHzMQ5qhLV2285A
This commit is contained in:
1 parent
51426a944c
commit
90669b4568
2 files changed
+253
-12
No files matched your search
+32
-12
@@ -1,14 +1,18 @@
|
||||
# Synapse Setup (lokal/Server)
|
||||
|
||||
Minimal-Setup für einen Matrix-Synapse-Homeserver als Backend für TalkTime. Drei Installationswege — Docker (empfohlen, einfacher zu warten), Bare-Metal manuell (Debian/Ubuntu, kein Docker verfügbar/gewünscht), oder ein fertiges Autoinstaller-Skript für Proxmox-LXC.
|
||||
Minimal-Setup für einen Matrix-Synapse-Homeserver als Backend für TalkTime. Installationswege:
|
||||
|
||||
## Option C: Autoinstaller für Proxmox-LXC
|
||||
- **Option A — Docker** (empfohlen, einfacher zu warten)
|
||||
- **Option B — Bare-Metal/Proxmox-LXC**, per eigenem [`install.sh`](install.sh) (universell, setzt gleich alle TalkTime-Defaults richtig) oder manuell Schritt für Schritt
|
||||
- **Option C — externer Autoinstaller** ([bashclub/zamba-lxc-toolbox](https://github.com/bashclub/zamba-lxc-toolbox/tree/main/src/matrix)), falls Nginx+Element Web gleich mit dabei sein sollen
|
||||
|
||||
[bashclub/zamba-lxc-toolbox](https://github.com/bashclub/zamba-lxc-toolbox/tree/main/src/matrix) bringt ein fertiges `install-service.sh` für Debian-LXC mit: installiert Synapse (apt-Repo) + PostgreSQL + nginx + Element Web, stellt auf Postgres um, setzt `registration_shared_secret`, legt per `register_new_matrix_user` einen Admin-User an, generiert Self-Signed-TLS.
|
||||
## Option C: Externer Autoinstaller (bashclub/zamba-lxc-toolbox)
|
||||
|
||||
Praktisch als Schnellstart, wenn ein Proxmox-LXC zur Verfügung steht und Nginx+Element gleich mit dabei sein sollen. Skript vor Ausführung selbst prüfen (Repo-README/`zamba.conf` lesen) — nicht ungeprüft als root laufen lassen. Nach Lauf trotzdem `SYNAPSE_ADMIN_TOKEN` wie in Schritt 7/8 unten beschrieben ziehen und in TalkTime eintragen; `enable_registration` danach auf `false` setzen, da TalkTime die Benutzeranlage selbst übernimmt (siehe Schritt 5).
|
||||
Alternative zu `install.sh`, wenn zusätzlich Nginx+Element Web (eigenständiger Matrix-Webclient, nicht Teil von TalkTime) gleich mit installiert werden sollen. `install-service.sh` installiert Synapse (apt-Repo) + PostgreSQL + nginx + Element Web, stellt auf Postgres um, setzt `registration_shared_secret`, legt per `register_new_matrix_user` einen Admin-User an, generiert Self-Signed-TLS.
|
||||
|
||||
Für volle Kontrolle (kein extra nginx/Element, schlankeres Setup) weiter mit Option A oder B unten.
|
||||
Skript vor Ausführung selbst prüfen (Repo-README/`zamba.conf` lesen) — nicht ungeprüft als root laufen lassen. Nach Lauf trotzdem `SYNAPSE_ADMIN_TOKEN` wie in Option B "Admin-Zugang" beschrieben ziehen und in TalkTime eintragen; `enable_registration` danach auf `false` setzen, da TalkTime die Benutzeranlage selbst übernimmt.
|
||||
|
||||
Für ein schlankeres Setup ohne extra Nginx/Element: `install.sh` in Option B unten.
|
||||
|
||||
## Voraussetzungen (beide Varianten)
|
||||
|
||||
@@ -97,9 +101,25 @@ Das zurückgegebene `access_token` in `backend/.env` als `SYNAPSE_ADMIN_TOKEN` e
|
||||
|
||||
---
|
||||
|
||||
## Option B: Bare-Metal (Debian/Ubuntu, kein Docker)
|
||||
## Option B: Bare-Metal (Debian/Ubuntu oder Proxmox-LXC, kein Docker)
|
||||
|
||||
### 1. Systempakete + venv
|
||||
### Schnellweg: `install.sh`
|
||||
|
||||
Eigener, universeller Installer — macht alle Schritte unten automatisch inklusive TalkTime-Sicherheits-Defaults (Registrierung/Föderation aus, eigene Secrets, Systemd-Service, Admin-User+Token):
|
||||
|
||||
```bash
|
||||
sudo ./synapse/install.sh chat.example.org
|
||||
```
|
||||
|
||||
Läuft identisch in einem Proxmox-LXC (Debian-Template) und auf echtem Bare-Metal — beides ist aus Sicht des Skripts nur ein Debian-Userland mit `apt-get`. Am Ende gibt es `SYNAPSE_BASE_URL`/`SYNAPSE_ADMIN_TOKEN`/`SYNAPSE_SERVER_NAME` fix und fertig zum Eintragen in `backend/.env` aus.
|
||||
|
||||
Optionale Env-Vars: `INSTALL_DIR` (default `/opt/synapse`), `DB_PASSWORD`, `ADMIN_USER`, `ADMIN_PASSWORD` (sonst zufällig generiert), `SYNAPSE_PORT` (default 8008). Nutzt `homeserver.yaml.sample` aus diesem Ordner als Vorlage — bei Änderungen an der Vorlage (siehe oben) übernimmt der Installer sie automatisch.
|
||||
|
||||
Danach direkt weiter zu **"Reverse Proxy + TLS"** unten.
|
||||
|
||||
### Manuell, Schritt für Schritt (falls `install.sh` nicht passt, z. B. anderer Linux-Flavor)
|
||||
|
||||
#### 1. Systempakete + venv
|
||||
|
||||
```bash
|
||||
sudo apt update
|
||||
@@ -113,7 +133,7 @@ sudo -u postgres createdb -O synapse synapse -E UTF8 --locale=C --template=templ
|
||||
|
||||
`-P` fragt beim Anlegen nach dem Passwort für den `synapse`-DB-User.
|
||||
|
||||
### 2. Synapse installieren
|
||||
#### 2. Synapse installieren
|
||||
|
||||
```bash
|
||||
sudo mkdir -p /opt/synapse
|
||||
@@ -123,7 +143,7 @@ python3 -m venv /opt/synapse/venv
|
||||
/opt/synapse/venv/bin/pip install "matrix-synapse[postgres]"
|
||||
```
|
||||
|
||||
### 3. Konfiguration generieren
|
||||
#### 3. Konfiguration generieren
|
||||
|
||||
```bash
|
||||
cd /opt/synapse
|
||||
@@ -136,11 +156,11 @@ cd /opt/synapse
|
||||
|
||||
Erzeugt `homeserver.yaml` + Signing-Key im aktuellen Verzeichnis.
|
||||
|
||||
### 4. Datenbank umstellen, Registrierung absichern
|
||||
#### 4. Datenbank umstellen, Registrierung absichern
|
||||
|
||||
Wie Option A, Abschnitt 4 — [`homeserver.yaml.sample`](homeserver.yaml.sample) nach `/opt/synapse/homeserver.yaml` kopieren und Platzhalter ersetzen, nur `database.args.host: localhost` statt `synapse-db`.
|
||||
|
||||
### 5. Als systemd-Dienst starten
|
||||
#### 5. Als systemd-Dienst starten
|
||||
|
||||
```ini
|
||||
# /etc/systemd/system/matrix-synapse.service
|
||||
@@ -172,7 +192,7 @@ Health-Check:
|
||||
curl http://localhost:8008/health
|
||||
```
|
||||
|
||||
### 6. Admin-Zugang für TalkTime einrichten
|
||||
#### 6. Admin-Zugang für TalkTime einrichten
|
||||
|
||||
```bash
|
||||
/opt/synapse/venv/bin/register_new_matrix_user \
|
||||
|
||||
Executable
+221
@@ -0,0 +1,221 @@
|
||||
#!/usr/bin/env bash
|
||||
# Universal Synapse installer for TalkTime — Debian/Ubuntu, works in a Proxmox
|
||||
# LXC or on bare metal identically (both are just a Debian userland).
|
||||
#
|
||||
# What it does, in order:
|
||||
# 1. Install system packages + PostgreSQL
|
||||
# 2. Create a dedicated Postgres role/database for Synapse
|
||||
# 3. Install matrix-synapse into a venv (pip, not apt — works on any
|
||||
# Debian/Ubuntu version without depending on the matrix.org apt repo)
|
||||
# 4. Generate homeserver.yaml from synapse/homeserver.yaml.sample with all
|
||||
# secrets filled in and TalkTime's secure defaults (registration off,
|
||||
# federation off)
|
||||
# 5. Install + start a systemd service
|
||||
# 6. Create the admin user and fetch its access token
|
||||
#
|
||||
# Usage:
|
||||
# sudo ./install.sh chat.example.org
|
||||
# sudo SYNAPSE_SERVER_NAME=chat.example.org ADMIN_USER=admin ./install.sh
|
||||
#
|
||||
# Idempotent-ish: re-running skips steps whose result already exists
|
||||
# (venv, database, service file) but always re-registers nothing — the
|
||||
# admin user is only created once (step 6 fails loudly if it already exists,
|
||||
# that's fine, just note the token from the first run).
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# ---- config (env vars override) --------------------------------------------
|
||||
SERVER_NAME="${1:-${SYNAPSE_SERVER_NAME:-}}"
|
||||
INSTALL_DIR="${INSTALL_DIR:-/opt/synapse}"
|
||||
SYNAPSE_USER="${SYNAPSE_USER:-synapse}"
|
||||
DB_NAME="${DB_NAME:-synapse}"
|
||||
DB_USER="${DB_USER:-synapse}"
|
||||
DB_PASSWORD="${DB_PASSWORD:-$(openssl rand -hex 24)}"
|
||||
ADMIN_USER="${ADMIN_USER:-admin}"
|
||||
ADMIN_PASSWORD="${ADMIN_PASSWORD:-$(openssl rand -hex 16)}"
|
||||
SYNAPSE_PORT="${SYNAPSE_PORT:-8008}"
|
||||
|
||||
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"
|
||||
|
||||
if [[ -z "$SERVER_NAME" ]]; then
|
||||
echo "Usage: $0 <server-name> (e.g. chat.example.org)" >&2
|
||||
echo "Or set SYNAPSE_SERVER_NAME=... as an env var." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
echo "Must run as root (sudo $0 ...)." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v apt-get &>/dev/null; then
|
||||
echo "This installer only supports Debian/Ubuntu (apt-get not found)." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log() { echo -e "\n== $* =="; }
|
||||
|
||||
# ---- 1. system packages -----------------------------------------------------
|
||||
log "Installing system packages"
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt-get update -qq
|
||||
apt-get install -y -qq \
|
||||
python3-dev python3-pip python3-venv \
|
||||
libpq-dev build-essential libffi-dev libssl-dev libjpeg-dev libxslt1-dev \
|
||||
postgresql openssl >/dev/null
|
||||
|
||||
# ---- 2. postgres role + database -------------------------------------------
|
||||
log "Setting up PostgreSQL database"
|
||||
if ! sudo -u postgres psql -tAc "SELECT 1 FROM pg_roles WHERE rolname='${DB_USER}'" | grep -q 1; then
|
||||
sudo -u postgres psql -c "CREATE ROLE ${DB_USER} WITH LOGIN PASSWORD '${DB_PASSWORD}';" >/dev/null
|
||||
else
|
||||
echo "Role ${DB_USER} already exists, updating password."
|
||||
sudo -u postgres psql -c "ALTER ROLE ${DB_USER} WITH PASSWORD '${DB_PASSWORD}';" >/dev/null
|
||||
fi
|
||||
|
||||
if ! sudo -u postgres psql -tAc "SELECT 1 FROM pg_database WHERE datname='${DB_NAME}'" | grep -q 1; then
|
||||
sudo -u postgres createdb -O "${DB_USER}" "${DB_NAME}" -E UTF8 --locale=C --template=template0
|
||||
else
|
||||
echo "Database ${DB_NAME} already exists, reusing."
|
||||
fi
|
||||
|
||||
# ---- 3. synapse into a venv --------------------------------------------------
|
||||
log "Installing matrix-synapse (this can take a few minutes)"
|
||||
mkdir -p "${INSTALL_DIR}"
|
||||
if ! id "${SYNAPSE_USER}" &>/dev/null; then
|
||||
useradd -r -d "${INSTALL_DIR}" -s /usr/sbin/nologin "${SYNAPSE_USER}"
|
||||
fi
|
||||
|
||||
if [[ ! -d "${INSTALL_DIR}/venv" ]]; then
|
||||
python3 -m venv "${INSTALL_DIR}/venv"
|
||||
fi
|
||||
"${INSTALL_DIR}/venv/bin/pip" install --upgrade pip -q
|
||||
"${INSTALL_DIR}/venv/bin/pip" install -q "matrix-synapse[postgres]"
|
||||
|
||||
# ---- 4. homeserver.yaml from our template -----------------------------------
|
||||
log "Writing homeserver.yaml"
|
||||
if [[ ! -f "${INSTALL_DIR}/${SERVER_NAME}.signing.key" ]]; then
|
||||
"${INSTALL_DIR}/venv/bin/python" -m synapse.app.homeserver \
|
||||
--server-name="${SERVER_NAME}" \
|
||||
--config-path="${INSTALL_DIR}/homeserver.generated.yaml" \
|
||||
--generate-config \
|
||||
--report-stats=no \
|
||||
--data-directory="${INSTALL_DIR}" >/dev/null
|
||||
rm -f "${INSTALL_DIR}/homeserver.generated.yaml" "${INSTALL_DIR}/${SERVER_NAME}.log.config.generated"
|
||||
fi
|
||||
|
||||
REGISTRATION_SECRET="$(openssl rand -hex 32)"
|
||||
MACAROON_SECRET="$(openssl rand -hex 32)"
|
||||
FORM_SECRET="$(openssl rand -hex 32)"
|
||||
|
||||
sed \
|
||||
-e "s|<chat.talktime.local>|${SERVER_NAME}|g" \
|
||||
-e "s|<db-passwort>|${DB_PASSWORD}|g" \
|
||||
-e "s|<langer-zufalls-string>|PLACEHOLDER|g" \
|
||||
-e "s|/data/|${INSTALL_DIR}/|g" \
|
||||
-e "s|host: synapse-db|host: localhost|g" \
|
||||
-e "s|user: synapse|user: ${DB_USER}|g" \
|
||||
-e "s|database: synapse|database: ${DB_NAME}|g" \
|
||||
"${SCRIPT_DIR}/homeserver.yaml.sample" > "${INSTALL_DIR}/homeserver.yaml"
|
||||
|
||||
mkdir -p "${INSTALL_DIR}/media_store"
|
||||
|
||||
# Replace the three PLACEHOLDER secrets one at a time so each gets its own value.
|
||||
python3 - "$INSTALL_DIR/homeserver.yaml" "$REGISTRATION_SECRET" "$MACAROON_SECRET" "$FORM_SECRET" <<'PYEOF'
|
||||
import sys
|
||||
path, reg, mac, form = sys.argv[1:5]
|
||||
with open(path) as f:
|
||||
content = f.read()
|
||||
for value in (reg, mac, form):
|
||||
content = content.replace("PLACEHOLDER", value, 1)
|
||||
with open(path, "w") as f:
|
||||
f.write(content)
|
||||
PYEOF
|
||||
|
||||
# Also write log config referenced by our template (Synapse needs the file to exist).
|
||||
cat > "${INSTALL_DIR}/${SERVER_NAME}.log.config" <<EOF
|
||||
version: 1
|
||||
formatters:
|
||||
precise:
|
||||
format: '%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(message)s'
|
||||
handlers:
|
||||
console:
|
||||
class: logging.StreamHandler
|
||||
formatter: precise
|
||||
loggers:
|
||||
synapse:
|
||||
level: INFO
|
||||
root:
|
||||
level: INFO
|
||||
handlers: [console]
|
||||
disable_existing_loggers: false
|
||||
EOF
|
||||
|
||||
chown -R "${SYNAPSE_USER}:${SYNAPSE_USER}" "${INSTALL_DIR}"
|
||||
|
||||
# ---- 5. systemd service -------------------------------------------------------
|
||||
log "Installing systemd service"
|
||||
cat > /etc/systemd/system/matrix-synapse.service <<EOF
|
||||
[Unit]
|
||||
Description=Matrix Synapse Homeserver (TalkTime)
|
||||
After=network.target postgresql.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=${SYNAPSE_USER}
|
||||
WorkingDirectory=${INSTALL_DIR}
|
||||
ExecStart=${INSTALL_DIR}/venv/bin/python -m synapse.app.homeserver -c ${INSTALL_DIR}/homeserver.yaml
|
||||
Restart=on-failure
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl enable --now matrix-synapse
|
||||
|
||||
log "Waiting for Synapse to come up"
|
||||
for _ in $(seq 1 30); do
|
||||
if curl -fs "http://localhost:${SYNAPSE_PORT}/health" >/dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
if ! curl -fs "http://localhost:${SYNAPSE_PORT}/health" >/dev/null 2>&1; then
|
||||
echo "Synapse did not come up in time — check: journalctl -u matrix-synapse -e" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ---- 6. admin user + access token -------------------------------------------
|
||||
log "Creating admin user"
|
||||
"${INSTALL_DIR}/venv/bin/register_new_matrix_user" \
|
||||
-c "${INSTALL_DIR}/homeserver.yaml" \
|
||||
-u "${ADMIN_USER}" -p "${ADMIN_PASSWORD}" -a \
|
||||
"http://localhost:${SYNAPSE_PORT}"
|
||||
|
||||
ADMIN_TOKEN="$(curl -fs -XPOST "http://localhost:${SYNAPSE_PORT}/_matrix/client/v3/login" \
|
||||
-d "{\"type\":\"m.login.password\",\"user\":\"${ADMIN_USER}\",\"password\":\"${ADMIN_PASSWORD}\"}" \
|
||||
| python3 -c 'import sys,json; print(json.load(sys.stdin)["access_token"])')"
|
||||
|
||||
cat <<EOF
|
||||
|
||||
== Done ==
|
||||
|
||||
Synapse is running at http://localhost:${SYNAPSE_PORT} (server_name: ${SERVER_NAME}).
|
||||
Federation is disabled by default — this is a private homeserver for TalkTime.
|
||||
|
||||
Add to backend/.env:
|
||||
|
||||
SYNAPSE_BASE_URL=http://localhost:${SYNAPSE_PORT}
|
||||
SYNAPSE_ADMIN_TOKEN=${ADMIN_TOKEN}
|
||||
SYNAPSE_SERVER_NAME=${SERVER_NAME}
|
||||
|
||||
Admin login (keep safe, only needed if you need to log into Synapse directly):
|
||||
user: ${ADMIN_USER}
|
||||
password: ${ADMIN_PASSWORD}
|
||||
|
||||
Database password (only needed for manual DB access): ${DB_PASSWORD}
|
||||
|
||||
Put Synapse behind a TLS-terminating reverse proxy before exposing it publicly
|
||||
— see synapse/README.md "Reverse Proxy + TLS".
|
||||
EOF
|
||||
Reference in new issue
Block a user