Both apps demanded a domain and Traefik. That was over-constrained: LibrePortal ships WireGuard, Headscale and private ports, so LAN and VPN-only is a first-class deployment here, and Rocket.Chat and Mattermost already prove chat apps work fine on http://<lan-ip>:<port>. The gate on Matrix rested on a mistake of mine: server_name being permanent. server_name and public_baseurl are independent — the identity can be a domain you own with no DNS behind it while clients reach the server on a LAN address, so federation can be switched on later by adding DNS and TLS, with no rebuild and no lost history. CFG_MATRIX_SERVER_NAME now exposes exactly that, and the install warns when it falls back to the machine's IP. What is genuinely lost without a domain is stated where it belongs, at install: Matrix cannot federate and Element's mobile apps want HTTPS; Stoat cannot do camera or microphone, because browsers gate getUserMedia on a secure context and a VPN does not change that, the check being on the URL scheme. Both now derive their URL from the port that was actually allocated. Since ports are only assigned during compose-up, each writes a best guess before start and corrects it afterwards, restarting only when the value really changed. Three bugs found while proving it works end to end: - The Synapse image writes /data as its UID/GID env, default 991, which under rootless is a host sub-UID owning nothing — so the generated signing key could not be moved by the install user. Both the generate container and the service now run as the same identity USER_TAG resolves to. - Element's config.json is bind-mounted as a file, and docker silently creates a DIRECTORY when the source is missing. An early return left exactly that landmine, which then broke every later run. It is written first now, and a stale directory is cleared. - A successful admin registration was reported as an error: checkSuccess read $? after an intervening [[ ]] test rather than the command's own status. Verified with no domain and no Traefik installed: Synapse answers /_matrix/client/versions and /health on http://<ip>:<port>, admin login returns a token, and Element is configured against the corrected base_url. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
109 lines
4.4 KiB
YAML
109 lines
4.4 KiB
YAML
# Synapse homeserver configuration.
|
|
#
|
|
# Copied to <app dir>/data/homeserver.yaml by matrix_install_post_compose, which
|
|
# substitutes the *_PLACEHOLDER values below. Edit the deployed copy, not this
|
|
# template — this one is only read at install time.
|
|
#
|
|
# Restart the container after editing: docker restart matrix-synapse
|
|
|
|
# server_name is permanent. It is signed into every event this server has ever
|
|
# sent and forms the second half of every user ID (@alice:<server_name>).
|
|
# Changing it later does not migrate anything — it orphans the whole database.
|
|
server_name: "SYNAPSE_SERVER_NAME_PLACEHOLDER"
|
|
|
|
# Where clients actually reach this server. Independent of server_name: on a
|
|
# LAN or WireGuard-only install this is http://<ip>:<port> while server_name
|
|
# stays whatever permanent identity you chose. Adding TLS later means changing
|
|
# only this line.
|
|
public_baseurl: "SYNAPSE_PUBLIC_BASEURL_PLACEHOLDER"
|
|
pid_file: /data/homeserver.pid
|
|
|
|
# Serve /.well-known/matrix/server ourselves, advertising port 443. Federation
|
|
# otherwise defaults to port 8448 on server_name, which Traefik is not
|
|
# listening on. Only switched on for a real HTTPS deployment — advertising
|
|
# <server_name>:443 from an install that is only reachable at http://<ip>:<port>
|
|
# would just invite other servers to connect somewhere that cannot answer.
|
|
serve_server_wellknown: SYNAPSE_SERVE_WELLKNOWN_PLACEHOLDER
|
|
|
|
listeners:
|
|
# Port 8008 is the container-internal port and is deliberately hardcoded: it
|
|
# is what CFG_MATRIX_PORT_1 declares as the internal half of its mapping, and
|
|
# what the Traefik service label points at. Change one and you must change all
|
|
# three.
|
|
- port: 8008
|
|
tls: false
|
|
type: http
|
|
# Traefik terminates TLS and proxies onward, so the source address Synapse
|
|
# sees is Traefik's. Without this, rate limiting and the audit log would
|
|
# attribute every request in the world to a single internal IP.
|
|
x_forwarded: true
|
|
bind_addresses: ['0.0.0.0']
|
|
resources:
|
|
- names: [client, federation]
|
|
compress: false
|
|
|
|
database:
|
|
name: psycopg2
|
|
args:
|
|
user: synapse
|
|
password: "SYNAPSE_DB_PASSWORD_PLACEHOLDER"
|
|
dbname: synapse
|
|
host: matrix-postgres
|
|
port: 5432
|
|
cp_min: 5
|
|
cp_max: 10
|
|
|
|
log_config: "/data/log.config"
|
|
media_store_path: /data/media_store
|
|
signing_key_path: "/data/signing.key"
|
|
|
|
# Uploads. Raise max_upload_size if your users share video; remember the
|
|
# reverse proxy has its own limit too.
|
|
max_upload_size: 50M
|
|
|
|
# Open registration is off by default: a reachable homeserver with registration
|
|
# enabled will be found and used for spam within days. The install creates one
|
|
# admin account for you; invite everyone else, or turn this on deliberately via
|
|
# CFG_MATRIX_ENABLE_REGISTRATION and re-run the install.
|
|
enable_registration: SYNAPSE_ENABLE_REGISTRATION_PLACEHOLDER
|
|
enable_registration_without_verification: SYNAPSE_ENABLE_REGISTRATION_PLACEHOLDER
|
|
|
|
registration_shared_secret: "SYNAPSE_REGISTRATION_SECRET_PLACEHOLDER"
|
|
macaroon_secret_key: "SYNAPSE_MACAROON_SECRET_PLACEHOLDER"
|
|
form_secret: "SYNAPSE_FORM_SECRET_PLACEHOLDER"
|
|
|
|
report_stats: false
|
|
suppress_key_server_warning: true
|
|
|
|
# Which servers to fetch other servers' signing keys from. matrix.org is the
|
|
# conventional default; federation still works if it is unreachable, just more
|
|
# slowly on first contact with a new server.
|
|
trusted_key_servers:
|
|
- server_name: "matrix.org"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Single sign-on against Authelia (optional)
|
|
# ---------------------------------------------------------------------------
|
|
# CFG_MATRIX_AUTHELIA must stay false — that switch puts Authelia's forward-auth
|
|
# in front of /_matrix, which breaks every client. Real SSO is done here
|
|
# instead, with Synapse as an OIDC client of Authelia.
|
|
#
|
|
# Register the client in Authelia's configuration.yml first, then uncomment and
|
|
# fill in the block below and restart the container.
|
|
#
|
|
# oidc_providers:
|
|
# - idp_id: authelia
|
|
# idp_name: "Authelia"
|
|
# issuer: "https://auth.<your domain>"
|
|
# client_id: "synapse"
|
|
# client_secret: "<the secret you set in Authelia>"
|
|
# scopes: ["openid", "profile", "email"]
|
|
# user_mapping_provider:
|
|
# config:
|
|
# localpart_template: "{{ user.preferred_username }}"
|
|
# display_name_template: "{{ user.name }}"
|
|
# email_template: "{{ user.email }}"
|
|
#
|
|
# The redirect URI to register in Authelia is:
|
|
# https://SYNAPSE_SERVER_NAME_PLACEHOLDER/_synapse/client/oidc/callback
|