From 95bc48a08a7ccaafec5c0ab5eabab9424d20087a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Barrag=C3=A1n=20Merino?= Date: Wed, 21 Oct 2026 12:09:08 +0000 Subject: [PATCH] :bug: Fix Admin Console URLs escaped twice MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Admin Console location built its proxy_pass target from a capture of $request_uri, which nginx escapes again when the path has escaped characters: %XX became %25XX and the query string ended up in the path, so Admin Console links returned 404. Strip the prefix with a rewrite and let proxy_pass forward the rewritten URI instead. AI-assisted-by: Claude Signed-off-by: David Barragán Merino --- .../nginx-admin-console-locations.conf.template | 11 ++++------- docker/images/files/nginx-entrypoint.sh | 13 ++++++------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/docker/images/files/nginx-admin-console-locations.conf.template b/docker/images/files/nginx-admin-console-locations.conf.template index 2b0a4f95b8..a2a90913b0 100644 --- a/docker/images/files/nginx-admin-console-locations.conf.template +++ b/docker/images/files/nginx-admin-console-locations.conf.template @@ -1,14 +1,11 @@ -# The Admin Console is served at the root of its own server: strip the public -# path and admin-console/ from the original request URI. +# The Admin Console is served at the root of its own server. Keep proxy_pass +# without a URI: building it from $request_uri escapes the path twice. location /admin-console { - set $admin_console_uri "/"; - if ($request_uri ~ "^${PENPOT_PUBLIC_PATH_REGEX}admin-console(/.*)$") { - set $admin_console_uri $1; - } + rewrite "^/admin-console(?:/(.*))?$" /$1 break; proxy_http_version 1.1; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $http_cf_connecting_ip; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_pass $PENPOT_ADMIN_CONSOLE_URI$admin_console_uri; + proxy_pass $PENPOT_ADMIN_CONSOLE_URI; } diff --git a/docker/images/files/nginx-entrypoint.sh b/docker/images/files/nginx-entrypoint.sh index e141db2d3a..d60a5d691f 100644 --- a/docker/images/files/nginx-entrypoint.sh +++ b/docker/images/files/nginx-entrypoint.sh @@ -53,18 +53,17 @@ update_oidc_name /var/www/app/js/config.js # Path of PENPOT_PUBLIC_URI (e.g. /penpot/ for https://example.com/penpot/). # Requests below it are rewritten to the root, so the proxy in front of this -# server forwards them unchanged and $request_uri keeps the original path. +# server forwards them unchanged. PENPOT_PUBLIC_PATH="$(sed -E 's|^[A-Za-z][A-Za-z0-9+.-]*://[^/]*||; s|[?#].*$||' <<< "${PENPOT_PUBLIC_URI:-}")" PENPOT_PUBLIC_PATH="/${PENPOT_PUBLIC_PATH#/}" export PENPOT_PUBLIC_PATH="${PENPOT_PUBLIC_PATH%/}/" -# shellcheck disable=SC2016 # literal regex metacharacters -PENPOT_PUBLIC_PATH_REGEX="$(sed -E 's/[][\.*^$(){}+?|]/\\&/g' <<< "$PENPOT_PUBLIC_PATH")" -export PENPOT_PUBLIC_PATH_REGEX - if [ "$PENPOT_PUBLIC_PATH" != "/" ]; then + # shellcheck disable=SC2016 # literal regex metacharacters + _public_path_regex="$(sed -E 's/[][\.*^$(){}+?|]/\\&/g' <<< "$PENPOT_PUBLIC_PATH")" export PENPOT_PUBLIC_PATH_DIRECTIVES="location = ${PENPOT_PUBLIC_PATH%/} { absolute_redirect off; return 301 ${PENPOT_PUBLIC_PATH}\$is_args\$args; } - rewrite ^${PENPOT_PUBLIC_PATH_REGEX}(.*)\$ /\$1 last;" + rewrite ^${_public_path_regex}(.*)\$ /\$1 last;" + unset _public_path_regex else export PENPOT_PUBLIC_PATH_DIRECTIVES="" fi @@ -81,7 +80,7 @@ envsubst "\$PENPOT_BACKEND_URI,\$PENPOT_EXPORTER_URI,\$PENPOT_HTTP_SERVER_MAX_BO if [[ $PENPOT_FLAGS == *"enable-admin-console"* ]]; then export PENPOT_ADMIN_CONSOLE_URI=${PENPOT_ADMIN_CONSOLE_URI:-http://penpot-admin-console:3000} - envsubst "\$PENPOT_ADMIN_CONSOLE_URI,\$PENPOT_PUBLIC_PATH_REGEX" \ + envsubst "\$PENPOT_ADMIN_CONSOLE_URI" \ < /tmp/nginx-admin-console-locations.conf.template > /etc/nginx/overrides/server.d/admin-console-locations.conf else rm -f /etc/nginx/overrides/server.d/admin-console-locations.conf