feat(ess-pro/compose): deploy Element Server Suite Pro via Compose
initial commit of the converted role from helm charts for qubernetis to compose ansible role
This commit is contained in:
parent
c11f019aae
commit
32eca6b923
33 changed files with 1906 additions and 0 deletions
304
roles/ess_pro_compose/templates/compose.yml.j2
Normal file
304
roles/ess_pro_compose/templates/compose.yml.j2
Normal file
|
|
@ -0,0 +1,304 @@
|
|||
# {{ ansible_managed }}
|
||||
# ESS Pro v{{ ess_chart_version }} on docker compose — rendered by ess_pro_compose.
|
||||
# Topology mirrors the Helm chart: HAProxy fronts all Synapse traffic,
|
||||
# synapse-main is the Python homeserver, synapse-fed-reader is the Rust Pro
|
||||
# worker handling federation reads, MAS handles all auth, LiveKit + lk-jwt
|
||||
# serve Element Call.
|
||||
|
||||
name: {{ ess_compose_project_name }}
|
||||
|
||||
networks:
|
||||
{{ ess_compose_traefik_network }}:
|
||||
external: true
|
||||
{{ ess_compose_internal_network }}:
|
||||
driver: bridge
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
synapse_media:
|
||||
|
||||
services:
|
||||
|
||||
# ===========================================================================
|
||||
# Data plane
|
||||
# ===========================================================================
|
||||
|
||||
postgres:
|
||||
image: {{ ess_images.postgres }}
|
||||
container_name: postgres
|
||||
restart: unless-stopped
|
||||
networks: [ {{ ess_compose_internal_network }} ]
|
||||
environment:
|
||||
LC_COLLATE: "C"
|
||||
LC_CTYPE: "C"
|
||||
PGDATA: /var/lib/postgresql/data/pgdata
|
||||
POSTGRES_INITDB_ARGS: "-E UTF8"
|
||||
POSTGRES_PASSWORD_FILE: /secrets/ess-generated/POSTGRES_ADMIN_PASSWORD
|
||||
command:
|
||||
- postgres
|
||||
- "-c"
|
||||
- "max_connections={{ ess_postgres_max_connections }}"
|
||||
- "-c"
|
||||
- "shared_buffers={{ ess_postgres_shared_buffers }}"
|
||||
- "-c"
|
||||
- "effective_cache_size={{ ess_postgres_effective_cache_size }}"
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
- {{ ess_compose_secrets_dir }}:/secrets/ess-generated:ro
|
||||
- {{ ess_compose_conf_dir }}/postgres/configure-dbs.sh:/docker-entrypoint-initdb.d/init-ess-dbs.sh:ro
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
|
||||
redis:
|
||||
image: {{ ess_images.redis }}
|
||||
container_name: redis
|
||||
restart: unless-stopped
|
||||
networks: [ {{ ess_compose_internal_network }} ]
|
||||
command: ["/usr/local/etc/redis/redis.conf"]
|
||||
volumes:
|
||||
- {{ ess_compose_conf_dir }}/redis/redis.conf:/usr/local/etc/redis/redis.conf:ro
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 10s
|
||||
timeout: 3s
|
||||
retries: 5
|
||||
|
||||
# ===========================================================================
|
||||
# Synapse (Python main + Rust federation-reader worker)
|
||||
# ===========================================================================
|
||||
|
||||
synapse-main:
|
||||
image: {{ ess_images.synapse }}
|
||||
container_name: synapse-main
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
postgres: { condition: service_healthy }
|
||||
redis: { condition: service_healthy }
|
||||
networks: [ {{ ess_compose_internal_network }} ]
|
||||
command: ["python3", "-m", "synapse.app.homeserver", "-c", "/conf/homeserver.yaml"]
|
||||
volumes:
|
||||
- {{ ess_compose_conf_dir }}/synapse/homeserver.yaml:/conf/homeserver.yaml:ro
|
||||
- {{ ess_compose_conf_dir }}/synapse/log_config.yaml:/conf/log_config.yaml:ro
|
||||
- {{ ess_compose_secrets_dir }}:/secrets/ess-generated:ro
|
||||
- synapse_media:/media
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-fsS", "http://localhost:8080/health"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 30
|
||||
start_period: 60s
|
||||
|
||||
{% for i in range(ess_synapse_fed_reader_replicas | int) %}
|
||||
synapse-fed-reader-{{ i }}:
|
||||
image: {{ ess_images.synapse_pro_worker }}
|
||||
container_name: synapse-fed-reader-{{ i }}
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
synapse-main: { condition: service_healthy }
|
||||
networks: [ {{ ess_compose_internal_network }} ]
|
||||
environment:
|
||||
APP_CONFIG_FILEPATH: /conf/federation-reader.yaml
|
||||
volumes:
|
||||
- {{ ess_compose_conf_dir }}/synapse/federation-reader.yaml:/conf/federation-reader.yaml:ro
|
||||
- {{ ess_compose_secrets_dir }}:/secrets/ess-generated:ro
|
||||
|
||||
{% endfor %}
|
||||
# ===========================================================================
|
||||
# Matrix Authentication Service (4 listeners)
|
||||
# ===========================================================================
|
||||
|
||||
mas:
|
||||
image: {{ ess_images.mas }}
|
||||
container_name: mas
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
postgres: { condition: service_healthy }
|
||||
networks:
|
||||
- {{ ess_compose_internal_network }}
|
||||
- {{ ess_compose_traefik_network }}
|
||||
environment:
|
||||
MAS_CONFIG: /conf/mas-config.yaml
|
||||
command: ["server", "--no-migrate"]
|
||||
volumes:
|
||||
- {{ ess_compose_conf_dir }}/mas/config.yaml:/conf/mas-config.yaml:ro
|
||||
- {{ ess_compose_secrets_dir }}:/secrets/ess-generated:ro
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-fsS", "http://localhost:8081/health"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 20
|
||||
start_period: 30s
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.docker.network={{ ess_compose_traefik_network }}"
|
||||
- "traefik.http.routers.ess-mas.rule=Host(`{{ ess_hostnames.mas }}`)"
|
||||
- "traefik.http.routers.ess-mas.entrypoints={{ ess_compose_traefik_entrypoint }}"
|
||||
- "traefik.http.routers.ess-mas.tls=true"
|
||||
{% if ess_compose_traefik_certresolver | length > 0 %}
|
||||
- "traefik.http.routers.ess-mas.tls.certresolver={{ ess_compose_traefik_certresolver }}"
|
||||
{% endif %}
|
||||
- "traefik.http.services.ess-mas.loadbalancer.server.port=8080"
|
||||
|
||||
# MAS root listener (port 8082) is mounted as a separate Traefik router so
|
||||
# /.well-known/openid-configuration on the apex of the mas host is reachable.
|
||||
# We attach a second router on the same service via a path rule.
|
||||
|
||||
# ===========================================================================
|
||||
# HAProxy — fronts all Synapse + well-known traffic
|
||||
# ===========================================================================
|
||||
|
||||
haproxy:
|
||||
image: {{ ess_images.haproxy }}
|
||||
container_name: haproxy
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
synapse-main: { condition: service_healthy }
|
||||
networks:
|
||||
- {{ ess_compose_internal_network }}
|
||||
- {{ ess_compose_traefik_network }}
|
||||
command: ["-f", "/usr/local/etc/haproxy/haproxy.cfg", "-dW"]
|
||||
volumes:
|
||||
- {{ ess_compose_conf_dir }}/haproxy/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro
|
||||
- {{ ess_compose_conf_dir }}/haproxy/path_map_file:/synapse/path_map_file:ro
|
||||
- {{ ess_compose_conf_dir }}/haproxy/path_map_file_get:/synapse/path_map_file_get:ro
|
||||
- {{ ess_compose_conf_dir }}/haproxy/429.http:/synapse/429.http:ro
|
||||
- {{ ess_compose_conf_dir }}/haproxy/admin-allow-ips.lst:/synapse/admin-allow-ips.lst:ro
|
||||
- {{ ess_compose_conf_dir }}/haproxy/well-known/server:/well-known/server:ro
|
||||
- {{ ess_compose_conf_dir }}/haproxy/well-known/client:/well-known/client:ro
|
||||
- {{ ess_compose_conf_dir }}/haproxy/well-known/support:/well-known/support:ro
|
||||
- {{ ess_compose_conf_dir }}/haproxy/well-known/element.json:/well-known/element.json:ro
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-q", "-O-", "http://localhost:8406/synapse_ready"]
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 20
|
||||
start_period: 90s
|
||||
labels:
|
||||
# matrix.<server> -> HAProxy frontend synapse-http-in (port 8008)
|
||||
- "traefik.enable=true"
|
||||
- "traefik.docker.network={{ ess_compose_traefik_network }}"
|
||||
- "traefik.http.routers.ess-synapse.rule=Host(`{{ ess_hostnames.synapse }}`)"
|
||||
- "traefik.http.routers.ess-synapse.entrypoints={{ ess_compose_traefik_entrypoint }}"
|
||||
- "traefik.http.routers.ess-synapse.tls=true"
|
||||
{% if ess_compose_traefik_certresolver | length > 0 %}
|
||||
- "traefik.http.routers.ess-synapse.tls.certresolver={{ ess_compose_traefik_certresolver }}"
|
||||
{% endif %}
|
||||
- "traefik.http.routers.ess-synapse.service=ess-synapse"
|
||||
- "traefik.http.services.ess-synapse.loadbalancer.server.port=8008"
|
||||
# <server>/.well-known/matrix -> HAProxy well-known-in (port 8010)
|
||||
- "traefik.http.routers.ess-wellknown.rule=Host(`{{ ess_server_name }}`) && PathPrefix(`/.well-known/matrix`)"
|
||||
- "traefik.http.routers.ess-wellknown.entrypoints={{ ess_compose_traefik_entrypoint }}"
|
||||
- "traefik.http.routers.ess-wellknown.tls=true"
|
||||
{% if ess_compose_traefik_certresolver | length > 0 %}
|
||||
- "traefik.http.routers.ess-wellknown.tls.certresolver={{ ess_compose_traefik_certresolver }}"
|
||||
{% endif %}
|
||||
- "traefik.http.routers.ess-wellknown.service=ess-wellknown"
|
||||
- "traefik.http.services.ess-wellknown.loadbalancer.server.port=8010"
|
||||
|
||||
# ===========================================================================
|
||||
# Element Web (browser client)
|
||||
# ===========================================================================
|
||||
|
||||
element-web:
|
||||
image: {{ ess_images.element_web }}
|
||||
container_name: element-web
|
||||
restart: unless-stopped
|
||||
networks: [ {{ ess_compose_traefik_network }} ]
|
||||
volumes:
|
||||
- {{ ess_compose_conf_dir }}/element-web/config.json:/app/config.json:ro
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.docker.network={{ ess_compose_traefik_network }}"
|
||||
- "traefik.http.routers.ess-element-web.rule=Host(`{{ ess_hostnames.element_web }}`)"
|
||||
- "traefik.http.routers.ess-element-web.entrypoints={{ ess_compose_traefik_entrypoint }}"
|
||||
- "traefik.http.routers.ess-element-web.tls=true"
|
||||
{% if ess_compose_traefik_certresolver | length > 0 %}
|
||||
- "traefik.http.routers.ess-element-web.tls.certresolver={{ ess_compose_traefik_certresolver }}"
|
||||
{% endif %}
|
||||
- "traefik.http.services.ess-element-web.loadbalancer.server.port=8080"
|
||||
|
||||
# ===========================================================================
|
||||
# Element Admin (admin panel)
|
||||
# ===========================================================================
|
||||
|
||||
element-admin:
|
||||
image: {{ ess_images.element_admin }}
|
||||
container_name: element-admin
|
||||
restart: unless-stopped
|
||||
networks: [ {{ ess_compose_traefik_network }} ]
|
||||
environment:
|
||||
SERVER_NAME: "{{ ess_server_name }}"
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.docker.network={{ ess_compose_traefik_network }}"
|
||||
- "traefik.http.routers.ess-element-admin.rule=Host(`{{ ess_hostnames.element_admin }}`)"
|
||||
- "traefik.http.routers.ess-element-admin.entrypoints={{ ess_compose_traefik_entrypoint }}"
|
||||
- "traefik.http.routers.ess-element-admin.tls=true"
|
||||
{% if ess_compose_traefik_certresolver | length > 0 %}
|
||||
- "traefik.http.routers.ess-element-admin.tls.certresolver={{ ess_compose_traefik_certresolver }}"
|
||||
{% endif %}
|
||||
- "traefik.http.services.ess-element-admin.loadbalancer.server.port=8080"
|
||||
|
||||
# ===========================================================================
|
||||
# Matrix RTC / Element Call (LiveKit SFU + lk-jwt)
|
||||
# ===========================================================================
|
||||
|
||||
matrix-rtc-sfu:
|
||||
image: {{ ess_images.livekit }}
|
||||
container_name: matrix-rtc-sfu
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- {{ ess_compose_internal_network }}
|
||||
- {{ ess_compose_traefik_network }}
|
||||
command: ["--config", "/conf/sfu-config.yaml"]
|
||||
volumes:
|
||||
- {{ ess_compose_conf_dir }}/sfu/config.yaml:/conf/sfu-config.yaml:ro
|
||||
# WebRTC media ports — DMZ firewall must NAT-forward these to this host.
|
||||
ports:
|
||||
- "{{ ess_rtc_tcp_port }}:{{ ess_rtc_tcp_port }}/tcp"
|
||||
- "{{ ess_rtc_udp_port }}:{{ ess_rtc_udp_port }}/udp"
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.docker.network={{ ess_compose_traefik_network }}"
|
||||
- "traefik.http.routers.ess-matrix-rtc.rule=Host(`{{ ess_hostnames.matrix_rtc }}`)"
|
||||
- "traefik.http.routers.ess-matrix-rtc.entrypoints={{ ess_compose_traefik_entrypoint }}"
|
||||
- "traefik.http.routers.ess-matrix-rtc.tls=true"
|
||||
{% if ess_compose_traefik_certresolver | length > 0 %}
|
||||
- "traefik.http.routers.ess-matrix-rtc.tls.certresolver={{ ess_compose_traefik_certresolver }}"
|
||||
{% endif %}
|
||||
- "traefik.http.routers.ess-matrix-rtc.service=ess-matrix-rtc"
|
||||
- "traefik.http.services.ess-matrix-rtc.loadbalancer.server.port=7880"
|
||||
|
||||
matrix-rtc-authorisation:
|
||||
image: {{ ess_images.lk_jwt }}
|
||||
container_name: matrix-rtc-authorisation
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
matrix-rtc-sfu: { condition: service_started }
|
||||
networks:
|
||||
- {{ ess_compose_internal_network }}
|
||||
- {{ ess_compose_traefik_network }}
|
||||
environment:
|
||||
LIVEKIT_URL: "wss://{{ ess_hostnames.matrix_rtc }}"
|
||||
LIVEKIT_KEY: "{{ ess_livekit_key }}"
|
||||
LIVEKIT_SECRET_FROM_FILE: /secrets/ess-generated/ELEMENT_CALL_LIVEKIT_SECRET
|
||||
LIVEKIT_FULL_ACCESS_HOMESERVERS: "{{ ess_server_name }}"
|
||||
volumes:
|
||||
- {{ ess_compose_secrets_dir }}:/secrets/ess-generated:ro
|
||||
labels:
|
||||
# /sfu/get is the JWT token endpoint Element Call hits to join calls.
|
||||
# It lives on the same host as the SFU but on a different backend.
|
||||
- "traefik.enable=true"
|
||||
- "traefik.docker.network={{ ess_compose_traefik_network }}"
|
||||
- "traefik.http.routers.ess-matrix-rtc-auth.rule=Host(`{{ ess_hostnames.matrix_rtc }}`) && PathPrefix(`/sfu/get`)"
|
||||
- "traefik.http.routers.ess-matrix-rtc-auth.entrypoints={{ ess_compose_traefik_entrypoint }}"
|
||||
- "traefik.http.routers.ess-matrix-rtc-auth.tls=true"
|
||||
- "traefik.http.routers.ess-matrix-rtc-auth.priority=200"
|
||||
{% if ess_compose_traefik_certresolver | length > 0 %}
|
||||
- "traefik.http.routers.ess-matrix-rtc-auth.tls.certresolver={{ ess_compose_traefik_certresolver }}"
|
||||
{% endif %}
|
||||
- "traefik.http.routers.ess-matrix-rtc-auth.service=ess-matrix-rtc-auth"
|
||||
- "traefik.http.services.ess-matrix-rtc-auth.loadbalancer.server.port=8080"
|
||||
33
roles/ess_pro_compose/templates/element-web/config.json.j2
Normal file
33
roles/ess_pro_compose/templates/element-web/config.json.j2
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"bug_report_endpoint_url": "local",
|
||||
"default_server_config": {
|
||||
"m.homeserver": {
|
||||
"base_url": "https://{{ ess_hostnames.synapse }}",
|
||||
"server_name": "{{ ess_server_name }}"
|
||||
}
|
||||
},
|
||||
"element_call": {
|
||||
"use_exclusively": true
|
||||
},
|
||||
"embedded_pages": {
|
||||
"login_for_welcome": true
|
||||
},
|
||||
"features": {
|
||||
"feature_element_call_video_rooms": true,
|
||||
"feature_group_calls": true,
|
||||
"feature_new_room_decoration_ui": true,
|
||||
"feature_video_rooms": true
|
||||
},
|
||||
"mobile_guide_app_variant": "element-pro",
|
||||
"setting_defaults": {
|
||||
"UIFeature.deactivate": false,
|
||||
"UIFeature.passwordReset": false,
|
||||
"UIFeature.registration": {{ ess_enable_registration | bool | lower }},
|
||||
"feature_group_calls": true,
|
||||
"urlPreviewsEnabled": {{ ess_synapse_url_previews_enabled | bool | lower }},
|
||||
"urlPreviewsEnabled_e2ee": {{ ess_synapse_url_previews_enabled | bool | lower }}
|
||||
},
|
||||
"sso_redirect_options": {
|
||||
"immediate": false
|
||||
}
|
||||
}
|
||||
102
roles/ess_pro_compose/templates/generate-secrets.py.j2
Normal file
102
roles/ess_pro_compose/templates/generate-secrets.py.j2
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
#!/usr/bin/env python3
|
||||
# {{ ansible_managed }}
|
||||
"""
|
||||
Generate the ess-generated secret bundle the way the Helm chart's
|
||||
init-secrets job does. Idempotent: only writes files that don't exist.
|
||||
|
||||
Mirrors `matrix-tools generate-secrets` arguments from chart v{{ ess_chart_version }}.
|
||||
"""
|
||||
import os
|
||||
import secrets
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from cryptography.hazmat.primitives import serialization
|
||||
from cryptography.hazmat.primitives.asymmetric import ec, ed25519, rsa
|
||||
|
||||
SECRETS_DIR = Path("{{ ess_compose_secrets_dir }}")
|
||||
SECRETS_DIR.mkdir(mode=0o700, parents=True, exist_ok=True)
|
||||
|
||||
|
||||
def write_if_missing(name, content_bytes):
|
||||
p = SECRETS_DIR / name
|
||||
if p.exists():
|
||||
return False
|
||||
# Atomic-ish write
|
||||
tmp = p.with_suffix(p.suffix + ".tmp")
|
||||
tmp.write_bytes(content_bytes)
|
||||
os.chmod(tmp, 0o600)
|
||||
tmp.rename(p)
|
||||
return True
|
||||
|
||||
|
||||
def rand32():
|
||||
# `matrix-tools rand32` produces 32 url-safe characters
|
||||
return secrets.token_urlsafe(24)[:32].encode()
|
||||
|
||||
|
||||
def hex32():
|
||||
return secrets.token_hex(32).encode()
|
||||
|
||||
|
||||
def rsa_der():
|
||||
key = rsa.generate_private_key(public_exponent=65537, key_size=4096)
|
||||
return key.private_bytes(
|
||||
encoding=serialization.Encoding.DER,
|
||||
format=serialization.PrivateFormat.PKCS8,
|
||||
encryption_algorithm=serialization.NoEncryption(),
|
||||
)
|
||||
|
||||
|
||||
def ecdsa_prime256v1():
|
||||
key = ec.generate_private_key(ec.SECP256R1())
|
||||
return key.private_bytes(
|
||||
encoding=serialization.Encoding.PEM,
|
||||
format=serialization.PrivateFormat.PKCS8,
|
||||
encryption_algorithm=serialization.NoEncryption(),
|
||||
)
|
||||
|
||||
|
||||
def synapse_signing_key():
|
||||
# Synapse expects: ed25519 <keyid> <unpadded-base64-seed>
|
||||
import base64
|
||||
key = ed25519.Ed25519PrivateKey.generate()
|
||||
seed = key.private_bytes(
|
||||
encoding=serialization.Encoding.Raw,
|
||||
format=serialization.PrivateFormat.Raw,
|
||||
encryption_algorithm=serialization.NoEncryption(),
|
||||
)
|
||||
# 4-char keyid like Synapse generates
|
||||
keyid = secrets.token_hex(2)
|
||||
b64 = base64.b64encode(seed).rstrip(b"=").decode()
|
||||
return f"ed25519 a_{keyid} {b64}\n".encode()
|
||||
|
||||
|
||||
SPEC = {
|
||||
"POSTGRES_ADMIN_PASSWORD": rand32,
|
||||
"POSTGRES_SYNAPSE_PASSWORD": rand32,
|
||||
"POSTGRES_MATRIX_AUTHENTICATION_SERVICE_PASSWORD": rand32,
|
||||
"SYNAPSE_MACAROON": rand32,
|
||||
"SYNAPSE_REGISTRATION_SHARED_SECRET": rand32,
|
||||
"SYNAPSE_WORKERS_REPLICATION_SECRET": rand32,
|
||||
"SYNAPSE_SIGNING_KEY": synapse_signing_key,
|
||||
"MAS_SYNAPSE_SHARED_SECRET": rand32,
|
||||
"MAS_MATRIX_TOOLS_OIDC_CLIENT_SECRET": rand32,
|
||||
"MAS_ENCRYPTION_SECRET": hex32,
|
||||
"MAS_RSA_PRIVATE_KEY": rsa_der,
|
||||
"MAS_ECDSA_PRIME256V1_PRIVATE_KEY": ecdsa_prime256v1,
|
||||
"ELEMENT_CALL_LIVEKIT_SECRET": rand32,
|
||||
"ADMIN_USER_PASSWORD": rand32,
|
||||
}
|
||||
|
||||
|
||||
created = []
|
||||
for name, fn in SPEC.items():
|
||||
if write_if_missing(name, fn()):
|
||||
created.append(name)
|
||||
|
||||
if created:
|
||||
print("CREATED:", " ".join(created))
|
||||
else:
|
||||
print("NOCHANGE")
|
||||
sys.exit(0)
|
||||
9
roles/ess_pro_compose/templates/haproxy/429.http.j2
Normal file
9
roles/ess_pro_compose/templates/haproxy/429.http.j2
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
HTTP/1.0 429 Too Many Requests
|
||||
Cache-Control: no-cache
|
||||
Connection: close
|
||||
Content-Type: application/json
|
||||
access-control-allow-origin: *
|
||||
access-control-allow-methods: GET, POST, PUT, DELETE, OPTIONS
|
||||
access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, Authorization
|
||||
|
||||
{"errcode":"M_UNKNOWN","error":"Server is unavailable"}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
# {{ ansible_managed }}
|
||||
{% for cidr in ess_admin_allow_ips %}
|
||||
{{ cidr }}
|
||||
{% endfor %}
|
||||
177
roles/ess_pro_compose/templates/haproxy/haproxy.cfg.j2
Normal file
177
roles/ess_pro_compose/templates/haproxy/haproxy.cfg.j2
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
# {{ ansible_managed }}
|
||||
# Adapted from ess-helm chart {{ ess_chart_version }} (ess-haproxy ConfigMap).
|
||||
# K8s DNS-SRV-based service discovery replaced with direct compose hostnames.
|
||||
|
||||
global
|
||||
maxconn 20000
|
||||
log stdout format raw local0 info
|
||||
tune.maxrewrite 4096
|
||||
stats socket ipv4@127.0.0.1:1999 level admin
|
||||
dns-accept-family ipv4
|
||||
|
||||
defaults
|
||||
mode http
|
||||
fullconn 10000
|
||||
maxconn 10000
|
||||
log global
|
||||
option forwardfor if-none
|
||||
option forwarded
|
||||
timeout connect 5s
|
||||
timeout queue 60s
|
||||
timeout client 900s
|
||||
timeout http-keep-alive 900s
|
||||
timeout http-request 10s
|
||||
timeout server 180s
|
||||
http-reuse aggressive
|
||||
default-server maxconn 500
|
||||
option redispatch
|
||||
compression algo gzip
|
||||
compression type text/plain text/html text/xml application/json text/css
|
||||
hash-type consistent sdbm
|
||||
|
||||
# Compose resolves service names via the embedded DNS (127.0.0.11). We point
|
||||
# HAProxy at it so backend health-checks pick up restarts properly.
|
||||
resolvers compose-dns
|
||||
nameserver dns1 127.0.0.11:53
|
||||
accepted_payload_size 8192
|
||||
hold timeout 600s
|
||||
hold refused 600s
|
||||
|
||||
frontend prometheus
|
||||
bind *:8405
|
||||
http-request use-service prometheus-exporter if { path /metrics }
|
||||
monitor-uri /haproxy_test
|
||||
no log
|
||||
|
||||
frontend http-blackhole
|
||||
bind *:8009
|
||||
http-request deny content-type application/json string '{"errcode": "M_FORBIDDEN", "error": "Blocked"}'
|
||||
|
||||
frontend startup
|
||||
bind *:8406
|
||||
acl synapse_dead nbsrv(synapse-main) lt 1
|
||||
monitor-uri /synapse_ready
|
||||
monitor fail if synapse_dead
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Synapse traffic — main entrypoint that the DMZ Traefik points at for matrix.*
|
||||
# ----------------------------------------------------------------------------
|
||||
frontend synapse-http-in
|
||||
bind *:8008
|
||||
errorfile 503 /synapse/429.http
|
||||
http-request capture hdr(host) len 32
|
||||
http-request capture req.fhdr(x-forwarded-for) len 64
|
||||
http-request capture req.fhdr(user-agent) len 200
|
||||
|
||||
http-request set-header X-Forwarded-Proto https if !{ hdr(X-Forwarded-Proto) -m found }
|
||||
http-request set-var(txn.x_forwarded_proto) hdr(x-forwarded-proto)
|
||||
http-response add-header Strict-Transport-Security max-age=31536000 if { var(txn.x_forwarded_proto) -m str -i "https" }
|
||||
|
||||
# Access token extraction (used by upstream rate-limit decisions)
|
||||
http-request set-var(req.access_token) urlp("access_token") if { urlp("access_token") -m found }
|
||||
http-request set-var(req.access_token) req.fhdr(Authorization),word(2," ") if { hdr_beg("Authorization") -i "Bearer " }
|
||||
http-request set-header X-Access-Token %[var(req.access_token)]
|
||||
|
||||
http-response set-header Permissions-Policy "interest-cohort=()"
|
||||
|
||||
# Admin endpoint IP allow-list
|
||||
acl is_admin path_reg ^/_synapse/admin/.*
|
||||
http-request set-var(txn.user_ip) req.fhdr(x-forwarded-for) if { hdr(x-forwarded-for) -m found }
|
||||
http-request set-var(txn.user_ip) src if !{ hdr(x-forwarded-for) -m found }
|
||||
acl allow_ip_admin var(txn.user_ip) -m ip -f /synapse/admin-allow-ips.lst
|
||||
http-request deny if !allow_ip_admin is_admin
|
||||
|
||||
# FOSS-worker path maps (empty by default; reserved for advanced worker splits)
|
||||
acl has_get_map path -m reg -M -f /synapse/path_map_file_get
|
||||
http-request set-var(req.backend) path,map_reg(/synapse/path_map_file_get,main) if has_get_map METH_GET
|
||||
http-request set-var(req.backend) path,map_reg(/synapse/path_map_file,main) unless { var(req.backend) -m found }
|
||||
|
||||
# Pro federation-reader worker: takes /event, /state, /state_ids reads
|
||||
acl has_available_pro_fed nbsrv('synapse-pro-federation-api-requests') ge 1
|
||||
http-request set-var(req.backend) str('pro-federation-api-requests') if has_available_pro_fed { path -m reg ^/_matrix/federation/v1/event/ }
|
||||
http-request set-var(req.backend) str('pro-federation-api-requests') if has_available_pro_fed { path -m reg ^/_matrix/federation/v1/state/ }
|
||||
http-request set-var(req.backend) str('pro-federation-api-requests') if has_available_pro_fed { path -m reg ^/_matrix/federation/v1/state_ids/ }
|
||||
|
||||
# CORS preflight short-circuits
|
||||
acl rendezvous path_beg /_matrix/client/unstable/org.matrix.msc4108/rendezvous
|
||||
acl rendezvous path_beg /_synapse/client/rendezvous
|
||||
use_backend return_204_rendezvous if { method OPTIONS } rendezvous
|
||||
use_backend return_204_synapse if { method OPTIONS }
|
||||
|
||||
# Failover from pro-fed-reader to main if the worker is unavailable
|
||||
acl has_failover var(req.backend) -m str "pro-federation-api-requests"
|
||||
acl backend_unavailable str(),concat('synapse-',req.backend),nbsrv lt 1
|
||||
use_backend synapse-main-failover if has_failover backend_unavailable
|
||||
|
||||
use_backend synapse-%[var(req.backend)]
|
||||
|
||||
backend synapse-main
|
||||
default-server maxconn 250
|
||||
option httpchk
|
||||
http-check connect port 8080
|
||||
http-check send meth GET uri /health
|
||||
server main synapse-main:8008 check port 8080 resolvers compose-dns
|
||||
|
||||
backend synapse-main-failover
|
||||
default-server maxconn 250
|
||||
option httpchk
|
||||
http-check connect port 8080
|
||||
http-check send meth GET uri /health
|
||||
server main synapse-main:8008 check port 8080 resolvers compose-dns
|
||||
|
||||
backend synapse-pro-federation-api-requests
|
||||
option httpchk
|
||||
http-check connect port 8008
|
||||
http-check send meth GET uri /health/alive
|
||||
balance uri whole
|
||||
# The federation-reader worker is a Rust service speaking h2c.
|
||||
{% for i in range(ess_synapse_fed_reader_replicas | int) %}
|
||||
server fed-reader-{{ i }} synapse-fed-reader-{{ i }}:8008 check resolvers compose-dns proto h2
|
||||
{% endfor %}
|
||||
|
||||
backend return_204_synapse
|
||||
http-request return status 204 hdr "Access-Control-Allow-Origin" "*" hdr "Access-Control-Allow-Methods" "GET, HEAD, POST, PUT, DELETE, OPTIONS" hdr "Access-Control-Allow-Headers" "Origin, X-Requested-With, Content-Type, Accept, Authorization, Date" hdr "Access-Control-Expose-Headers" "Synapse-Trace-Id, Server"
|
||||
|
||||
backend return_204_rendezvous
|
||||
http-request return status 204 hdr "Access-Control-Allow-Origin" "*" hdr "Access-Control-Allow-Methods" "GET, HEAD, POST, PUT, DELETE, OPTIONS" hdr "Access-Control-Allow-Headers" "Origin, Content-Type, Accept, Content-Type, If-Match, If-None-Match" hdr "Access-Control-Expose-Headers" "Synapse-Trace-Id, Server, ETag"
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Well-known — served at the apex domain via the same HAProxy.
|
||||
# DMZ Traefik routes Host=`{{ ess_server_name }}` && PathPrefix(/.well-known) here.
|
||||
# ----------------------------------------------------------------------------
|
||||
frontend well-known-in
|
||||
bind *:8010
|
||||
acl is_delete_put_post_method method DELETE POST PUT
|
||||
http-request deny status 405 if is_delete_put_post_method
|
||||
|
||||
acl well-known path /.well-known/matrix/server
|
||||
acl well-known path /.well-known/matrix/client
|
||||
acl well-known path /.well-known/matrix/support
|
||||
acl well-known path /.well-known/element/element.json
|
||||
http-request redirect code 301 location https://{{ ess_hostnames.element_web }} unless well-known
|
||||
|
||||
use_backend well-known-static if well-known
|
||||
default_backend well-known-no-match
|
||||
|
||||
backend well-known-static
|
||||
mode http
|
||||
http-after-response set-header X-Frame-Options SAMEORIGIN
|
||||
http-after-response set-header X-Content-Type-Options nosniff
|
||||
http-after-response set-header X-XSS-Protection "1; mode=block"
|
||||
http-after-response set-header Content-Security-Policy "frame-ancestors 'self'"
|
||||
http-after-response set-header X-Robots-Tag "noindex, nofollow, noarchive, noimageindex"
|
||||
http-after-response set-header Access-Control-Allow-Origin *
|
||||
http-after-response set-header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
|
||||
http-after-response set-header Access-Control-Allow-Headers "X-Requested-With, Content-Type, Authorization"
|
||||
|
||||
http-request return status 200 content-type "application/json" file "/well-known/server" if { path /.well-known/matrix/server }
|
||||
http-request return status 200 content-type "application/json" file "/well-known/client" if { path /.well-known/matrix/client }
|
||||
http-request return status 200 content-type "application/json" file "/well-known/support" if { path /.well-known/matrix/support }
|
||||
http-request return status 200 content-type "application/json" file "/well-known/element.json" if { path /.well-known/element/element.json }
|
||||
|
||||
backend well-known-no-match
|
||||
mode http
|
||||
http-request deny status 404
|
||||
|
||||
backend return_500
|
||||
http-request deny deny_status 500
|
||||
5
roles/ess_pro_compose/templates/haproxy/path_map_file.j2
Normal file
5
roles/ess_pro_compose/templates/haproxy/path_map_file.j2
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# {{ ansible_managed }}
|
||||
# Map matrix paths to worker backends. Format: path_regexp backend_name
|
||||
# Chart default: empty (no FOSS-worker splits). Reserved for advanced
|
||||
# worker topologies; the Pro federation-reader routing is hard-coded in
|
||||
# haproxy.cfg via the synapse-pro-federation-api-requests backend.
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
# {{ ansible_managed }}
|
||||
# GET-only worker path map. See path_map_file for context.
|
||||
11
roles/ess_pro_compose/templates/haproxy/well-known/client.j2
Normal file
11
roles/ess_pro_compose/templates/haproxy/well-known/client.j2
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"m.homeserver": {
|
||||
"base_url": "https://{{ ess_hostnames.synapse }}"
|
||||
},
|
||||
"org.matrix.msc4143.rtc_foci": [
|
||||
{
|
||||
"livekit_service_url": "https://{{ ess_hostnames.matrix_rtc }}",
|
||||
"type": "livekit"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
{}
|
||||
|
|
@ -0,0 +1 @@
|
|||
{"m.server": "{{ ess_hostnames.synapse }}:443"}
|
||||
|
|
@ -0,0 +1 @@
|
|||
{}
|
||||
114
roles/ess_pro_compose/templates/mas/config.yaml.j2
Normal file
114
roles/ess_pro_compose/templates/mas/config.yaml.j2
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
## {{ ansible_managed }}
|
||||
## Matrix Authentication Service — merged from chart fragments.
|
||||
## Adapted from ess-helm {{ ess_chart_version }} for docker compose.
|
||||
|
||||
http:
|
||||
public_base: "https://{{ ess_hostnames.mas }}/"
|
||||
issuer: "https://{{ ess_hostnames.mas }}/"
|
||||
listeners:
|
||||
# Public web UI + OAuth + GraphQL + admin API. Fronted by DMZ Traefik.
|
||||
- name: web
|
||||
binds:
|
||||
- host: 0.0.0.0
|
||||
port: 8080
|
||||
resources:
|
||||
- name: human
|
||||
- name: oauth
|
||||
- name: assets
|
||||
- name: graphql
|
||||
undocumented_oauth2_access: true
|
||||
- name: adminapi
|
||||
# Internal — never exposed publicly. Used for healthchecks and metrics.
|
||||
- name: internal
|
||||
binds:
|
||||
- host: 0.0.0.0
|
||||
port: 8081
|
||||
resources:
|
||||
- name: health
|
||||
- name: prometheus
|
||||
- name: connection-info
|
||||
# Root domain — serves .well-known/openid-configuration et al. on
|
||||
# https://{{ ess_hostnames.mas }} root. Mounted as the public listener
|
||||
# since DMZ Traefik strips paths.
|
||||
- name: root
|
||||
binds:
|
||||
- host: 0.0.0.0
|
||||
port: 8082
|
||||
resources:
|
||||
- name: discovery
|
||||
- name: compat
|
||||
# Talks to Synapse on the internal network only.
|
||||
- name: synapse
|
||||
binds:
|
||||
- host: 0.0.0.0
|
||||
port: 8083
|
||||
resources:
|
||||
- name: discovery
|
||||
- name: oauth
|
||||
|
||||
database:
|
||||
uri: "postgresql://matrixauthenticationservice_user:{{ _ess_secrets.POSTGRES_MATRIX_AUTHENTICATION_SERVICE_PASSWORD }}@postgres:5432/matrixauthenticationservice?sslmode=prefer&application_name=matrix-authentication-service"
|
||||
|
||||
telemetry:
|
||||
metrics:
|
||||
exporter: prometheus
|
||||
|
||||
matrix:
|
||||
homeserver: "{{ ess_server_name }}"
|
||||
secret_file: {{ _ess_secret_mount }}/MAS_SYNAPSE_SHARED_SECRET
|
||||
endpoint: "http://synapse-main:8008"
|
||||
kind: synapse_modern
|
||||
|
||||
# ---- OAuth2 clients -------------------------------------------------------
|
||||
clients:
|
||||
# Matrix-tools admin client used by mas-cli operations.
|
||||
- client_id: "000000000000000MATR1XT001S"
|
||||
client_auth_method: client_secret_basic
|
||||
client_secret_file: {{ _ess_secret_mount }}/MAS_MATRIX_TOOLS_OIDC_CLIENT_SECRET
|
||||
|
||||
# ---- Signing keys & encryption (file-mounted) ----------------------------
|
||||
secrets:
|
||||
encryption_file: {{ _ess_secret_mount }}/MAS_ENCRYPTION_SECRET
|
||||
keys:
|
||||
- key_file: {{ _ess_secret_mount }}/MAS_RSA_PRIVATE_KEY
|
||||
- key_file: {{ _ess_secret_mount }}/MAS_ECDSA_PRIME256V1_PRIVATE_KEY
|
||||
|
||||
# ---- Policy ---------------------------------------------------------------
|
||||
policy:
|
||||
data:
|
||||
admin_clients:
|
||||
- "000000000000000MATR1XT001S"
|
||||
admin_users: []
|
||||
client_registration:
|
||||
allow_host_mismatch: false
|
||||
allow_insecure_uris: false
|
||||
|
||||
account:
|
||||
password_registration_enabled: {{ ess_enable_registration | bool | lower }}
|
||||
|
||||
passwords:
|
||||
enabled: true
|
||||
|
||||
{% if ess_oidc_enabled %}
|
||||
# ---- Upstream OIDC (Authentik for demo, Keycloak for prod) ----------------
|
||||
upstream_oauth2:
|
||||
providers:
|
||||
- id: "{{ ess_oidc_provider_ulid }}"
|
||||
human_name: "{{ ess_oidc_provider_name }}"
|
||||
issuer: "{{ ess_oidc_issuer }}"
|
||||
client_id: "{{ ess_oidc_client_id }}"
|
||||
client_secret: "{{ ess_oidc_client_secret }}"
|
||||
token_endpoint_auth_method: client_secret_basic
|
||||
scope: "{{ ess_oidc_scopes }}"
|
||||
claims_imports:
|
||||
localpart:
|
||||
action: require
|
||||
template: "{{ '{{ user.preferred_username }}' }}"
|
||||
displayname:
|
||||
action: suggest
|
||||
template: "{{ '{{ user.name }}' }}"
|
||||
email:
|
||||
action: suggest
|
||||
template: "{{ '{{ user.email }}' }}"
|
||||
set_email_verification: always
|
||||
{% endif %}
|
||||
30
roles/ess_pro_compose/templates/postgres/configure-dbs.sh.j2
Normal file
30
roles/ess_pro_compose/templates/postgres/configure-dbs.sh.j2
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#!/bin/sh
|
||||
# {{ ansible_managed }}
|
||||
# Postgres init script — chart-equivalent of configure-dbs.sh.
|
||||
# Reads password files from /secrets/ess-generated and creates two DBs.
|
||||
|
||||
set -e
|
||||
|
||||
create_or_ensure_db() {
|
||||
user="$1"
|
||||
db="$2"
|
||||
password="$3"
|
||||
admin_password="$4"
|
||||
|
||||
if echo -n "$admin_password" | psql -W -U postgres -tc "SELECT 1 FROM pg_catalog.pg_roles WHERE rolname = '$user'" | grep -q 1; then
|
||||
echo -n "$admin_password" | psql -W -U postgres -c "ALTER USER $user PASSWORD '$password'"
|
||||
else
|
||||
echo -n "$admin_password" | psql -W -U postgres -c "CREATE ROLE $user LOGIN PASSWORD '$password'"
|
||||
fi
|
||||
|
||||
if ! echo -n "$admin_password" | psql -W -U postgres -tc "SELECT 1 FROM pg_database WHERE datname = '$db'" | grep -q 1; then
|
||||
echo -n "$admin_password" | createdb --encoding=UTF8 --locale=C --template=template0 --owner=$user $db -U postgres
|
||||
fi
|
||||
}
|
||||
|
||||
POSTGRES_PASSWORD="$(cat /secrets/ess-generated/POSTGRES_ADMIN_PASSWORD)"
|
||||
ESS_SYNAPSE_PW="$(cat /secrets/ess-generated/POSTGRES_SYNAPSE_PASSWORD)"
|
||||
ESS_MAS_PW="$(cat /secrets/ess-generated/POSTGRES_MATRIX_AUTHENTICATION_SERVICE_PASSWORD)"
|
||||
|
||||
create_or_ensure_db "matrixauthenticationservice_user" "matrixauthenticationservice" "$ESS_MAS_PW" "$POSTGRES_PASSWORD"
|
||||
create_or_ensure_db "synapse_user" "synapse" "$ESS_SYNAPSE_PW" "$POSTGRES_PASSWORD"
|
||||
27
roles/ess_pro_compose/templates/redis/redis.conf.j2
Normal file
27
roles/ess_pro_compose/templates/redis/redis.conf.j2
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
# {{ ansible_managed }}
|
||||
# Redis config — adapted from ess-helm {{ ess_chart_version }}. Used as
|
||||
# pub/sub for Synapse worker replication; no persistence needed.
|
||||
|
||||
protected-mode no
|
||||
port 6379
|
||||
tcp-backlog 511
|
||||
tcp-keepalive 300
|
||||
timeout 0
|
||||
daemonize no
|
||||
supervised no
|
||||
loglevel notice
|
||||
logfile ''
|
||||
databases 16
|
||||
always-show-logo no
|
||||
stop-writes-on-bgsave-error yes
|
||||
save ''
|
||||
|
||||
# Disable persistence — Synapse uses Redis only for pub/sub between workers.
|
||||
appendonly no
|
||||
|
||||
maxmemory 256mb
|
||||
maxmemory-policy allkeys-lru
|
||||
|
||||
hz 1
|
||||
dynamic-hz yes
|
||||
jemalloc-bg-thread yes
|
||||
32
roles/ess_pro_compose/templates/sfu/config.yaml.j2
Normal file
32
roles/ess_pro_compose/templates/sfu/config.yaml.j2
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
## {{ ansible_managed }}
|
||||
## LiveKit SFU — adapted from ess-helm {{ ess_chart_version }}.
|
||||
|
||||
port: 7880
|
||||
|
||||
prometheus:
|
||||
port: 6789
|
||||
|
||||
logging:
|
||||
level: info
|
||||
pion_level: error
|
||||
json: false
|
||||
|
||||
rtc:
|
||||
use_external_ip: false
|
||||
tcp_port: {{ ess_rtc_tcp_port }}
|
||||
udp_port: {{ ess_rtc_udp_port }}
|
||||
# Public IP that LiveKit advertises in ICE candidates. The DMZ NAT forwards
|
||||
# {{ ess_rtc_tcp_port }}/TCP and {{ ess_rtc_udp_port }}/UDP to this host.
|
||||
node_ip: "{{ ess_rtc_external_ip }}"
|
||||
|
||||
# Keys are embedded directly (rendered at compose-up time). The single key
|
||||
# `{{ ess_livekit_key }}` matches what the authorisation service issues
|
||||
# tokens against.
|
||||
keys:
|
||||
{{ ess_livekit_key }}: "{{ _ess_secrets.ELEMENT_CALL_LIVEKIT_SECRET }}"
|
||||
|
||||
room:
|
||||
auto_create: false
|
||||
|
||||
turn:
|
||||
enabled: false
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
## {{ ansible_managed }}
|
||||
## synapse-pro-worker (Rust) federation reader.
|
||||
## This is a different config schema than Python Synapse.
|
||||
|
||||
http:
|
||||
bind_addr: "::"
|
||||
bind_port: 8008
|
||||
|
||||
metrics:
|
||||
bind_addr: "::"
|
||||
bind_port: 9001
|
||||
|
||||
synapse:
|
||||
server_name: "{{ ess_server_name }}"
|
||||
|
||||
database:
|
||||
connection_string: "postgresql://synapse_user:{{ _ess_secrets.POSTGRES_SYNAPSE_PASSWORD }}@postgres:5432/synapse?sslmode=prefer"
|
||||
|
||||
redis:
|
||||
host: redis
|
||||
port: 6379
|
||||
|
||||
logging: basic
|
||||
159
roles/ess_pro_compose/templates/synapse/homeserver.yaml.j2
Normal file
159
roles/ess_pro_compose/templates/synapse/homeserver.yaml.j2
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
## {{ ansible_managed }}
|
||||
## Synapse homeserver config — merged from chart fragments
|
||||
## 01-homeserver-underrides + 04-homeserver-overrides + 05-main.
|
||||
## Adapted from ess-helm {{ ess_chart_version }} for docker compose.
|
||||
|
||||
server_name: "{{ ess_server_name }}"
|
||||
public_baseurl: "https://{{ ess_hostnames.synapse }}/"
|
||||
web_client_location: "https://{{ ess_hostnames.element_web }}/"
|
||||
admin_contact: "{{ ess_admin_contact }}"
|
||||
|
||||
pid_file: /data/homeserver.pid
|
||||
signing_key_path: {{ _ess_secret_mount }}/SYNAPSE_SIGNING_KEY
|
||||
macaroon_secret_key_path: {{ _ess_secret_mount }}/SYNAPSE_MACAROON
|
||||
registration_shared_secret_path: {{ _ess_secret_mount }}/SYNAPSE_REGISTRATION_SHARED_SECRET
|
||||
worker_replication_secret_path: {{ _ess_secret_mount }}/SYNAPSE_WORKERS_REPLICATION_SECRET
|
||||
|
||||
log_config: "/conf/log_config.yaml"
|
||||
enable_metrics: true
|
||||
report_stats: false
|
||||
|
||||
# ---- Listeners (from 05-main.yaml) ----------------------------------------
|
||||
listeners:
|
||||
- port: 8008
|
||||
tls: false
|
||||
type: http
|
||||
bind_addresses: ['0.0.0.0', '::']
|
||||
x_forwarded: true
|
||||
resources:
|
||||
- names: [client, federation]
|
||||
compress: false
|
||||
- port: 9093
|
||||
tls: false
|
||||
type: http
|
||||
bind_addresses: ['0.0.0.0', '::']
|
||||
x_forwarded: false
|
||||
resources:
|
||||
- names: [replication]
|
||||
compress: false
|
||||
- port: 8080
|
||||
tls: false
|
||||
type: http
|
||||
bind_addresses: ['0.0.0.0', '::']
|
||||
x_forwarded: false
|
||||
resources:
|
||||
- names: [health]
|
||||
compress: false
|
||||
- type: metrics
|
||||
port: 9001
|
||||
bind_addresses: ['::']
|
||||
|
||||
enable_media_repo: true
|
||||
media_store_path: "/media/media_store"
|
||||
max_upload_size: "{{ ess_synapse_max_upload_size }}"
|
||||
|
||||
# ---- Pro modules ----------------------------------------------------------
|
||||
modules:
|
||||
- module: "synapse_ess_pro.EssPro"
|
||||
config:
|
||||
version_path: /ess/version
|
||||
- module: "synapse_mass_local_room_upgrades.MassLocalRoomUpgradesModule"
|
||||
config: {}
|
||||
|
||||
# ---- Database -------------------------------------------------------------
|
||||
database:
|
||||
name: psycopg2
|
||||
args:
|
||||
user: synapse_user
|
||||
password: "{{ _ess_secrets.POSTGRES_SYNAPSE_PASSWORD }}"
|
||||
dbname: synapse
|
||||
host: postgres
|
||||
port: 5432
|
||||
sslmode: prefer
|
||||
keepalives: 1
|
||||
keepalives_idle: 10
|
||||
keepalives_interval: 10
|
||||
keepalives_count: 3
|
||||
cp_min: 5
|
||||
cp_max: 10
|
||||
|
||||
# ---- Redis (required for workers) -----------------------------------------
|
||||
redis:
|
||||
enabled: true
|
||||
host: redis
|
||||
port: 6379
|
||||
|
||||
# Replication topology — fed-reader connects back to the main on 9093.
|
||||
instance_map:
|
||||
main:
|
||||
host: synapse-main
|
||||
port: 9093
|
||||
|
||||
# ---- Matrix 2.0 features (MSC4108 QR login, MSC4222 syncv2, MSC4143 RTC) --
|
||||
experimental_features:
|
||||
msc4143_enabled: true
|
||||
msc4222_enabled: true
|
||||
msc4108_enabled: true
|
||||
msc4028_push_encrypted_events: true
|
||||
|
||||
# ---- Delegated auth to MAS (stable since Synapse 1.118) -------------------
|
||||
matrix_authentication_service:
|
||||
enabled: true
|
||||
secret_path: {{ _ess_secret_mount }}/MAS_SYNAPSE_SHARED_SECRET
|
||||
endpoint: "http://mas:8083/"
|
||||
force_http2: true
|
||||
|
||||
password_config:
|
||||
localdb_enabled: false
|
||||
enabled: false
|
||||
|
||||
# ---- Matrix RTC (Element Call discovery) ----------------------------------
|
||||
matrix_rtc:
|
||||
transports:
|
||||
- type: livekit
|
||||
livekit_service_url: "https://{{ ess_hostnames.matrix_rtc }}"
|
||||
|
||||
# ---- URL previews ---------------------------------------------------------
|
||||
url_preview_enabled: {{ ess_synapse_url_previews_enabled | bool | lower }}
|
||||
url_preview_ip_range_whitelist: []
|
||||
url_preview_ip_range_blacklist:
|
||||
- '127.0.0.0/8'
|
||||
- '10.0.0.0/8'
|
||||
- '172.16.0.0/12'
|
||||
- '192.168.0.0/16'
|
||||
- '100.64.0.0/10'
|
||||
- '169.254.0.0/16'
|
||||
- '::1/128'
|
||||
- 'fe80::/10'
|
||||
- 'fc00::/7'
|
||||
|
||||
# ---- Federation -----------------------------------------------------------
|
||||
{% if ess_enable_federation %}
|
||||
send_federation: true
|
||||
federation_client_minimum_tls_version: '1.2'
|
||||
{% else %}
|
||||
send_federation: false
|
||||
federation_domain_whitelist: []
|
||||
{% endif %}
|
||||
|
||||
# ---- Other defaults from chart underrides ---------------------------------
|
||||
require_auth_for_profile_requests: true
|
||||
presence:
|
||||
enabled: false
|
||||
start_pushers: true
|
||||
max_event_delay_duration: 24h
|
||||
|
||||
room_list_publication_rules:
|
||||
- action: allow
|
||||
user_id: "@*:{{ ess_server_name }}"
|
||||
|
||||
rc_message:
|
||||
per_second: 0.5
|
||||
burst_count: 30
|
||||
rc_delayed_event_mgmt:
|
||||
per_second: 1
|
||||
burst_count: 20
|
||||
|
||||
trusted_key_servers:
|
||||
- server_name: "matrix.org"
|
||||
suppress_key_server_warning: true
|
||||
16
roles/ess_pro_compose/templates/synapse/log_config.yaml.j2
Normal file
16
roles/ess_pro_compose/templates/synapse/log_config.yaml.j2
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
## {{ ansible_managed }}
|
||||
version: 1
|
||||
formatters:
|
||||
precise:
|
||||
format: '%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s'
|
||||
handlers:
|
||||
console:
|
||||
class: logging.StreamHandler
|
||||
formatter: precise
|
||||
loggers:
|
||||
synapse.storage.SQL:
|
||||
level: INFO
|
||||
root:
|
||||
level: INFO
|
||||
handlers: [console]
|
||||
disable_existing_loggers: false
|
||||
Loading…
Add table
Add a link
Reference in a new issue