From 679c5f525ed6803c9a703c79d5ab5c16db5f9d1b Mon Sep 17 00:00:00 2001 From: Aine Date: Sat, 19 Sep 2026 12:16:05 +0100 Subject: [PATCH] maubot: fix trailing slash handling, add changelog entry --- CHANGELOG.md | 14 ++++++++++++++ .../molecule/default/verify.yml | 4 +++- .../tasks/validate_config.yml | 7 +++++++ .../matrix-bot-maubot/templates/labels.j2 | 19 ++++++++++++++++--- 4 files changed, 40 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6833a16bd..c5ac098cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,17 @@ +# 2026-09-19 + +## Maubot's plugin webhooks and management interface work again + +Maubot v0.6.0 removed the ability to customize the paths maubot serves internally, so the playbook now strips the public path prefix (`matrix_bot_maubot_path_prefix`, `/_matrix/maubot` by default) before proxying requests to maubot, and tells it about the prefix through its `public_url` instead. + +Two leftovers from that rework broke things. Plugin endpoints were still configured with a fully-prefixed path, even though maubot receives paths relative to the prefix, so every plugin webhook (`https://matrix.example.com/_matrix/maubot/plugin/...`) answered `404` and maubot handed out webhook URLs with a duplicated prefix (`/_matrix/maubot/_matrix/maubot/plugin/...`). The management interface also lacked a trailing-slash redirect, and because it loads its assets relative to the URL you visit, `https://matrix.example.com/_matrix/maubot` made browsers request `/_matrix/static/...` (which Synapse serves) instead of the interface itself. + +Maubot is now configured with a relative plugin base path (`/plugin/`), and the management endpoint redirects the slashless prefix to its trailing-slash form. Re-running the playbook (`just install-all`) regenerates the configuration and restarts maubot. + +A `matrix_bot_maubot_path_prefix` ending with a slash was never supported (the role's own documentation says the prefix must be `/` or not end with a slash), and the playbook now refuses such a value with an explicit error instead of deploying a half-working setup. + +If you expose maubot at the root (`matrix_bot_maubot_path_prefix: /`), your plugin webhook URLs move back to `/plugin/...`, where they were before the v0.6.0 upgrade. + # 2026-09-18 ## LiveKit JWT Service 0.7.0 and federated calls diff --git a/roles/custom/matrix-bot-maubot/molecule/default/verify.yml b/roles/custom/matrix-bot-maubot/molecule/default/verify.yml index 69f638999..671437a61 100644 --- a/roles/custom/matrix-bot-maubot/molecule/default/verify.yml +++ b/roles/custom/matrix-bot-maubot/molecule/default/verify.yml @@ -321,8 +321,10 @@ - "'traefik.http.services.matrix-bot-maubot.loadbalancer.server.port=29427' in matrix_bot_maubot_labels_lines" - "'traefik.http.routers.matrix-bot-maubot-management.rule=Host(`maubot.molecule.local`) && PathPrefix(`/molecule-maubot`)' in matrix_bot_maubot_labels_lines" - "'traefik.http.routers.matrix-bot-maubot-management.priority=719' in matrix_bot_maubot_labels_lines" + - "'traefik.http.middlewares.matrix-bot-maubot-management-slashless-redirect.redirectregex.regex=(/molecule-maubot)$' in matrix_bot_maubot_labels_lines" + - "'traefik.http.middlewares.matrix-bot-maubot-management-slashless-redirect.redirectregex.replacement=${1}/' in matrix_bot_maubot_labels_lines" - "'traefik.http.middlewares.matrix-bot-maubot-management-strip-prefix.stripprefix.prefixes=/molecule-maubot' in matrix_bot_maubot_labels_lines" - - "'traefik.http.routers.matrix-bot-maubot-management.middlewares=matrix-bot-maubot-management-strip-prefix' in matrix_bot_maubot_labels_lines" + - "'traefik.http.routers.matrix-bot-maubot-management.middlewares=matrix-bot-maubot-management-slashless-redirect,matrix-bot-maubot-management-strip-prefix' in matrix_bot_maubot_labels_lines" - "'traefik.http.routers.matrix-bot-maubot-management.entrypoints=web' in matrix_bot_maubot_labels_lines" - "'traefik.http.routers.matrix-bot-maubot-management.tls=false' in matrix_bot_maubot_labels_lines" - "'molecule.maubot.coverage=enabled' in matrix_bot_maubot_labels_lines" diff --git a/roles/custom/matrix-bot-maubot/tasks/validate_config.yml b/roles/custom/matrix-bot-maubot/tasks/validate_config.yml index 332c0c6f3..5b67325ce 100644 --- a/roles/custom/matrix-bot-maubot/tasks/validate_config.yml +++ b/roles/custom/matrix-bot-maubot/tasks/validate_config.yml @@ -50,3 +50,10 @@ - {'name': 'matrix_bot_maubot_homeserver_name', when: true} - {'name': 'matrix_bot_maubot_homeserver_url', when: true} - {'name': 'matrix_bot_maubot_initial_password', when: true} + +# The prefix is used verbatim in the redirect regex, the strip prefix and the public URL. +- name: Fail if matrix_bot_maubot_path_prefix ends with a slash + ansible.builtin.fail: + msg: >- + matrix_bot_maubot_path_prefix (`{{ matrix_bot_maubot_path_prefix }}`) must either be `/` or not end with a slash (e.g. `/_matrix/maubot`). + when: "matrix_bot_maubot_path_prefix != '/' and matrix_bot_maubot_path_prefix[-1] == '/'" diff --git a/roles/custom/matrix-bot-maubot/templates/labels.j2 b/roles/custom/matrix-bot-maubot/templates/labels.j2 index 12f0a40a0..144595bfe 100644 --- a/roles/custom/matrix-bot-maubot/templates/labels.j2 +++ b/roles/custom/matrix-bot-maubot/templates/labels.j2 @@ -20,6 +20,20 @@ traefik.http.services.matrix-bot-maubot.loadbalancer.server.port={{ matrix_bot_m # # ############################################################ +{% set middlewares = [] %} + +{% if matrix_bot_maubot_container_labels_management_prefix != '/' %} +# The management UI loads its assets relative to the document URL, so the prefix needs a trailing slash. +traefik.http.middlewares.matrix-bot-maubot-management-slashless-redirect.redirectregex.regex=({{ matrix_bot_maubot_container_labels_management_prefix | quote }})$ +traefik.http.middlewares.matrix-bot-maubot-management-slashless-redirect.redirectregex.replacement=${1}/ +{% set middlewares = middlewares + ['matrix-bot-maubot-management-slashless-redirect'] %} +{% endif %} + +{% if matrix_bot_maubot_container_labels_management_prefix != '/' %} +traefik.http.middlewares.matrix-bot-maubot-management-strip-prefix.stripprefix.prefixes={{ matrix_bot_maubot_container_labels_management_prefix }} +{% set middlewares = middlewares + ['matrix-bot-maubot-management-strip-prefix'] %} +{% endif %} + traefik.http.routers.matrix-bot-maubot-management.rule={{ matrix_bot_maubot_container_labels_management_traefik_rule }} {% if matrix_bot_maubot_container_labels_management_traefik_priority | int > 0 %} @@ -27,9 +41,8 @@ traefik.http.routers.matrix-bot-maubot-management.priority={{ matrix_bot_maubot_ {% endif %} traefik.http.routers.matrix-bot-maubot-management.service=matrix-bot-maubot -{% if matrix_bot_maubot_container_labels_management_prefix != '/' %} -traefik.http.middlewares.matrix-bot-maubot-management-strip-prefix.stripprefix.prefixes={{ matrix_bot_maubot_container_labels_management_prefix }} -traefik.http.routers.matrix-bot-maubot-management.middlewares=matrix-bot-maubot-management-strip-prefix +{% if middlewares | length > 0 %} +traefik.http.routers.matrix-bot-maubot-management.middlewares={{ middlewares | join(',') }} {% endif %} traefik.http.routers.matrix-bot-maubot-management.entrypoints={{ matrix_bot_maubot_container_labels_management_traefik_entrypoints }}