Initial Commit

This commit is contained in:
cortex
2026-05-20 10:28:49 +01:00
parent a5b3ddd701
commit 784cca8b27
14 changed files with 1035 additions and 3 deletions
+19
View File
@@ -0,0 +1,19 @@
version: 1
formatters:
precise:
format: '%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(message)s'
handlers:
file:
class: logging.handlers.RotatingFileHandler
filename: /var/log/synapse/{{WORKER_NAME}}.log
maxBytes: {{MAX_BYTES}}
backupCount: {{BACKUP_COUNT}}
formatter: precise
root:
level: {{LOG_LEVEL}}
handlers: [file]
loggers:
synapse:
level: {{SYNAPSE_LOG_LEVEL}}
synapse.storage:
level: WARNING
+45
View File
@@ -0,0 +1,45 @@
# Auto-generated config for {{WORKER_NAME}}
# Generated by generate-workers.sh
worker_app: synapse.app.generic_worker
instance_map:
master:
host: synapse
port: 9090
{{WORKER_NAME}}:
host: {{WORKER_NAME}}
port: {{PORT}}
worker_name: {{WORKER_NAME}}
worker_listeners:
- port: {{PORT}}
bind_addresses: ['::']
type: http
resources:
- names: [replication]
worker_replication_host: synapse
worker_replication_http_port: {{PORT}}
server_name: {{SERVER_NAME}}
database:
name: psycopg2
args:
user: {{DB_USER}}
password: {{DB_PASSWORD}}
database: {{DB_NAME}}
host: db
cp_min: 5
cp_max: 10
redis:
enabled: true
host: redis
port: 6379
log_config: "/data/workers/{{WORKER_NAME}}.log.config"
worker_daemonize: true
worker_pid_file: "/var/run/synapse/{{WORKER_NAME}}.pid"
metrics_enabled: true
+67
View File
@@ -0,0 +1,67 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${SCRIPT_DIR}/functions.sh"
resolve_paths
TEMPLATE_FILE="${INIT_DIR}/templates/compose.yaml.template"
OUTPUT_FILE="${ROOT_DIR}/compose.yaml"
require_file "$TEMPLATE_FILE" "Compose template"
require_env
log_info "Configuring optional services..."
read -r -p "Enable LiveKit RTC Stack? (Y/n) [Y]: " LIVEKIT_INPUT
LIVEKIT_INPUT="${LIVEKIT_INPUT:-Y}"
if [[ "$LIVEKIT_INPUT" =~ ^[Yy]$ ]]; then
INCLUDE_LIVEKIT=true
LIVEKIT_KEY=$(openssl rand -hex 16)
LIVEKIT_SECRET=$(openssl rand -hex 32)
cat >> "$ENV_FILE" <<EOF
LIVEKIT_FQDN="rtc.${DOMAIN}"
JWT_FQDN="jwt.${DOMAIN}"
LIVEKIT_API_KEY="${LIVEKIT_KEY}"
LIVEKIT_API_SECRET="${LIVEKIT_SECRET}"
LIVEKIT_UDP_RANGE="10000-20000"
EOF
else
INCLUDE_LIVEKIT=false
fi
echo "Select Web Client: 1) Element 2) Cinny 3) FluffyChat 4) None"
read -r -p "Default [1]: " WEB_APP_INPUT
WEB_APP_INPUT="${WEB_APP_INPUT:-1}"
case "$WEB_APP_INPUT" in
1) INCLUDE_ELEMENT=true; INCLUDE_CINNY=false; INCLUDE_FLUFFY=false ;;
2) INCLUDE_ELEMENT=false; INCLUDE_CINNY=true; INCLUDE_FLUFFY=false ;;
3) INCLUDE_ELEMENT=false; INCLUDE_CINNY=false; INCLUDE_FLUFFY=true ;;
*) INCLUDE_ELEMENT=false; INCLUDE_CINNY=false; INCLUDE_FLUFFY=false ;;
esac
echo "Select Reverse Proxy: 1) Traefik 2) nginx"
read -r -p "Default [1]: " PROXY_INPUT
PROXY_INPUT="${PROXY_INPUT:-1}"
case "$PROXY_INPUT" in
1) INCLUDE_NGINX=false; INCLUDE_TRAEFIK=true ;;
*) INCLUDE_NGINX=true; INCLUDE_TRAEFIK=false ;;
esac
cp "$TEMPLATE_FILE" "$OUTPUT_FILE"
toggle_block() {
[[ "$3" == "true" ]] && sed -i "/$1/d; /$2/d" "$OUTPUT_FILE" || sed -i "/$1/,/$2/d" "$OUTPUT_FILE"
}
toggle_block "# \[LIVEKIT_START\]" "# \[LIVEKIT_END\]" "$INCLUDE_LIVEKIT"
toggle_block "# \[ELEMENT_START\]" "# \[ELEMENT_END\]" "$INCLUDE_ELEMENT"
toggle_block "# \[CINNY_START\]" "# \[CINNY_END\]" "$INCLUDE_CINNY"
toggle_block "# \[FLUFFYCHAT_START\]" "# \[FLUFFYCHAT_END\]" "$INCLUDE_FLUFFY"
toggle_block "# \[NGINX_START\]" "# \[NGINX_END\]" "$INCLUDE_NGINX"
toggle_block "# \[TRAEFIK_START\]" "# \[TRAEFIK_END\]" "$INCLUDE_TRAEFIK"
[[ "$INCLUDE_TRAEFIK" == "true" ]] && sed -i "/# \[TRAEFIK_LABELS_START\]/d; /# \[TRAEFIK_LABELS_END\]/d" "$OUTPUT_FILE" || \
sed -i "/# \[TRAEFIK_LABELS_START\]/,/# \[TRAEFIK_LABELS_END\]/d" "$OUTPUT_FILE"
log_info "Compose file generated: $OUTPUT_FILE"
+63
View File
@@ -0,0 +1,63 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${SCRIPT_DIR}/functions.sh"
resolve_paths
require_env
require_docker
resolve_volume_path
mkdir -p "${VOLUME_PATH}/synapse" "${VOLUME_PATH}/mas" "${VOLUME_PATH}/postgres"
log_info "Initializing PostgreSQL..."
docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" up -d --wait --timeout 60 matrix-db
# Wait for database readiness (silent except on failure)
for ATTEMPT in $(seq 1 30); do
if docker compose -f "$COMPOSE_FILE" exec -T matrix-db psql -U "$PG_USER" -c "SELECT 1;" > /dev/null 2>&1; then
break
fi
[[ $ATTEMPT -eq 30 ]] && { log_error "Database timeout"; exit 1; }
sleep 2
done
# Database initialization SQL
INIT_SQL=$(cat <<EOF
DO \$\$ BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'mas') THEN
CREATE ROLE mas WITH LOGIN PASSWORD '${PG_PASSWORD_MAS}';
END IF;
IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'matrix') THEN
CREATE ROLE matrix WITH LOGIN PASSWORD '${PG_PASSWORD_MATRIX}';
END IF;
END \$\$;
SELECT CASE WHEN NOT EXISTS (SELECT 1 FROM pg_database WHERE datname = 'auth')
THEN format('CREATE DATABASE %I OWNER %I', 'auth', 'mas') ELSE NULL END AS cmd \gexec
SELECT CASE WHEN NOT EXISTS (SELECT 1 FROM pg_database WHERE datname = 'synapse')
THEN format('CREATE DATABASE %I OWNER %I', 'synapse', 'matrix') ELSE NULL END AS cmd \gexec
EOF
)
echo "$INIT_SQL" | docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" exec -T matrix-db psql -U "$PG_USER" -f -
log_info "Generating Synapse configuration..."
docker run -it --rm --network matrix_network \
-v "${VOLUME_PATH}/synapse:/data" \
-e SYNAPSE_SERVER_NAME="$HOMESERVER_FQDN" \
-e SYNAPSE_REPORT_STATS=no \
ghcr.io/element-hq/synapse:latest generate
fix_ownership "${VOLUME_PATH}/synapse"
log_info "Generating MAS configuration..."
docker run -it --rm --network matrix_network \
-v "${VOLUME_PATH}/mas:/data" \
ghcr.io/element-hq/matrix-authentication-service:latest config generate \
| grep -v '^[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}' > "${VOLUME_PATH}/mas/config.yaml"
fix_ownership "${VOLUME_PATH}/mas"
log_info "Configuration complete"
+54
View File
@@ -0,0 +1,54 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${SCRIPT_DIR}/functions.sh"
resolve_paths
require_env
require_command "yq"
require_command "openssl"
SYNAPSE_CFG="${VOLUME_PATH}/synapse/homeserver.yaml"
MAS_CFG="${VOLUME_PATH}/mas/config.yaml"
require_file "$SYNAPSE_CFG" "Synapse config"
require_file "$MAS_CFG" "MAS config"
CLIENT_ID="synapse-client"
CLIENT_SECRET=$(openssl rand -hex 32)
TEMP_FILTER=$(mktemp)
trap "rm -f $TEMP_FILTER" EXIT
cat > "$TEMP_FILTER" <<EOF
.oidc.providers += [{"id": "synapse", "client_id": "${CLIENT_ID}", "client_secret": "${CLIENT_SECRET}", "scopes": ["openid", "profile", "email"], "issuer": "http://mas:8000"}]
EOF
yq -y -i "$(cat "$TEMP_FILTER")" "$MAS_CFG" || { log_error "Failed to update MAS config"; exit 1; }
CLIENT_ID=$(yq '.oidc.providers[0].client_id' "$MAS_CFG" | tr -d '"')
CLIENT_SECRET=$(yq '.oidc.providers[0].client_secret' "$MAS_CFG" | tr -d '"')
ISSUER_URL="https://${MAS_FQDN}"
fix_ownership "$SYNAPSE_CFG"
cat > "$TEMP_FILTER" <<EOF
.oidc_providers += [{"idp_id": "mas", "idp_name": "Matrix Authentication Service", "idp_brand": "mas", "issuer": "${ISSUER_URL}", "client_id": "${CLIENT_ID}", "client_secret": "${CLIENT_SECRET}", "scopes": ["openid", "profile"], "skip_verification": false}]
EOF
if ! yq '.oidc_providers' "$SYNAPSE_CFG" 2>/dev/null | grep -q "idp_id"; then
yq -y -i "$(cat "$TEMP_FILTER")" "$SYNAPSE_CFG" || { log_error "Failed to inject OIDC config"; exit 1; }
fi
if [[ -n "${LIVEKIT_API_KEY:-}" ]]; then
JWT_URL="https://${JWT_FQDN:-jwt.${DOMAIN}}"
if yq '.livekit.url' "$SYNAPSE_CFG" 2>/dev/null | grep -q "."; then
yq -y -i ".livekit.url = \"$JWT_URL\"" "$SYNAPSE_CFG"
else
yq -y -i ".livekit.url = \"$JWT_URL\"" "$SYNAPSE_CFG"
fi
fi
log_info "OIDC and LiveKit linking complete"
+129
View File
@@ -0,0 +1,129 @@
#!/usr/bin/env bash
# AMMIDS Shared Functions Library
# Location: init/scripts/functions.sh
# Sourced by all other scripts in this directory
# Prevent direct execution
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
echo "This is a library, not a script. Source it instead."
exit 1
fi
# --- Color Codes ---
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
TITLE='\033[38;2;17;97;2m'
NC='\033[0m'
# --- Path Resolution ---
# Standardised for project structure: /init/scripts/xxx.sh
# Sets: SCRIPT_DIR, INIT_DIR, ROOT_DIR
resolve_paths() {
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[1]}")" && pwd)"
INIT_DIR="$(dirname "$SCRIPT_DIR")"
ROOT_DIR="$(dirname "$INIT_DIR")"
export SCRIPT_DIR INIT_DIR ROOT_DIR
}
# --- Logging ---
log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
# --- State Management (init.ini) ---
write_state() {
local key="$1"
local value="$2"
local init_file="${INIT_DIR}/init.ini"
local upper_value
upper_value=$(echo "$value" | tr '[:lower:]' '[:upper:]')
echo "${key}=${upper_value}" >> "$init_file"
}
load_state() {
local init_file="${INIT_DIR}/init.ini"
if [[ -f "$init_file" ]]; then
source "$init_file"
else
log_warn "State file not found at ${init_file}. Using defaults."
fi
}
clear_state() {
local init_file="${INIT_DIR}/init.ini"
> "$init_file"
}
# --- Secrets ---
generate_secret() {
local length="${1:-32}"
if command -v openssl &> /dev/null; then
openssl rand -hex "$((length / 2))"
elif command -v pwgen &> /dev/null; then
pwgen -s "$length" 1
else
tr -dc 'A-Za-z0-9' < /dev/urandom | head -c "$length"
fi
}
# --- File Permissions ---
fix_ownership() {
local target="$1"
local uid="${2:-${USER_ID:-1000}}"
local gid="${3:-${GROUP_ID:-1000}}"
if [[ -e "$target" ]] && [[ "$(stat -c '%U' "$target" 2>/dev/null)" != "$USER" ]]; then
log_warn "Fixing ownership on $target..."
sudo chown -R "${uid}:${gid}" "$target"
fi
}
# --- Dependency Checks ---
require_command() {
local cmd="$1"
if ! command -v "$cmd" &> /dev/null; then
log_error "Required command '${cmd}' not found. Install it and retry."
exit 1
fi
}
require_file() {
local file="$1"
local description="${2:-File}"
if [[ ! -f "$file" ]]; then
log_error "${description} not found at ${file}"
exit 1
fi
}
require_env() {
local file="${ROOT_DIR}/.env"
if [[ ! -f "$file" ]]; then
log_error ".env file not found. Run set_env.sh first."
exit 1
fi
source "$file"
}
require_docker() {
require_command "docker"
require_command "docker compose"
}
# --- Volume Path Resolution ---
resolve_volume_path() {
VOLUME_PATH="${VOLUME_PATH:-./matrix}"
if [[ "$VOLUME_PATH" != /* ]]; then
VOLUME_PATH="${ROOT_DIR}/${VOLUME_PATH}"
fi
export VOLUME_PATH
}
# Add to functions.sh
quiet_echo() {
[[ "${QUIET_MODE:-0}" == "1" ]] || echo "$1"
}
+44
View File
@@ -0,0 +1,44 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${SCRIPT_DIR}/functions.sh"
resolve_paths
require_command "openssl" || require_command "pwgen"
main() {
> "$ENV_FILE"
read -r -p "Base Domain (e.g. example.org) [example.org]: " DOMAIN_INPUT
BASE_DOMAIN="${DOMAIN_INPUT:-example.org}"
cat >> "$ENV_FILE" <<EOF
DOMAIN="${BASE_DOMAIN}"
HOMESERVER_FQDN="matrix.${BASE_DOMAIN}"
MAS_FQDN="auth.${BASE_DOMAIN}"
APP_FQDN="app.${BASE_DOMAIN}"
EOF
log_info "Base Domain set to: ${BASE_DOMAIN}"
prompt_var "USER_ID" "Docker UserId" "1000" "no"
prompt_var "GROUP_ID" "Docker GroupID" "1000" "no"
prompt_var "VOLUME_PATH" "Install directory" "./matrix" "no"
prompt_var "COUNTRY" "Country Code (e.g. GB)" "GB" "no"
prompt_var "PG_USER" "PostgreSQL Superuser" "postgres" "no"
prompt_var "PG_PASSWORD" "PostgreSQL Superuser Password" "generated" "yes"
prompt_var "PG_USER_MATRIX" "Synapse Database User" "matrix" "no"
prompt_var "PG_DB_MATRIX" "Synapse Database Name" "synapse" "no"
prompt_var "PG_PASSWORD_MATRIX" "Synapse Database Password" "generated" "yes"
prompt_var "PG_USER_MAS" "MAS Database User" "mas" "no"
prompt_var "PG_DB_MAS" "MAS Database Name" "auth" "no"
prompt_var "PG_PASSWORD_MAS" "MAS Database Password" "generated" "yes"
chmod 600 "$ENV_FILE"
log_info "Environment file created: $ENV_FILE"
log_warn "Add $ENV_FILE to .gitignore and backup securely"
}
main "$@"
+87
View File
@@ -0,0 +1,87 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${SCRIPT_DIR}/functions.sh"
resolve_paths
WORKER_COUNT=1
while getopts "c:" opt; do
case $opt in
c) WORKER_COUNT="$OPTARG" ;;
*) echo "Usage: $0 [-c count]"; exit 1 ;;
esac
done
require_env
resolve_volume_path
TEMPLATE_COMPOSE="${INIT_DIR}/templates/worker.yaml"
TEMPLATE_CONFIG="${INIT_DIR}/config/worker.yaml"
TEMPLATE_LOG="${INIT_DIR}/config/worker-log.yaml"
require_file "$TEMPLATE_COMPOSE" "Compose template"
require_file "$TEMPLATE_CONFIG" "Config template"
require_file "$TEMPLATE_LOG" "Log template"
WORKERS_DIR="${VOLUME_PATH}/synapse/workers"
mkdir -p "$WORKERS_DIR" "${ROOT_DIR}/.tmp"
TRAEFIK_ENABLED="${PROXY:-0}"
TEMP_COMPOSE="${ROOT_DIR}/.tmp/compose_workers.yaml"
> "$TEMP_COMPOSE"
for ((i=1; i<=WORKER_COUNT; i++)); do
worker_name="synapse-worker-${i}"
port=$((9093 + i))
sed -e "s/{{WORKER_NAME}}/${worker_name}/g" \
-e "s/{{PORT}}/${port}/g" \
-e "s/{{SERVER_NAME}}/${HOMESERVER_FQDN}/g" \
-e "s/{{DB_USER}}/${DB_USER:-synapse}/g" \
-e "s/{{DB_PASSWORD}}/${DB_PASSWORD:-synapse_password}/g" \
-e "s/{{DB_NAME}}/${DB_NAME:-synapse}/g" \
"$TEMPLATE_CONFIG" > "${WORKERS_DIR}/${worker_name}.yaml"
sed -e "s/{{WORKER_NAME}}/${worker_name}/g" \
-e "s/{{MAX_BYTES}}/${LOG_MAX_BYTES:-10485760}/g" \
-e "s/{{BACKUP_COUNT}}/${LOG_BACKUP_COUNT:-5}/g" \
-e "s/{{LOG_LEVEL}}/${LOG_LEVEL:-INFO}/g" \
-e "s/{{SYNAPSE_LOG_LEVEL}}/${SYNAPSE_LOG_LEVEL:-INFO}/g" \
"$TEMPLATE_LOG" > "${WORKERS_DIR}/${worker_name}.log.config"
TRAEFIK_LABELS=""
if [[ "$TRAEFIK_ENABLED" == "1" && -n "$DOMAIN" ]]; then
TRAEFIK_LABELS=" labels:
- traefik.enable=true
- traefik.http.services.${worker_name}.loadbalancer.server.port=${port}
- traefik.http.routers.synapse-worker-${worker_name}.rule=Host(\`${DOMAIN}\`) && PathPrefix(\`/_matrix\`)
- traefik.http.routers.synapse-worker-${worker_name}.entrypoints=websecure
- traefik.http.routers.synapse-worker-${worker_name}.service=${worker_name}
- traefik.http.routers.synapse-worker-${worker_name}.priority=10
"
fi
sed -e "s/{{WORKER_NAME}}/${worker_name}/g" \
-e "s/{{PORT}}/${port}/g" \
-e "s/{{APP_TYPE}}/synapse.app.generic_worker/g" \
-e "s/{{TRAEFIK_LABELS}}/${TRAEFIK_LABELS}/g" \
"$TEMPLATE_COMPOSE" >> "$TEMP_COMPOSE"
echo "" >> "$TEMP_COMPOSE"
done
if [[ -f "$COMPOSE_FILE" ]]; then
if ! grep -qE "^ synapse-worker-[0-9]+:" "$COMPOSE_FILE"; then
cat "$TEMP_COMPOSE" >> "$COMPOSE_FILE"
log_info "Appended ${WORKER_COUNT} worker(s) to compose.yaml"
else
log_warn "Some workers already exist. Manual merge required"
cp "$TEMP_COMPOSE" "${ROOT_DIR}/.tmp/compose_workers.yaml"
fi
else
log_warn "compose.yaml not found. Generated: ${TEMP_COMPOSE}"
fi
rm -f "$TEMP_COMPOSE"
log_info "Worker generation complete"
+10
View File
@@ -0,0 +1,10 @@
{
"default_server_config": {
"m.homeserver": {
"base_url": "https://${HOMESERVER_FQDN}",
"server_name": "${HOMESERVER_FQDN}"
}
},
"default_server_name": "${HOMESERVER_FQDN}",
"brand": "Element"
}
+241
View File
@@ -0,0 +1,241 @@
# COMPOSE TEMPLATE - DO NOT EDIT MANUALLY
# Generated by set_compose.sh
networks:
matrix_network:
name: matrix_network
services:
# --- CORE SERVICES (Always Included) ---
matrix-db:
image: postgres:latest
container_name: "matrix-db"
restart: unless-stopped
volumes:
- ${VOLUME_PATH}/postgres:/var/lib/postgresql:rw
networks:
- matrix_network
environment:
POSTGRES_USER: ${PG_USER}
POSTGRES_PASSWORD: ${PG_PASSWORD}
POSTGRES_INITDB_ARGS: --encoding=UTF8 --locale=C
healthcheck:
test: ["CMD-SHELL", "pg_isready -U '${PG_USER}'"]
start_period: "1s"
interval: "1s"
timeout: "5s"
redis:
image: redis:latest
container_name: "matrix-redis"
restart: unless-stopped
networks:
- matrix_network
command: redis-server --appendonly yes
synapse:
image: ghcr.io/element-hq/synapse:latest
container_name: "synapse"
user: ${USER_ID}:${GROUP_ID}
restart: unless-stopped
volumes:
- ${VOLUME_PATH}/synapse:/data:rw
networks:
- matrix_network
environment:
SYNAPSE_CONFIG_DIR: /data
SYNAPSE_CONFIG_PATH: /data/homeserver.yaml
depends_on:
redis:
condition: service_started
matrix-db:
condition: service_healthy
# [TRAEFIK_LABELS_START]
labels:
- "traefik.enable=true"
- "traefik.http.routers.synapse.rule=Host(`${HOMESERVER_FQDN}`)"
- "traefik.http.routers.synapse.entrypoints=websecure"
- "traefik.http.routers.synapse.tls.certresolver=myresolver"
- "traefik.http.services.synapse.loadbalancer.server.port=8008"
# [TRAEFIK_LABELS_END]
mas:
image: ghcr.io/element-hq/matrix-authentication-service:latest
container_name: "mas"
restart: unless-stopped
volumes:
- ${VOLUME_PATH}/mas:/data:rw
networks:
- matrix_network
command: "server --config=/data/config.yaml"
depends_on:
matrix-db:
condition: service_healthy
# [TRAEFIK_LABELS_START]
labels:
- "traefik.enable=true"
- "traefik.http.routers.auth.rule=Host(`${MAS_FQDN}`)"
- "traefik.http.routers.auth.entrypoints=websecure"
- "traefik.http.routers.auth.tls.certresolver=myresolver"
- "traefik.http.services.auth.loadbalancer.server.port=8000"
# [TRAEFIK_LABELS_END]
# --- OPTIONAL: LIVEKIT RTC STACK ---
# [LIVEKIT_START]
livekit:
image: livekit/livekit-server:latest
container_name: "livekit"
restart: unless-stopped
volumes:
- ${VOLUME_PATH}/livekit:/etc/livekit
environment:
- LIVEKIT_KEYS=access-key=${LIVEKIT_API_KEY},secret=${LIVEKIT_API_SECRET}
- LIVEKIT_PORT=7880
- LIVEKIT_WS_PORT=7881
- LIVEKIT_SERVER_URL=https://${LIVEKIT_FQDN}
networks:
- matrix_network
depends_on:
- redis
- matrix-db
ports:
- "${LIVEKIT_UDP_RANGE}:${LIVEKIT_UDP_RANGE}/udp"
# [TRAEFIK_LABELS_START]
labels:
- "traefik.enable=true"
- "traefik.http.routers.rtc.rule=Host(`${LIVEKIT_FQDN}`)"
- "traefik.http.routers.rtc.entrypoints=websecure"
- "traefik.http.routers.rtc.tls.certresolver=myresolver"
- "traefik.http.services.rtc.loadbalancer.server.port=7880"
# [TRAEFIK_LABELS_END]
# The JWT Bridge Service
lk-jwt-service:
image: ghcr.io/element-hq/lk-jwt-service:latest
container_name: "lk-jwt-service"
restart: unless-stopped
environment:
- LK_JWT_PORT=8080
- LIVEKIT_URL=wss://${LIVEKIT_FQDN}
- LIVEKIT_KEY=${LIVEKIT_API_KEY}
- LIVEKIT_SECRET=${LIVEKIT_API_SECRET}
- LIVEKIT_LOCAL_HOMESERVERS=${HOMESERVER_FQDN}
networks:
- matrix_network
depends_on:
- livekit
# [TRAEFIK_LABELS_START]
labels:
- "traefik.enable=true"
- "traefik.http.routers.jwt.rule=Host(`${JWT_FQDN}`)"
- "traefik.http.routers.jwt.entrypoints=websecure"
- "traefik.http.routers.jwt.tls.certresolver=myresolver"
- "traefik.http.services.jwt.loadbalancer.server.port=8080"
# [TRAEFIK_LABELS_END]
# [LIVEKIT_END]
# --- OPTIONAL: WEB HOSTED APP ---
# [ELEMENT_START]
element-web:
image: vectorim/element-web:latest
container_name: "matrix-web-client"
restart: unless-stopped
volumes:
- ${VOLUME_PATH}/element-web:/usr/share/nginx/html:ro
networks:
- matrix_network
environment:
- ELEMENT_WEB_CONFIG_PATH=/usr/share/nginx/html/config.json
# [TRAEFIK_LABELS_START]
labels:
- "traefik.enable=true"
- "traefik.http.routers.app.rule=Host(`${APP_FQDN}`)"
- "traefik.http.routers.app.entrypoints=websecure"
- "traefik.http.routers.app.tls.certresolver=myresolver"
- "traefik.http.services.app.loadbalancer.server.port=80"
# [TRAEFIK_LABELS_END]
# [ELEMENT_END]
# [CINNY_START]
cinny:
image: cinny-web:latest
container_name: "matrix-web-client"
restart: unless-stopped
volumes:
- ${VOLUME_PATH}/cinny:/usr/share/nginx/html:ro
networks:
- matrix_network
# [TRAEFIK_LABELS_START]
labels:
- "traefik.enable=true"
- "traefik.http.routers.app.rule=Host(`${APP_FQDN}`)"
- "traefik.http.routers.app.entrypoints=websecure"
- "traefik.http.routers.app.tls.certresolver=myresolver"
- "traefik.http.services.app.loadbalancer.server.port=80"
# [TRAEFIK_LABELS_END]
# [CINNY_END]
# [FLUFFYCHAT_START]
fluffy-chat:
image: kibaek/fluffy-chat:latest
container_name: "matrix-web-client"
restart: unless-stopped
volumes:
- ${VOLUME_PATH}/fluffy-chat:/usr/share/nginx/html:ro
networks:
- matrix_network
# [TRAEFIK_LABELS_START]
labels:
- "traefik.enable=true"
- "traefik.http.routers.app.rule=Host(`${APP_FQDN}`)"
- "traefik.http.routers.app.entrypoints=websecure"
- "traefik.http.routers.app.tls.certresolver=myresolver"
- "traefik.http.services.app.loadbalancer.server.port=80"
# [TRAEFIK_LABELS_END]
# [FLUFFYCHAT_END]
# --- OPTIONAL: REVERSE PROXY ---
# [NGINX_START]
nginx:
image: nginx:latest
container_name: "matrix-nginx"
restart: unless-stopped
ports:
- "80:80"
- "443:443"
stop_grace_period: 0s
volumes:
- ${VOLUME_PATH}/nginx/conf.d:/etc/nginx/conf.d:ro
command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'"
networks:
matrix_network:
aliases:
- ${DOMAIN}
- ${HOMESERVER_FQDN}
- ${MAS_FQDN}
- ${APP_FQDN}
# [NGINX_END]
# [TRAEFIK_START]
traefik:
image: traefik:latest
container_name: "traefik"
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ${VOLUME_PATH}/traefik:/etc/traefik
command:
- "--api.insecure=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.myresolver.acme.tlschallenge=true"
- "--certificatesresolvers.myresolver.acme.email=${PG_USER}@${DOMAIN}"
- "--certificatesresolvers.myresolver.acme.storage=/etc/traefik/acme.json"
networks:
- matrix_network
# [TRAEFIK_END]
+20
View File
@@ -0,0 +1,20 @@
{{WORKER_NAME}}:
image: ghcr.io/element-hq/synapse:latest
container_name: "{{WORKER_NAME}}"
user: ${USER_ID}:${GROUP_ID}
restart: unless-stopped
entrypoint: ["/start.py", "run", "--config-path=/data/homeserver.yaml", "--config-path=/data/workers/{{WORKER_NAME}}.yaml"]
networks:
- matrix_network
volumes:
- ${VOLUME_PATH}/synapse:/data:rw
- ${VOLUME_PATH}/synapse/logs:/var/log/synapse:rw
environment:
SYNAPSE_WORKER: {{APP_TYPE}}
depends_on:
- synapse
- db
- redis
ports:
- "{{PORT}}:{{PORT}}"
{{TRAEFIK_LABELS}}