Files
esh-pfi-infrastructure/stacks/synapse
vh 73866f6a7e feat(synapse): restrict /_synapse/admin to LAN, track the stack
Synapse mounts its admin API on the same vhost as the client API, so publishing
matrix.phasefinal.com published the admin surface too -- it answered 200 from
the open internet. HMAC-protected, so not an open door, but Synapse's own
guidance is to keep it off the public listener.

A higher-priority router (explicit priority 100, not relying on Traefik's
rule-length tie-break) scopes PathPrefix(/_synapse/admin) behind an ipallowlist.
Verified from a genuinely external vantage rather than from a fleet host, since
nh3-dev sits inside the allowed range and would have proved nothing: via the NH3
residential egress proxy the admin path returns 403 while the client API returns
200 and Element is unaffected.

The 10.0.0.0/8 entry matches nothing today and the comment says so rather than
implying fleet access exists. matrix.phasefinal.com resolves publicly, so fleet
hosts hairpin out their own WAN -- a request from nh3-dev arrived as
70.230.226.88. The rule is effectively deny-all through Traefik, which is the
intended posture: admin work goes through docker exec to localhost:8008 and
never traverses Traefik. Allow-listing the sites' WAN addresses was considered
and rejected as a maintenance trap on dynamic addresses.

Also brings the stack under stacks/ with the Postgres password replaced by a
required .env variable. The tracked copy and the live file have therefore
DIVERGED and deploy-stack.sh must not be used until the live file reads from a
.env; the README says so.
2026-09-01 16:09:42 -07:00
..

synapse — Matrix homeserver (ana-docker)

Canonical copy of the stack running at /opt/docker/compose/synapse/ on ana-docker (10.250.50.70). Serves matrix.phasefinal.com and chat.phasefinal.com through Traefik.

Deep documentation — current versions, the upgrade procedure, the appservice namespace decision, conventions, and the push-notification findings — lives in docs/pfi/vm-102-matrix-synapse.md. This file covers only what is specific to deploying the stack.

⚠ The password is NOT in this copy

The live compose carries POSTGRES_PASSWORD inline in plaintext. This tracked copy replaces it with ${POSTGRES_PASSWORD:?set in .env} so the secret is not committed.

They have therefore diverged, and deploy-stack.sh would push the placeholder over a working literal and break the database on next recreate. Do not deploy this stack from the repo until the live file has been converted to read from a .env — which is the right fix and is not done yet.

Until then: edit the live file on the host, then re-mirror to here.

/_synapse/admin is LAN-only

Synapse mounts its admin API on the same vhost as the client API, so publishing matrix.phasefinal.com published the admin surface with it — it answered 200 from the open internet until 2026-09-01.

A higher-priority router now scopes PathPrefix(/_synapse/admin) behind an ipallowlist. Verified from a genuinely external vantage (the NH3 residential egress proxy, not a fleet host): admin 403, client API 200, Element unaffected.

⚠ The 10.0.0.0/8 entry currently matches nothing, deliberately. The hostname resolves publicly, so fleet hosts hairpin out their own WAN and arrive as a public address — a request from nh3-dev measured as 70.230.226.88. The rule is effectively deny-all through Traefik, which is intended: admin work is done with docker exec synapse against localhost:8008, which never touches Traefik. Allow-listing the sites' WAN addresses was rejected — they are dynamic, and a stale entry either locks us out or hands admin to whoever inherits the address.

Upgrades

Take a verified pg_dump first. Schema migrations are one-way; an older Synapse will not start against a newer database, so rollback is restore, not revert. Full procedure in the docs link above.