From 37e65300245be45d4000797b3ada53c68022fc26 Mon Sep 17 00:00:00 2001 From: Filip Wandzio Date: Wed, 1 Oct 2025 22:21:25 +0200 Subject: Implement use flags for subcommants Optimize synapse pipeline --- Makefile | 14 +- wh.1 | 67 ++++++++ wh.sh | 500 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ whiterabbit.1 | 51 ------ whiterabbit.sh | 417 ----------------------------------------------- 5 files changed, 574 insertions(+), 475 deletions(-) create mode 100644 wh.1 create mode 100755 wh.sh delete mode 100644 whiterabbit.1 delete mode 100755 whiterabbit.sh diff --git a/Makefile b/Makefile index fe1c42b..5a8c27d 100644 --- a/Makefile +++ b/Makefile @@ -4,12 +4,12 @@ MANDIR ?= $(PREFIX)/share/man/man1 install: @echo "Installing whiterabbit..." - install -Dm755 whiterabbit.sh $(BINDIR)/whiterabbit - install -Dm644 whiterabbit.1 $(MANDIR)/whiterabbit.1 - @echo "Installed to $(BINDIR)/whiterabbit and man page to $(MANDIR)/whiterabbit.1" + install -Dm755 wh.sh $(BINDIR)/wh + install -Dm644 wh.1 $(MANDIR)/wh.1 + @echo "Installed to $(BINDIR)/whand man page to $(MANDIR)/wh.1" uninstall: - @echo "Removing whiterabbit..." - rm -f $(BINDIR)/whiterabbit - rm -f $(MANDIR)/whiterabbit.1 - @echo "Removed whiterabbit and its man page" + @echo "Removing wh..." + rm -f $(BINDIR)/wh + rm -f $(MANDIR)/wh.1 + @echo "Removed wh and its man page" diff --git a/wh.1 b/wh.1 new file mode 100644 index 0000000..8a6230f --- /dev/null +++ b/wh.1 @@ -0,0 +1,67 @@ +.\" Manpage for whiterabbit +.TH WHITERABBIT 1 "2025-09-25" "1.0.0" "whiterabbit manual" +.SH NAME +whiterabbit \- auto-configure Matrix homeservers (Dendrite or Synapse) +.SH SYNOPSIS +.B whiterabbit +[\fIturn\fR|\fIdendrite\fR|\fIsynapse\fR|\fIlist\fR|\fIremove \fR| +\fI-t\fR|\fI-d\fR|\fI-s\fR|\fI-l\fR|\fI-r \fR] +.SH DESCRIPTION +whiterabbit sets up Matrix homeservers with a global Coturn server and Nginx/Let's Encrypt support. + +Main commands and their short flag equivalents: +.TP +.B turn, -t +Install or configure the global Coturn server. +.TP +.B dendrite, -d +Add a new Matrix Dendrite server. +.TP +.B synapse, -s +Add a new Matrix Synapse server. +.TP +.B list, -l +List all configured Matrix servers. +.TP +.B remove , -r +Remove a Matrix server by domain. + +.SH EXAMPLES +.TP +whiterabbit turn +Set up the global Coturn server. +.TP +whiterabbit -t +Same as above using flag. +.TP +whiterabbit dendrite +Add a Dendrite server with TLS and Nginx. +.TP +whiterabbit -d +Same as above using flag. +.TP +whiterabbit synapse +Add a Synapse server with TLS and Nginx. +.TP +whiterabbit -s +Same as above using flag. +.TP +whiterabbit list +Show all servers. +.TP +whiterabbit -l +Same as above using flag. +.TP +whiterabbit remove matrix.example.com +Remove a server. +.TP +whiterabbit -r matrix.example.com +Same as above using flag. + +.SH NOTES +All Matrix servers share the same Coturn instance. +TLS certificates are issued automatically via Let's Encrypt. +Requires docker, docker-compose, nginx, certbot, and coturn. + +.SH AUTHOR +Filip Wandzio diff --git a/wh.sh b/wh.sh new file mode 100755 index 0000000..db1c12d --- /dev/null +++ b/wh.sh @@ -0,0 +1,500 @@ +#!/bin/sh +set -eu + +BASE_DIR="/opt/matrix" + +DOCKER_COMPOSE=$(command -v docker-compose || command -v docker compose) || { + echo "[ERROR] docker-compose or docker compose not found" >&2 + exit 1 +} + +usage() { + cat <<'EOF' +whiterabbit: auto-configure Matrix homeservers (Dendrite or Synapse) +with a global Coturn instance and Nginx + Let's Encrypt proxy. + +Main actions: + turn Install or configure the global Coturn server + dendrite Add a new Matrix server (Dendrite) + synapse Add a new Matrix server (Synapse) + list Show all configured Matrix servers + remove Remove a Matrix server by domain +EOF + exit 1 +} + +require_nonempty() { + VAR_NAME="$1" + VAR_VALUE="$2" + [ -n "$VAR_VALUE" ] || { + echo "[ERROR] $VAR_NAME cannot be empty" >&2 + exit 1 + } +} + +list_servers() { + echo "=== Installed servers ===" + for dir in "$BASE_DIR"/*; do + [ -d "$dir" ] || continue + name=$(basename "$dir") + + status=$(docker ps --filter "name=^${name}$" --format "{{.Status}}") + ports=$(docker ps --filter "name=^${name}$" --format "{{.Ports}}" | sed 's/, /\n /g') + + [ -n "$status" ] && { + echo "- $name [RUNNING] on:" + echo " $ports" + } || echo "- $name [STOPPED]" + done +} + +install_turn() { + echo "=== Installing global Coturn ===" + printf "TURN domain (eg. turn.example.com): " + read -r TURN_DOMAIN + require_nonempty TURN_DOMAIN "$TURN_DOMAIN" + + printf "TURN IP (eg. 127.0.0.1): " + read -r TURN_SERVER_IP + require_nonempty TURN_SERVER_IP "$TURN_SERVER_IP" + + printf "Listening device (eg. eth0): " + read -r TURN_LISTENING_DEVICE + require_nonempty TURN_LISTENING_DEVICE "$TURN_LISTENING_DEVICE" + + printf "TURN shared secret: " + read -r TURN_SECRET + require_nonempty TURN_SECRET "$TURN_SECRET" + + mkdir -p /etc/turn + cat < /etc/turn/turnserver.conf +listening-device=$TURN_LISTENING_DEVICE +listening-port=3478 +tls-listening-port=5349 +listening-ip=$TURN_SERVER_IP +min-port=49152 +max-port=65535 +use-auth-secret +static-auth-secret=$TURN_SECRET +realm=$TURN_DOMAIN +syslog +no-rfc5780 +no-stun-backward-compatibility +response-origin-only-with-rfc5780 +EOF + + echo "$TURN_DOMAIN" > /etc/turn/domain + echo "$TURN_SECRET" > /etc/turn/secret + + case $(command -v systemctl >/dev/null && echo y || echo n) in + y) systemctl enable --now coturn || true ;; + n) service coturn start || true ;; + esac + + echo "[OK] Global Coturn configured ($TURN_DOMAIN)" +} + +common_prompts() { + printf "Matrix domain (eg. matrix.example.com): " + read -r MATRIX_DOMAIN + require_nonempty MATRIX_DOMAIN "$MATRIX_DOMAIN" + + printf "Let's Encrypt certificate email: " + read -r EMAIL + require_nonempty EMAIL "$EMAIL" + DB_PASS=$(tr -dc 'A-Za-z0-9' "/etc/nginx/sites-available/$DOMAIN" +server { + listen 80; + server_name $DOMAIN; + + location /.well-known/matrix/server { + default_type application/json; + return 200 '{ "m.server": "$DOMAIN:443" }'; + } + + location /.well-known/matrix/client { + default_type application/json; + return 200 '{ + "m.homeserver": { "base_url": "https://$DOMAIN" }, + "m.identity_server": { "base_url": "https://vector.im" } + }'; + } + + location / { + proxy_pass http://127.0.0.1:$SERVICE_PORT; + proxy_set_header Host \$host; + proxy_set_header X-Forwarded-For \$remote_addr; + } +} +EOF + + ln -sf "/etc/nginx/sites-available/$DOMAIN" "/etc/nginx/sites-enabled/$DOMAIN" + nginx -t || { echo "[ERROR] Invalid nginx config"; exit 1; } + + + case $(command -v systemctl >/dev/null && echo y || echo n) in + y) systemctl reload nginx ;; + n) nginx -s reload ;; + esac + + case $(command -v certbot >/dev/null && echo y || echo n) in + y) certbot --nginx --non-interactive --agree-tos -m "$EMAIL" -d "$DOMAIN" || { + echo "[WARN] Certbot failed for $DOMAIN" + } ;; + n) echo "[WARN] Certbot not installed, skipping TLS setup" ;; + esac +} + + +install_dendrite() { + echo "=== Installing Matrix Dendrite ===" + common_prompts + + INSTALL_DIR="$BASE_DIR/$MATRIX_DOMAIN" + mkdir -p "$INSTALL_DIR/config" + cd "$INSTALL_DIR" || exit 1 + + cat < .env +POSTGRES_HOSTNAME=postgres +POSTGRES_VERSION=15-alpine +POSTGRES_USER=dendrite +POSTGRES_PASSWORD=$DB_PASS +POSTGRES_DB=dendrite + +MONOLITH_HOSTNAME=monolith +MONOLITH_IMAGE=matrixdotorg/dendrite-monolith:latest +MONOLITH_PORT_HTTP=$PORT_HTTP +MONOLITH_PORT_HTTPS=$PORT_HTTPS +EOF + +cat < compose.yml +services: + postgres: + hostname: \${POSTGRES_HOSTNAME:-postgres} + container_name: ${MATRIX_DOMAIN}-db + image: postgres:\${POSTGRES_VERSION:-15-alpine} + restart: always + volumes: + - ./dendrite_postgres_data:/var/lib/postgresql/data + environment: + POSTGRES_PASSWORD: \${POSTGRES_PASSWORD:-$DB_PASS} + POSTGRES_USER: \${POSTGRES_USER:-dendrite} + POSTGRES_DB: \${POSTGRES_DB:-dendrite} + healthcheck: + test: ["CMD-SHELL", "pg_isready -U \${POSTGRES_USER:-dendrite}"] + interval: 5s + timeout: 5s + retries: 5 + networks: + - internal + + monolith: + hostname: \${MONOLITH_HOSTNAME:-monolith} + container_name: ${MATRIX_DOMAIN} + image: \${MONOLITH_IMAGE:-matrixdotorg/dendrite-monolith:latest} + ports: + - \${MONOLITH_PORT_HTTP:-8008}:8008 + - \${MONOLITH_PORT_HTTPS:-8448}:8448 + volumes: + - ./config:/etc/dendrite + - ./dendrite_media:/var/dendrite/media + - ./dendrite_jetstream:/var/dendrite/jetstream + - ./dendrite_search_index:/var/dendrite/searchindex + - ./:/mnt + depends_on: + postgres: + condition: service_healthy + networks: + - internal + restart: unless-stopped + +networks: + internal: + attachable: true +volumes: + dendrite_postgres_data: + dendrite_media: + dendrite_jetstream: + dendrite_search_index: +EOF + +cat < config/dendrite.yaml +version: 2 +global: + server_name: $MATRIX_DOMAIN + private_key: /mnt/matrix_key.pem + tls_cert: /mnt/server.crt + tls_key: /mnt/server.key + old_private_keys: [] + key_validity_period: 168h0m0s + database: + connection_string: postgresql://dendrite:$DB_PASS@postgres/dendrite?sslmode=disable + max_open_conns: 90 + max_idle_conns: 5 + conn_max_lifetime: -1 + well_known_server_name: "$MATRIX_DOMAIN:443" + well_known_client_name: "https://$MATRIX_DOMAIN" + cache: + max_size_estimated: 1gb + max_age: 1h + trusted_third_party_id_servers: + - matrix.org + - vector.im + disable_federation: false + report_stats: + enabled: false +client_api: + registration_disabled: true + registration_shared_secret: "$REG_SECRET" + turn: + turn_user_lifetime: "5m" + turn_uris: + - turn:$TURN_DOMAIN?transport=udp + - turn:$TURN_DOMAIN?transport=tcp + turn_shared_secret: "$TURN_SECRET" +federation_api: + send_max_retries: 16 + disable_tls_validation: false +media_api: + base_path: ./media_store + max_file_size_bytes: 10485760 +sync_api: + search: + enabled: false + index_path: "./searchindex" +user_api: + auto_join_rooms: + - "#main:$MATRIX_DOMAIN" +logging: + - type: std + level: info + - type: file + level: info + params: + path: ./logs +jetstream: + addresses: [] + disable_tls_validation: false + storage_path: ./ + topic_prefix: Dendrite +metrics: + enabled: false + basic_auth: + username: metrics + password: metrics +dns_cache: + enabled: false + cache_size: 256 + cache_lifetime: "5m" +EOF + + echo "[INFO] Generating Dendrite keys..." + + docker run --rm --entrypoint="" -v $(pwd):/mnt matrixdotorg/dendrite-monolith:latest /usr/bin/generate-keys -private-key /mnt/matrix_key.pem -tls-cert /mnt/server.crt -tls-key /mnt/server.key + echo "[OK] Keys generated in $PWD" + + $DOCKER_COMPOSE up -d + configure_nginx "$MATRIX_DOMAIN" "$PORT_HTTP" + echo "[OK] Dendrite server ($MATRIX_DOMAIN) is running." +} + +install_synapse() { + echo "=== Installing Matrix Synapse ===" + common_prompts + + INSTALL_DIR="$BASE_DIR/$MATRIX_DOMAIN" + mkdir -p "$INSTALL_DIR" + cd "$INSTALL_DIR" || exit 1 + mkdir -p data db + chown -R 991:991 data/ + chown -R 999:999 db/ + DB_USER="synapse" + DB_NAME="synapse" + DB_PASS=$(openssl rand -hex 16) + REG_SECRET=$(openssl rand -hex 32) + + : "${PORT_HTTP:=8008}" + : "${PORT_HTTPS:=8448}" + + cat < .env +# Matrix Synapse environment +MATRIX_DOMAIN=$MATRIX_DOMAIN +PORT_HTTP=$PORT_HTTP +PORT_HTTPS=$PORT_HTTPS + +DB_USER=$DB_USER +DB_NAME=$DB_NAME +DB_PASS=$DB_PASS + +REG_SECRET=$REG_SECRET +TURN_DOMAIN=$TURN_DOMAIN +TURN_SECRET=$TURN_SECRET +EOF + + +cat < compose.yml +services: + db: + image: postgres:15-alpine + restart: always + environment: + POSTGRES_USER: ${DB_USER} + POSTGRES_PASSWORD: ${DB_PASS} + POSTGRES_DB: ${DB_NAME} + LANG: C + LC_ALL: C + command: postgres -c lc_collate=C -c lc_ctype=C + volumes: + - ./db:/var/lib/postgresql/data + networks: + - synapse-net + + synapse: + image: matrixdotorg/synapse:latest + restart: always + depends_on: + - db + environment: + SYNAPSE_SERVER_NAME: ${MATRIX_DOMAIN} + SYNAPSE_REPORT_STATS: "yes" + ports: + - "${PORT_HTTP}:8008" + - "${PORT_HTTPS}:8448" + volumes: + - ./data:/data + networks: + - synapse-net + +networks: + synapse-net: + driver: bridge +EOF + +$DOCKER_COMPOSE --env-file .env up -d +docker run -it --rm -v ./data:/data -e SYNAPSE_SERVER_NAME=$MATRIX_DOMAIN -e SYNAPSE_REPORT_STATS=no matrixdotorg/synapse:latest generate + +echo "[INFO] Generating homeserver.yaml for Postgres + TURN..." +cat < data/homeserver.yaml +server_name: $MATRIX_DOMAIN +pid_file: /data/homeserver.pid + +listeners: + - port: $PORT_HTTP + tls: false + type: http + x_forwarded: true + resources: + - names: [client, federation] + compress: false + +database: + name: psycopg2 + args: + user: $DB_USER + password: $DB_PASS + host: db + database: $DB_NAME + cp_min: 5 + cp_max: 10 + +enable_registration: false +registration_shared_secret: "$REG_SECRET" + +turn_uris: + - turn:$TURN_DOMAIN?transport=udp + - turn:$TURN_DOMAIN?transport=tcp +turn_shared_secret: "$TURN_SECRET" +turn_user_lifetime: "5m" + +log_config: "/data/$MATRIX_DOMAIN.log.config" +media_store_path: /data/media_store +report_stats: false + +macaroon_secret_key: $REG_SECRET +form_secret: $REG_SECRET +signing_key_path: "/data/$MATRIX_DOMAIN.signing.key" + +trusted_key_servers: + - server_name: "matrix.org" +suppress_key_server_warning: true +EOF + + echo "[INFO] Restarting Synapse with full config..." + $DOCKER_COMPOSE --env-file .env restart synapse + $DOCKER_COMPOSE --env-file .env restart synapse + + configure_nginx "$MATRIX_DOMAIN" "$PORT_HTTP" + echo "[OK] Synapse server ($MATRIX_DOMAIN) is running with Postgres." +} + + +remove_server() { + [ "$#" -eq 0 ] && echo "Usage: remove_server [domain2 ...]" && return 1 + + for DOMAIN in "$@"; do + SERVER_DIR="$BASE_DIR/$DOMAIN" + + case "$DOMAIN" in + ""|"/"|".") + echo "[ERROR] Refusing to delete dangerous path ($DOMAIN)" + continue + ;; + esac + + [ -d "$SERVER_DIR" ] && \ + echo "[INFO] Stopping and removing server: $DOMAIN" && \ + (cd "$SERVER_DIR" && $DOCKER_COMPOSE down -v) || \ + echo "[WARN] Failed to stop container for $DOMAIN" + + rm -rf "$SERVER_DIR" + rm -f "/etc/nginx/sites-available/$DOMAIN" "/etc/nginx/sites-enabled/$DOMAIN" + done + + nginx -t && (systemctl reload nginx 2>/dev/null || nginx -s reload) + echo "[OK] Done removing servers: $*" +} + +CMD="${1:-}" + +case "$CMD" in + -t) install_turn ;; + -d) install_dendrite ;; + -s) install_synapse ;; + -l) list_servers ;; + -r) + [ -z "$2" ] && { echo "Usage: $0 -r [domain2 ...]"; exit 1; } + shift + remove_server "$@" + ;; + turn) install_turn ;; + dendrite) install_dendrite ;; + synapse) install_synapse ;; + list) list_servers ;; + remove) + [ -z "$2" ] && { echo "Usage: $0 remove [domain2 ...]"; exit 1; } + shift + remove_server "$@" + ;; + *) usage ;; +esac + diff --git a/whiterabbit.1 b/whiterabbit.1 deleted file mode 100644 index e02030f..0000000 --- a/whiterabbit.1 +++ /dev/null @@ -1,51 +0,0 @@ -.\" Manpage for whiterabbit -.TH WHITERABBIT 1 "2025-09-25" "1.0.0" "whiterabbit manual" -.SH NAME -whiterabbit \- auto-configure Matrix homeservers (Dendrite or Synapse) -.SH SYNOPSIS -.B whiterabbit -[\fIturn\fR|\fIdendrite\fR|\fIsynapse\fR|\fIlist\fR|\fIremove \fR] -.SH DESCRIPTION -whiterabbit sets up Matrix homeservers with a global Coturn server and Nginx/Let's Encrypt support. - -Main commands: -.TP -.B turn -Install or configure the global Coturn server. -.TP -.B dendrite -Add a new Matrix Dendrite server. -.TP -.B synapse -Add a new Matrix Synapse server. -.TP -.B list -List all configured Matrix servers. -.TP -.B remove -Remove a Matrix server by domain. - -.SH EXAMPLES -.TP -whiterabbit turn -Set up the global Coturn server. -.TP -whiterabbit dendrite -Add a Dendrite server with TLS and Nginx. -.TP -whiterabbit synapse -Add a Synapse server with TLS and Nginx. -.TP -whiterabbit list -Show all servers. -.TP -whiterabbit remove matrix.example.com -Remove a server. - -.SH NOTES -All Matrix servers share the same Coturn instance. -TLS certificates are issued automatically via Let's Encrypt. -Requires docker, docker-compose, nginx, certbot, and coturn. - -.SH AUTHOR -Filip Wandzio diff --git a/whiterabbit.sh b/whiterabbit.sh deleted file mode 100755 index f8eb350..0000000 --- a/whiterabbit.sh +++ /dev/null @@ -1,417 +0,0 @@ -#!/bin/sh -set -eu - -BASE_DIR="/opt/matrix" - -# Detect docker compose binary -DOCKER_COMPOSE=$(command -v docker-compose || command -v "docker" compose || true) -if [ -z "$DOCKER_COMPOSE" ]; then - echo "[ERROR] docker-compose or docker compose not found" >&2 - exit 1 -fi - -usage() { - cat <<'EOF' -whiterabbit: auto-configure Matrix homeservers (Dendrite or Synapse) -with a global Coturn instance and Nginx + Let's Encrypt proxy. - -Main actions: - turn Install or configure the global Coturn server - dendrite Add a new Matrix server (Dendrite) - synapse Add a new Matrix server (Synapse) - list Show all configured Matrix servers - remove Remove a Matrix server by domain - -Notes: - • Coturn should be installed only once using 'turn'. - • All Matrix servers share the same Coturn (TURN domain/secret). - • TLS certificates are issued automatically using Let's Encrypt. - • Requirements: docker, docker-compose, nginx, certbot, coturn. -EOF - exit 1 -} - -require_nonempty() { - VAR_NAME="$1" - VAR_VALUE="$2" - if [ -z "$VAR_VALUE" ]; then - echo "[ERROR] $VAR_NAME cannot be empty" >&2 - exit 1 - fi -} - -list_servers() { - echo "=== Installed servers ===" - ls -1 "$BASE_DIR" 2>/dev/null || echo "No servers installed" -} - -install_turn() { - echo "=== Installing global Coturn ===" - printf "TURN domain (eg. turn.example.com): " - read -r TURN_DOMAIN - require_nonempty TURN_DOMAIN "$TURN_DOMAIN" - - printf "TURN IP (eg. 127.0.0.1): " - read -r TURN_SERVER_IP - require_nonempty TURN_SERVER_IP "$TURN_SERVER_IP" - - printf "Listening device (eg. eth0): " - read -r TURN_LISTENING_DEVICE - require_nonempty TURN_LISTENING_DEVICE "$TURN_LISTENING_DEVICE" - - printf "TURN shared secret: " - read -r TURN_SECRET - require_nonempty TURN_SECRET "$TURN_SECRET" - - mkdir -p /etc/turn - cat < /etc/turn/turnserver.conf -listening-device=$TURN_LISTENING_DEVICE -listening-port=3478 -tls-listening-port=5349 -listening-ip=$TURN_SERVER_IP -min-port=49152 -max-port=65535 -use-auth-secret -static-auth-secret=$TURN_SECRET -realm=$TURN_DOMAIN -syslog -no-rfc5780 -no-stun-backward-compatibility -response-origin-only-with-rfc5780 -EOF - - echo "$TURN_DOMAIN" > /etc/turn/domain - echo "$TURN_SECRET" > /etc/turn/secret - - if command -v systemctl >/dev/null; then - systemctl enable --now coturn || true - else - service coturn start || true - fi - - echo "[OK] Global Coturn configured ($TURN_DOMAIN)" -} - -common_prompts() { - printf "Matrix domain (eg. matrix.example.com): " - read -r MATRIX_DOMAIN - require_nonempty MATRIX_DOMAIN "$MATRIX_DOMAIN" - - printf "Let's Encrypt certificate email: " - read -r EMAIL - require_nonempty EMAIL "$EMAIL" - - printf "Postgres secret: " - read -r DB_PASS - require_nonempty DB_PASS "$DB_PASS" - - printf "registration_shared_secret: " - read -r REG_SECRET - require_nonempty REG_SECRET "$REG_SECRET" - - printf "MATRIX server IP (eg. 127.0.0.1): " - read -r MATRIX_SERVER_IP - require_nonempty MATRIX_SERVER_IP "$MATRIX_SERVER_IP" - - TURN_DOMAIN=$(cat /etc/turn/domain) - TURN_SECRET=$(cat /etc/turn/secret) - - # Generate unique port numbers from hash of domain - HASH=$(printf "%s" "$MATRIX_DOMAIN" | cksum | cut -d ' ' -f1) - PORT_BASE=$(( (HASH % 1000) + 8000 )) - PORT_HTTP=$PORT_BASE - PORT_HTTPS=$((PORT_BASE+1)) -} - -configure_nginx() { - DOMAIN="$1" - SERVICE_PORT="$2" - - mkdir -p /etc/nginx/sites-available - mkdir -p /etc/nginx/sites-enabled - - cat < "/etc/nginx/sites-available/$DOMAIN" -server { - listen 80; - server_name $DOMAIN; - - location /.well-known/matrix/server { - default_type application/json; - return 200 '{ "m.server": "$DOMAIN:443" }'; - } - - location /.well-known/matrix/client { - default_type application/json; - return 200 '{ - "m.homeserver": { "base_url": "https://$DOMAIN" }, - "m.identity_server": { "base_url": "https://vector.im" } - }'; - } - - location / { - proxy_pass http://127.0.0.1:$SERVICE_PORT; - proxy_set_header Host \$host; - proxy_set_header X-Forwarded-For \$remote_addr; - } -} -EOF - - ln -sf "/etc/nginx/sites-available/$DOMAIN" "/etc/nginx/sites-enabled/$DOMAIN" - nginx -t || { echo "[ERROR] Invalid nginx config"; exit 1; } - if command -v systemctl >/dev/null; then - systemctl reload nginx - else - nginx -s reload - fi - - if command -v certbot >/dev/null; then - certbot --nginx --non-interactive --agree-tos -m "$EMAIL" -d "$DOMAIN" || { - echo "[WARN] Certbot failed for $DOMAIN" - } - else - echo "[WARN] Certbot not installed, skipping TLS setup" - fi - - echo "[OK] Nginx and SSL certificate configured for $DOMAIN" -} - - -install_dendrite() { - echo "=== Installing Matrix Dendrite ===" - common_prompts - - INSTALL_DIR="$BASE_DIR/$MATRIX_DOMAIN" - mkdir -p "$INSTALL_DIR/config" - cd "$INSTALL_DIR" || exit 1 - - cat < .env -POSTGRES_HOSTNAME=postgres -POSTGRES_VERSION=15-alpine -POSTGRES_USER=dendrite -POSTGRES_PASSWORD=$DB_PASS -POSTGRES_DB=dendrite - -MONOLITH_HOSTNAME=monolith -MONOLITH_IMAGE=matrixdotorg/dendrite-monolith:latest -MONOLITH_PORT_HTTP=$PORT_HTTP -MONOLITH_PORT_HTTPS=$PORT_HTTPS -EOF - -cat < compose.yml -services: - postgres: - hostname: \${POSTGRES_HOSTNAME:-postgres} - image: postgres:\${POSTGRES_VERSION:-15-alpine} - restart: always - volumes: - - ./dendrite_postgres_data:/var/lib/postgresql/data - environment: - POSTGRES_PASSWORD: \${POSTGRES_PASSWORD:-$DB_PASS} - POSTGRES_USER: \${POSTGRES_USER:-dendrite} - POSTGRES_DB: \${POSTGRES_DB:-dendrite} - healthcheck: - test: ["CMD-SHELL", "pg_isready -U \${POSTGRES_USER:-dendrite}"] - interval: 5s - timeout: 5s - retries: 5 - networks: - - internal - - monolith: - hostname: \${MONOLITH_HOSTNAME:-monolith} - image: \${MONOLITH_IMAGE:-matrixdotorg/dendrite-monolith:latest} - ports: - - \${MONOLITH_PORT_HTTP:-8008}:8008 - - \${MONOLITH_PORT_HTTPS:-8448}:8448 - volumes: - - ./config:/etc/dendrite - - ./dendrite_media:/var/dendrite/media - - ./dendrite_jetstream:/var/dendrite/jetstream - - ./dendrite_search_index:/var/dendrite/searchindex - - ./:/mnt - depends_on: - postgres: - condition: service_healthy - networks: - - internal - restart: unless-stopped - -networks: - internal: - attachable: true -volumes: - dendrite_postgres_data: - dendrite_media: - dendrite_jetstream: - dendrite_search_index: -EOF - - # --- Plik konfiguracji Dendrite --- - -cat < config/dendrite.yaml -version: 2 -global: - server_name: $MATRIX_DOMAIN - private_key: /mnt/matrix_key.pem - tls_cert: /mnt/server.crt - tls_key: /mnt/server.key - old_private_keys: [] - key_validity_period: 168h0m0s - database: - connection_string: postgresql://dendrite:$DB_PASS@postgres/dendrite?sslmode=disable - max_open_conns: 90 - max_idle_conns: 5 - conn_max_lifetime: -1 - well_known_server_name: "$MATRIX_DOMAIN:443" - well_known_client_name: "https://$MATRIX_DOMAIN" - cache: - max_size_estimated: 1gb - max_age: 1h - trusted_third_party_id_servers: - - matrix.org - - vector.im - disable_federation: false - report_stats: - enabled: false -client_api: - registration_disabled: true - registration_shared_secret: "$REG_SECRET" - turn: - turn_user_lifetime: "5m" - turn_uris: - - turn:$TURN_DOMAIN?transport=udp - - turn:$TURN_DOMAIN?transport=tcp - turn_shared_secret: "$TURN_SECRET" -federation_api: - send_max_retries: 16 - disable_tls_validation: false -media_api: - base_path: ./media_store - max_file_size_bytes: 10485760 -sync_api: - search: - enabled: false - index_path: "./searchindex" -user_api: - auto_join_rooms: - - "#main:$MATRIX_DOMAIN" -logging: - - type: std - level: info - - type: file - level: info - params: - path: ./logs -jetstream: - addresses: [] - disable_tls_validation: false - storage_path: ./ - topic_prefix: Dendrite -metrics: - enabled: false - basic_auth: - username: metrics - password: metrics -dns_cache: - enabled: false - cache_size: 256 - cache_lifetime: "5m" -EOF - - # Generate necessary project directory - $DOCKER_COMPOSE up -d - - $DOCKER_COMPOSE down - - # --- Generowanie kluczy Dendrite + TLS jeśli nie istnieją --- - echo "[INFO] Generating Dendrite keys..." - -docker run --rm --entrypoint="" -v $(pwd):/mnt matrixdotorg/dendrite-monolith:latest /usr/bin/generate-keys -private-key /mnt/matrix_key.pem -tls-cert /mnt/server.crt -tls-key /mnt/server.key - echo "[OK] Keys generated in $PWD" - - # --- Start kontenerów --- - $DOCKER_COMPOSE up -d - - # --- Konfiguracja Nginx + SSL/TLS --- - configure_nginx "$MATRIX_DOMAIN" "$PORT_HTTP" - - echo "[OK] Dendrite server ($MATRIX_DOMAIN) is running." -} - -install_synapse() { - echo "=== Installing Matrix Synapse ===" - common_prompts - - INSTALL_DIR="$BASE_DIR/$MATRIX_DOMAIN" - mkdir -p "$INSTALL_DIR" - cd "$INSTALL_DIR" || exit 1 - - cat < docker-compose.yml -version: '3.4' -services: - db: - image: postgres:15-alpine - environment: - POSTGRES_USER: synapse - POSTGRES_PASSWORD: $DB_PASS - POSTGRES_DB: synapse - volumes: - - ./db:/var/lib/postgresql/data - - synapse: - image: matrixdotorg/synapse:latest - depends_on: [ db ] - environment: - SYNAPSE_SERVER_NAME: $MATRIX_DOMAIN - SYNAPSE_REPORT_STATS: "yes" - POSTGRES_PASSWORD: $DB_PASS - ports: - - $PORT_HTTP:8008 - - $PORT_HTTPS:8448 - volumes: - - ./data:/data -EOF - - $DOCKER_COMPOSE up -d - - cat < data/homeserver-extra.yaml -turn_uris: [ "turn:$TURN_DOMAIN?transport=udp", "turn:$TURN_DOMAIN?transport=tcp" ] -turn_shared_secret: "$TURN_SECRET" -turn_user_lifetime: "5m" -EOF - - configure_nginx "$MATRIX_DOMAIN" "$PORT_HTTP" - - echo "[OK] Synapse server ($MATRIX_DOMAIN) is running." -} - -remove_server() { - DOMAIN="$1" - [ -z "$DOMAIN" ] && usage - - SERVER_DIR="$BASE_DIR/$DOMAIN" - case "$DOMAIN" in - ""|"/"|".") echo "[ERROR] Refusing to delete dangerous path ($DOMAIN)"; exit 1 ;; - esac - - if [ -d "$SERVER_DIR" ]; then - (cd "$SERVER_DIR" && $DOCKER_COMPOSE down -v) || true - rm -rf "$SERVER_DIR" - fi - - rm -f "/etc/nginx/sites-available/$DOMAIN" "/etc/nginx/sites-enabled/$DOMAIN" - nginx -t && (systemctl reload nginx 2>/dev/null || nginx -s reload) - echo "[OK] Server $DOMAIN removed." -} - -# --- CLI router --- -CMD="${1:-}" - -case "$CMD" in - turn) install_turn ;; - dendrite) install_dendrite ;; - synapse) install_synapse ;; - list) list_servers ;; - remove) remove_server "${2:-}" ;; - *) usage ;; -esac -- cgit v1.2.3