From c35fd32d1a3c9bdf91e2091b05741978606a3900 Mon Sep 17 00:00:00 2001 From: Filip Wandzio Date: Thu, 25 Sep 2025 23:21:00 +0200 Subject: Add makefile and enable support for building on arch based distributions Organize script into modular functions Add manpages Signed-off-by: Filip Wandzio --- whiterabbit.sh | 367 ++++++++++++++++++++++++++++++++------------------------- 1 file changed, 205 insertions(+), 162 deletions(-) (limited to 'whiterabbit.sh') diff --git a/whiterabbit.sh b/whiterabbit.sh index e68351f..e6e3b58 100755 --- a/whiterabbit.sh +++ b/whiterabbit.sh @@ -1,104 +1,185 @@ -#!/usr/bin/sh -set -euo pipefail - -echo "=== Matrix Dendrite + Coturn auto-setup (Docker + standalone Coturn) ===" - -# ---- User Input ---- -read -rp "Matrix domain (eg. matrix.example.com): " MATRIX_DOMAIN -read -rp "TURN domain(eg. turn.example.com): " TURN_DOMAIN -read -rp "Let's Encrypt certificate email: " EMAIL -read -rp "Postgres secret: " DB_PASS -read -rp "registration_shared_secret: " REG_SECRET -read -rp "TURN shared secret: " TURN_SECRET -read -rp "TURN IP (eg. 127.0.0.1): " TURN_SERVER_IP -read -rp "MATRIX server IP (eg. 127.0.0.1): " MATRIX_SERVER_IP -read -rp "Listening device (eg. eth0): " TURN_LISTENING_DEVICE - -INSTALL_DIR="/opt/matrix/$MATRIX_DOMAIN" -mkdir -p "$INSTALL_DIR/config" -cd "$INSTALL_DIR" - -cat < .env -# PostgreSQL +#!/bin/sh +set -eu + +BASE_DIR="/opt/matrix" + +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 +} + +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 + printf "TURN IP (eg. 127.0.0.1): " + read -r TURN_SERVER_IP + printf "Listening device (eg. eth0): " + read -r TURN_LISTENING_DEVICE + printf "TURN shared secret: " + read -r 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 + + systemctl enable --now coturn || true + echo "[OK] Global Coturn configured ($TURN_DOMAIN)" +} + +common_prompts() { + printf "Matrix domain (eg. matrix.example.com): " + read -r MATRIX_DOMAIN + printf "Let's Encrypt certificate email: " + read -r EMAIL + printf "Postgres secret: " + read -r DB_PASS + printf "registration_shared_secret: " + read -r REG_SECRET + printf "MATRIX server IP (eg. 127.0.0.1): " + read -r MATRIX_SERVER_IP + + TURN_DOMAIN=$(cat /etc/turn/domain) + TURN_SECRET=$(cat /etc/turn/secret) +} + +configure_nginx() { + DOMAIN="$1" + SERVICE_PORT="$2" + + 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 && systemctl reload nginx + + certbot --nginx --non-interactive --agree-tos -m "$EMAIL" -d "$DOMAIN" + + 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 MONOLITH_HOSTNAME=monolith MONOLITH_IMAGE=matrixdotorg/dendrite-monolith:latest MONOLITH_PORT_HTTP=8008 MONOLITH_PORT_HTTPS=8448 EOF -cat <<'EOF' > compose.yml + cat <<'EOF' > 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:-itsasecret} - 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 + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + POSTGRES_USER: ${POSTGRES_USER} + POSTGRES_DB: ${POSTGRES_DB} + networks: [ internal ] monolith: - hostname: ${MONOLITH_HOSTNAME:-monolith} - image: ${MONOLITH_IMAGE:-matrixdotorg/dendrite-monolith:latest} + image: ${MONOLITH_IMAGE} ports: - - ${MONOLITH_PORT_HTTP:-8008}:8008 - - ${MONOLITH_PORT_HTTPS:-8448}:8448 + - ${MONOLITH_PORT_HTTP}:8008 + - ${MONOLITH_PORT_HTTPS}: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 + depends_on: [ postgres ] + 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 + cat < config/dendrite.yaml version: 2 global: server_name: $MATRIX_DOMAIN private_key: /mnt/matrix_key.pem - 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" client_api: registration_disabled: true - guests_disabled: true registration_shared_secret: "$REG_SECRET" turn: @@ -107,118 +188,80 @@ client_api: - 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 - dynamic_thumbnails: false - thumbnail_sizes: - - width: 96 - height: 96 - method: crop - - width: 640 - height: 480 - method: scale - -user_api: - bcrypt_cost: 10 - auto_join_rooms: - - "#main:$MATRIX_DOMAIN" - -logging: - - type: std - level: info EOF -cat < /etc/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 -syslog -no-rfc5780 -no-stun-backward-compatibility -response-origin-only-with-rfc5780 -EOF + docker compose up -d -echo "[INFO] Generating server 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 + configure_nginx "$MATRIX_DOMAIN" "8008" -echo "[INFO] Booting up containers(HTTP-only test)..." -docker compose up -d + echo "[OK] Dendrite server ($MATRIX_DOMAIN) is running." +} -echo "[INFO] Waiting for dendrite monolith to answer..." -for i in {1..30}; do - if curl -fs "http://$MATRIX_SERVER_IP:8008/_matrix/client/versions" >/dev/null 2>&1; then - echo "[OK] Monolith działa na http://$MATRIX_SERVER_IP:8008" - break - fi - echo " ...retry $i" - sleep 5 -done +install_synapse() { + echo "=== Installing Matrix Synapse ===" + common_prompts -echo "[INFO] Setting up NGINX RevPrx files" -cat < /etc/nginx/sites-available/$MATRIX_DOMAIN -server { - listen 80; - listen [::]:80; - server_name $MATRIX_DOMAIN; - location /.well-known/matrix/client { - return 301 https://$host$request_uri; - } - location /.well-known/matrix/server { - return 301 https://$host$request_uri; - } - location / { - return 301 https://$host$request_uri; - } -} + INSTALL_DIR="$BASE_DIR/$MATRIX_DOMAIN" + mkdir -p "$INSTALL_DIR" + cd "$INSTALL_DIR" || exit 1 -server { - listen 443 ssl http2; - listen [::]:443 ssl http2; - server_name $MATRIX_DOMAIN; + 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 - ssl_certificate /etc/letsencrypt/live/$MATRIX_DOMAIN/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/$MATRIX_DOMAIN/privkey.pem; - include /etc/letsencrypt/options-ssl-nginx.conf; - ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; + synapse: + image: matrixdotorg/synapse:latest + depends_on: [ db ] + environment: + SYNAPSE_SERVER_NAME: $MATRIX_DOMAIN + SYNAPSE_REPORT_STATS: "yes" + POSTGRES_PASSWORD: $DB_PASS + ports: + - 8008:8008 + - 8448:8448 + volumes: + - ./data:/data +EOF - location / { - proxy_pass http://127.0.0.1:8008; - proxy_http_version 1.1; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - } + docker compose up -d - location /.well-known/matrix/client { - default_type application/json; - add_header Access-Control-Allow-Origin *; - return 200 '{"m.homeserver": {"base_url": "https://$MATRIX_DOMAIN"}}'; - } + 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 - location /.well-known/matrix/server { - default_type application/json; - add_header Access-Control-Allow-Origin *; - return 200 '{"m.server": "$MATRIX_DOMAIN:443"}'; - } + configure_nginx "$MATRIX_DOMAIN" "8008" + + echo "[OK] Synapse server ($MATRIX_DOMAIN) is running." } -EOF -ln -s /etc/nginx/sites-available/$MATRIX_DOMAIN -echo "============================================" -echo " Matrix server setup finished!" -echo " HomeServer: https://$MATRIX_DOMAIN:8448" -echo " TURN: $TURN_DOMAIN (3478/5349)" +remove_server() { + DOMAIN="$1" + [ -z "$DOMAIN" ] && usage + SERVER_DIR="$BASE_DIR/$DOMAIN" + rm -rf "$SERVER_DIR" + rm -f "/etc/nginx/sites-available/$DOMAIN" "/etc/nginx/sites-enabled/$DOMAIN" + nginx -t && systemctl reload nginx + 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