Replaces `community.docker.docker_image` with the modern
`docker_image_pull` module. Drops the `ansible_version` compatibility
ladder and the now-redundant `_container_image_force_pull` variable
(the new pull module handles registry refresh natively via `pull: always`).
Related to https://github.com/spantaleev/matrix-docker-ansible-deploy/issues/5191.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces `community.docker.docker_image` with the modern
`docker_image_pull` module. Drops the `ansible_version` compatibility
ladder and the now-redundant `_container_image_force_pull` variable
(the new pull module handles registry refresh natively via `pull: always`).
Related to https://github.com/spantaleev/matrix-docker-ansible-deploy/issues/5191.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces `community.docker.docker_image` with the modern
`docker_image_pull` module. Drops the `ansible_version` compatibility
ladder and the now-redundant `_container_image_force_pull` variable
(the new pull module handles registry refresh natively via `pull: always`).
Related to https://github.com/spantaleev/matrix-docker-ansible-deploy/issues/5191.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The Draupnir roles now use `community.docker.docker_image_pull` and
`community.docker.docker_image_build`, both first available in
community.docker 3.6.0 (Jan 2024, shipped with Ansible 9.2.0).
This pin only takes effect for AWX / Automation Platform users (CLI
users do not install collections from this file), but those are the
users most likely to hit the issue with a stale collection cached in
their controller.
Related to https://github.com/spantaleev/matrix-docker-ansible-deploy/pull/5187.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The file is not used by the playbook's standard CLI install flow
(`make roles` / `just roles` only install roles via ansible-galaxy, not
collections). It exists for AWX / Ansible Automation Platform users,
where it is auto-detected during project sync.
Without this comment, the file looks like an unused leftover and is a
recurring source of confusion when discussing collection version pins
(should we add one here, etc.). Documenting the actual audience makes
those decisions more obvious.
No functional change.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sentence-case the heading to match the rest of the file, fix a broken
"appservice mode](url)(Draupnir for all)" link by folding the
parenthetical into the link text, hyphenate "non-release tag" and
"force-restart", correct "a update" -> "an update", and reword "work
perfectly" to the more accurate "work correctly".
Follow-up to 75f097e55 (#5187).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
matrix-bot-draupnir and matrix-appservice-draupnir-for-all share the same
upstream container image. When both are enabled and force-pull is on
(e.g. when pinning to a rolling tag like `latest` or `main`), the second
role to run during a single playbook invocation sees the image as already
up-to-date locally because the first role just pulled it. The
community.docker.docker_image module reports `changed: false` in that
case, so the second role's restart_necessary stays false and the
conditional restart logic skips it. Result: the first service picks up
the new image on restart, while the second keeps running the old one.
For other versions which don't get force-pulled (other than `latest`),
systemd service files also get updated by the playbook and these updates
done by each role properly flip the "requires restarting" variable
regardless of pulling. So it's just force-pulling that causes the problem.
Treating force-pull itself as a restart trigger sidesteps the lossy
"did this specific pull task fetch new bytes" heuristic. The downside
is that both Draupnir services now restart on every run when force-pull
is enabled, even when the upstream image has not moved. That is a small
amount of waste compared to silently running an outdated container.
Localized to these two roles via a comment that documents the
constraint, rather than applied playbook-wide, since this is the only
known image-sharing pair and other roles do not need the extra
restarts.
Fixes https://github.com/spantaleev/matrix-docker-ansible-deploy/issues/5186
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Synapse v1.152 introduces a new `quarantined_media_changes` stream and
requires that any worker serving `/_synapse/admin/v1/quarantine_media/`
be declared as a writer for that stream. Otherwise quarantining media
fails on the worker.
Add `quarantined_media_changes` as a web-facing stream writer alongside
the other stream-backed APIs and route the admin endpoint via the same
explicit writer-or-main model used for `device_lists`, `thread_subscriptions`,
etc. The endpoint is removed from `matrix_synapse_workers_media_repository_endpoints`
so the old media-repository route does not shadow (or conflict with) the
new writer-or-main route. Without that move, the previously-shipping
default of routing `/quarantine_media` to the `media_repository` worker
would silently break after the v1.152.0 image bump.
Default count is 1 in the `one-of-each` and `specialized-workers` presets
(matching `device_lists`), and 0 in `little-federation-helper` (which
also has no media-repository worker, so falling back to main is fine).
Refs:
- https://github.com/element-hq/synapse/blob/develop/docs/upgrade.md#upgrading-to-v11520
- https://element-hq.github.io/synapse/latest/workers.html#the-quarantined_media_changes-stream
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Ketesa needs the MAS admin API exposed to perform MAS-specific
operations (registration tokens, sessions, emails, etc.) when MAS
is in use.
The admin still needs to provision an admin token for Ketesa
manually, but at least the listener resource is now ready by default.
Mirrors the existing Synapse admin API auto-enable pattern.
Fixes https://github.com/spantaleev/matrix-docker-ansible-deploy/issues/5164
v1.3.0 moved the container's runtime paths to a unified MMRELAY_HOME=/data
model (credentials, database, logs, E2EE store, plugins all live under /data).
Legacy /app paths still work until v1.4.
Adapted the role to the new model: drop the three `/app/*` bind mounts and
the `_logs_path` variable, mount `_config_path` read-only at `/config` and
`_data_path` read-write at `/data`, and invoke the container as
`mmrelay --config /config/config.yaml` so the Ansible-managed config stays
separate from runtime data. Also drop the hardcoded `/app/data/...` database
and e2ee store_path overrides from the default config; MMRELAY_HOME defaults
place them under `_data_path/database/` and `_data_path/matrix/store/` on the
host.
Brings in a new `livekit_server_container_http_listen_interface`
variable, which allows publishing LiveKit's HTTP signaling port (7880)
on a host interface. Useful when a reverse-proxy fronting LiveKit runs
outside the container network.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Matches the earlier Python -> Go rewrites of the other mautrix-* bridges.
Related to:
- https://github.com/mautrix/telegram/releases/tag/v0.2604.0
- https://mau.fi/blog/2026-04-mautrix-release/
The bridge is now a Go binary with upstream-handled automatic database and
config migration on first start, so in-place upgrades on Postgres should
Just Work for users on the defaults. The lottieconverter sidecar container
is gone (bundled upstream), and the public web-based login endpoint is
gone (login happens inside Matrix now).
Upstream v0.2604.0 has a known bug in the legacy SQLite migration that
can corrupt data. The role detects legacy Python-bridge SQLite databases
(via the `telethon_sessions` table signature) and refuses to upgrade,
pointing users to switch to Postgres (playbook-managed pgloader migration)
or wait for the next upstream release. The guard is isolated in its own
`validate_config_sqlite_legacy_migration_bug.yml` so it can be deleted
cleanly once upstream fixes the bug.
Removed variables (all caught by the deprecation check in
`validate_config.yml` with actionable rename/removal hints): the entire
`_hostname` / `_path_prefix` / `_scheme` / `_public_endpoint` /
`_appservice_public_*` / `_container_labels_public_endpoint_*` /
`_container_http_host_bind_port` family (web login endpoint is gone);
`_bot_token` (old-style relaybot is gone, use the common bridgev2 relay
mode); `_filter_mode` (dropped upstream); `_bridge_login_shared_secret_map*`
(use Appservice Double Puppet); `_username_template`, `_alias_template`,
`_displayname_template` (templates moved under `network:`, new Go-template
syntax, exposed via `_network_displayname_template`); all
`_lottieconverter_*` variables; `_appservice_database` (renamed to
`_appservice_database_uri`).
Added playbook-time validation that catches legacy permission values
(`relaybot`, `puppeting`, `full`) in the fully-merged config (so overrides
via `matrix_mautrix_telegram_configuration_extension_yaml` are caught too),
with a mapping hint in the error message.
Other notes:
- The legacy sqlite->postgres relocation of `{base_path}/mautrix-telegram.db`
to `{data_path}/mautrix-telegram.db` now happens BEFORE the pgloader
migration step, so users who flip to Postgres as part of this upgrade
get their data imported correctly.
- The Ketesa managed-user regex for the telegram namespace is updated to
match both regular IDs and the new `channel-<id>` form used by bridgev2.
- `matrix_playbook_migration_expected_version` bumped to v2026.04.24.0,
with a new breaking-change entry pointing at the CHANGELOG section.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Avoid reopening a transition window where Synapse can accept new registrations or other auth changes
after syn2mas completes but before the MAS cutover is finalized.
Inspired by and continuing the work done in: https://github.com/spantaleev/matrix-docker-ansible-deploy/pull/5097
This backs out the LiveKit v1.10.0 role bump while we investigate MatrixRTC call failures reported in #5076.
The symptoms appear consistent with livekit/livekit#4384, and the upstream fix in livekit/livekit#4389 has not reached a release yet.
Register env, database config, scripts, and systemd service/timer results,
compute matrix_synapse_s3_storage_provider_restart_necessary, and wire it
into group_vars/matrix_servers instead of hardcoding restart_necessary: true.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Register image pull, env, and systemd service results, compute
matrix_goofys_restart_necessary, and wire it into group_vars/matrix_servers
instead of hardcoding restart_necessary: true.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace hardcoded restart_necessary: true with the computed
backup_borg_restart_necessary variable that the role already exposes.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace hardcoded restart_necessary: true with the computed variables
(jitsi_web_restart_necessary, jitsi_prosody_restart_necessary,
jitsi_jicofo_restart_necessary, jitsi_jvb_restart_necessary) that the
jitsi role already exposes.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace hardcoded restart_necessary: true with computed values for:
conduit, continuwuity, dendrite, element-call, media-repo,
appservice-kakaotalk, and wechat.
Each role now registers results from config, support files, systemd service,
and docker image pull tasks, then computes a restart_necessary variable
from their combined .changed state. group_vars/matrix_servers is updated
to reference these variables instead of hardcoding true.
For dendrite, the systemd service template was also separated out of the
combined support-files with_items loop so it can be independently tracked.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
These roles had conditional restart logic (restart_necessary set_fact) but
the docker_image build task result was not registered or included in the
condition, so a changed image build would not trigger a service restart.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
MAS now connects to the playbook-managed Postgres via a UNIX socket by
default (when available), matching the approach already used by Synapse.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
syn2mas reads Synapse's homeserver.yaml and reuses the database
connection details from there.
When Synapse is configured to reach the integrated Postgres over a UNIX socket,
the temporary syn2mas container was given the config file but not the socket mount,
so migrations could fail even though Synapse itself was configured correctly.
Wire the Synapse socket settings into MAS via playbook vars and mount
the same socket path into the syn2mas container, so migrations work in
socket-based deployments without coupling the MAS role directly to
Synapse role variables.
The client_reader route bucket had collapsed into one long alternation,
which made small worker-audit edits hard to review. Any endpoint change
rewrote the whole regex and obscured whether we were changing routing
policy or just maintaining the route list.
Refactor the variable into grouped regex entries with comments instead.
This keeps the current specialized-worker policy intact: nginx still
renders the client_reader locations in the same block, and the routes
still target the same upstream bucket. The goal here is to make future
doc/code audits, additions, and removals mechanical and reviewable.
This also matches MDAD's current worker model, where generic workers are
not mixed with the specialized room/sync/client/federation reader
routing buckets, so there is no need to derive this from the generic
worker map.
Refs:
- https://github.com/element-hq/synapse/blob/b99a58719b274fcbb327fd8d7649185792bfd12c/docs/workers.md#historical-apps
- https://github.com/element-hq/synapse/blob/b99a58719b274fcbb327fd8d7649185792bfd12c/docs/workers.md#synapseappgeneric_worker
Some client API endpoints (e.g. keys/upload) are backed by Synapse stream writers and
should not rely on broad worker regexes or route-order fallthrough for correctness.
When explicit per-stream routing is missing, requests may be captured by generic, room, or client_reader workers, instead of:
- going to the configured stream writer
- or to `main` when that stream writer is not enabled
This refactors synapse-reverse-proxy-companion's routing so that web-facing stream-backed endpoint families
are handled explicitly and early, with deterministic writer-or-main fallback.
Add first-class support for the missing `device_lists` stream writer,
generalize the same routing model to `push_rules`,
and remove stale broad-route ownership for device-list-sensitive endpoints.
The companion role was tightly coupled to Synapse through shared tags, worker routing, and lifecycle ordering. Keeping them separate added coordination overhead without practical benefits, especially for parallelized execution.
This merges the role into matrix-synapse while keeping companion logic organized under dedicated reverse_proxy_companion task/template subdirectories.
Compatibility is preserved:
- matrix_synapse_reverse_proxy_companion_* variable names remain unchanged
- install/setup companion-specific tags remain available
Cross-role/global wiring is now in group_vars (matrix-synapse section), while role defaults provide sensible standalone defaults and self-wiring for Synapse-owned values.
Only queue matrix-goofys.service for restart when Synapse is enabled. Goofys is installed from the Synapse role, so non-Synapse homeserver configurations should not try to restart this unit. This mirrors the fix for issue https://github.com/spantaleev/matrix-docker-ansible-deploy/issues/4959.
Only queue matrix-synapse-s3-storage-provider-migrate.timer for restart when Synapse is actually enabled. This prevents setup/install failures when a Synapse-only extension flag is set while using another homeserver implementation, as reported in https://github.com/spantaleev/matrix-docker-ansible-deploy/issues/4959.
The startup issue came from a timing dependency around coturn TLS certs:
- `matrix-coturn.service` depends on
`matrix-traefik-certs-dumper-wait-for-domain@<matrix-fqdn>.service`
- That waiter succeeds only after Traefik has obtained and dumped a cert for
the Matrix hostname (typically driven by homeserver labels/routes becoming
active)
- If coturn is started too early, it can block/fail waiting for cert files
that are not yet present
Historically, coturn priority was mode-dependent:
- `one-by-one`: coturn at 1500 (delayed after homeserver)
- other modes: coturn at 900 (before homeserver)
This could still trigger undesirable startup ordering and confusing behavior
in non-`one-by-one` modes, especially during initial bootstrap/restart flows
where cert availability lags service startup.
This change makes ordering explicit and consistent:
1. Introduce `matrix_homeserver_systemd_service_manager_priority` (default 1000)
in `roles/custom/matrix-base/defaults/main.yml`.
2. Use that variable for the homeserver service entry in
`group_vars/matrix_servers`.
3. Set coturn priority relative to homeserver priority in all modes:
`matrix_homeserver_systemd_service_manager_priority + 500`.
4. Update inline documentation comments in `group_vars/matrix_servers` to
match the new behavior and rationale.
Result:
- Homeserver/coturn ordering is deterministic and mode-agnostic.
- Coturn is intentionally started later than the homeserver by default,
reducing first-start certificate wait/fail races.
- Priority intent is now centralized and configurable via a dedicated
homeserver priority variable.
- Coturn may still be stated earlier, because the homeserver typically
has a `Wants` "dependency" on it, but that's alright
Users reported that /.well-known/matrix/* stopped being served after the image bump to static-web-server v2.41.0.
Regression introduced by commit 32aeaca28b in PR #4951: https://github.com/spantaleev/matrix-docker-ansible-deploy/pull/4951
Root cause: upstream changed hidden-file handling defaults, so paths under /.well-known were treated as hidden and no longer served by default.
Fix by explicitly configuring SERVER_IGNORE_HIDDEN_FILES=false in the matrix-static-files role and rendering it as a JSON boolean in the env template, making behavior stable across upstream default changes.
These three roles have multiple variable prefixes each:
- kakaotalk: matrix_appservice_kakaotalk + matrix_appservice_kakaotalk_node
- telegram: matrix_mautrix_telegram + matrix_mautrix_telegram_lottieconverter
- synapse: matrix_synapse + matrix_synapse_customized + matrix_synapse_rust_synapse_compress_state
For each: renamed _docker_image* to _container_image* (and _docker_src*,
_docker_repo* where applicable), added deprecation entries in
validate_config.yml, updated group_vars references, and moved
deprecation tasks to the front of validate_config.yml.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>