Skip to content

fix(plane-ce): https WEB_URL with TLS + Traefik trailing-slash redirects - #283

Open
kai-wei-mo wants to merge 1 commit into
makeplane:masterfrom
kai-wei-mo:fix/ce-web-url-https-traefik-trailing-slash
Open

fix(plane-ce): https WEB_URL with TLS + Traefik trailing-slash redirects#283
kai-wei-mo wants to merge 1 commit into
makeplane:masterfrom
kai-wei-mo:fix/ce-web-url-https-traefik-trailing-slash

Conversation

@kai-wei-mo

@kai-wei-mo kai-wei-mo commented Aug 9, 2026

Copy link
Copy Markdown

Summary

Self-hosting Plane CE behind Traefik/TLS currently forces WEB_URL to http://… (unlike plane-enterprise), which breaks CORS/auth flows when the app is only reachable over HTTPS. Traefik routes also lack explicit priorities and do not redirect /god-mode/god-mode/, so the admin SPA loads HTML but React Router fails (basename="/god-mode/").

This change:

  • Derives WEB_URL like enterprise: honor env.web_url when set; otherwise use https when TLS is configured (ssl.tls_secret_name, cert-manager certs, or Traefik ingress), else http
  • Adds Traefik route priorities so /god-mode, /api, … beat the catch-all /
  • Adds a Traefik 302 trailing-slash middleware for /god-mode, /spaces, and /live (temporary redirect to avoid sticky browser caches of bad Locations)
  • Documents env.web_url and bumps the chart to 1.6.3

Test plan

  • helm template with ingressClass=traefik + ssl.tls_secret_nameWEB_URL: https://…
  • helm template with ingressClass=nginx and no TLS → WEB_URL: http://…
  • helm template with env.web_url=https://custom.example.com → override wins
  • Traefik install: GET /god-mode302 to https://host/god-mode/ (no :3000 in Location)
  • Traefik install: /god-mode/ serves admin; / serves web

Out of scope / related

Frontend nginx still may emit :3000 in redirects without port_in_redirect off — that lives in makeplane/plane images (see makeplane/plane#8814 / PR #8826), not this chart.

Summary by CodeRabbit

  • New Features

    • Added optional web URL configuration with automatic HTTP/HTTPS fallback based on ingress and TLS settings.
    • Added trailing-slash redirects for /god-mode, /spaces, and /live routes.
    • Improved route prioritization for application, API, authentication, live, and storage paths.
  • Documentation

    • Updated deployment guidance for route priorities, redirects, and web URL configuration.
  • Chores

    • Updated the Helm chart version to 1.6.3.

…redirects

Align CE with enterprise WEB_URL selection (explicit env.web_url, else https
when TLS/Traefik is configured). Add Traefik route priorities and a 302
trailing-slash middleware so /god-mode matches the admin SPA basename.
@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

The Helm chart adds explicit WEB_URL configuration, TLS-aware URL derivation, Traefik route priorities, and temporary trailing-slash redirects for selected SPA paths. The chart version changes from 1.6.2 to 1.6.3.

Changes

Plane CE routing configuration

Layer / File(s) Summary
WEB_URL configuration
charts/plane-ce/values.yaml, charts/plane-ce/templates/config-secrets/app-env.yaml, charts/plane-ce/README.md
Adds optional env.web_url support. WEB_URL uses the explicit value when set and otherwise derives an HTTP or HTTPS URL from ingress and TLS settings.
Traefik route handling
charts/plane-ce/templates/traefik-middleware.yaml, charts/plane-ce/templates/ingress-traefik.yaml, charts/plane-ce/README.md, charts/plane-ce/Chart.yaml
Adds route priorities, trailing-slash redirects for /spaces, /god-mode, and /live, related documentation, and chart version 1.6.3.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Suggested reviewers: akshat5302, mguptahub

Poem

I’m a rabbit tuning routes tonight,
Making SPA paths redirect right.
WEB_URL follows TLS’s glow,
Priorities guide each request’s flow.
A chart hops from six-two to six-three—
Clean ingress paths for Plane CE!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main changes to HTTPS WEB_URL handling and Traefik trailing-slash redirects.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@charts/plane-ce/templates/config-secrets/app-env.yaml`:
- Around line 57-60: Update the WEB_URL inference condition in the app-env
template so the generated HTTPS URL requires .Values.ingress.enabled in addition
to the existing supported TLS/ingress checks. Keep explicit .Values.env.web_url
precedence unchanged, ensuring external HTTPS routes require that explicit value
when chart ingress is disabled.

In `@charts/plane-ce/templates/traefik-middleware.yaml`:
- Around line 28-30: Update the Traefik middleware regex to match optional query
strings for the god-mode, spaces, and live paths, capture those parameters, and
include the captured query portion in the replacement after adding the trailing
slash so redirects preserve the original parameters.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: f7658eec-4588-47bd-b37b-c065ed191a96

📥 Commits

Reviewing files that changed from the base of the PR and between e89b78a and 5dfd72b.

📒 Files selected for processing (6)
  • charts/plane-ce/Chart.yaml
  • charts/plane-ce/README.md
  • charts/plane-ce/templates/config-secrets/app-env.yaml
  • charts/plane-ce/templates/ingress-traefik.yaml
  • charts/plane-ce/templates/traefik-middleware.yaml
  • charts/plane-ce/values.yaml

Comment on lines +57 to +60
{{- if .Values.env.web_url }}
WEB_URL: {{ .Values.env.web_url | quote }}
{{- else if and .Values.ingress.appHost (or .Values.ssl.tls_secret_name (and .Values.ssl.createIssuer .Values.ssl.generateCerts) (hasPrefix "traefik" (.Values.ingress.ingressClass | default ""))) }}
WEB_URL: "https://{{ .Values.ingress.appHost }}"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

render_web_url() {
  helm template review charts/plane-ce \
    --set ingress.appHost=plane.example.com \
    --set ingress.enabled="$1" \
    --set ingress.ingressClass="$2" \
    --set ssl.tls_secret_name="$3" \
    --set ssl.createIssuer="$4" \
    --set ssl.generateCerts="$5" \
    --set env.web_url="" |
    awk '/name: review-app-vars/{in_map=1} in_map && /WEB_URL:/{print; exit}'
}

test "$(render_web_url false traefik "" false false)" = 'WEB_URL: "http://plane.example.com"'
test "$(render_web_url true traefik "" false false)" = 'WEB_URL: "https://plane.example.com"'

Repository: makeplane/helm-charts

Length of output: 197


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== locate relevant files =="
git ls-files | rg 'charts/plane-ce/(templates/(ingress-traefik|config-secrets/app-env)\.yaml|values\.yaml)$'

echo
echo "== relevant snippets =="
for f in charts/plane-ce/templates/ingress-traefik.yaml charts/plane-ce/templates/config-secrets/app-env.yaml charts/plane-ce/values.yaml; do
  if [ -f "$f" ]; then
    echo "--- $f ---"
    wc -l "$f"
    sed -n "1,110p" "$f"
  fi
done

echo
echo "== check helm availability =="
command -v helm || true

Repository: makeplane/helm-charts

Length of output: 9902


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== templates/gate occurrences for ingress.enabled, ssl, and ingressClass =="
rg -n "ingress\.enabled|ingressClass|createIssuer|generateCerts|tls_secret_name|\{\{- *if .*ingress" charts/plane-ce/templates charts/plane-ce/functions 2>/dev/null || true

echo
echo "== all ingress-related templates =="
git ls-files 'charts/plane-ce/templates/*ingress*'
for f in $(git ls-files 'charts/plane-ce/templates/*ingress*' 'charts/plane-ce/templates/config-secrets/app-env.yaml'); do
  if [ -f "$f" ]; then
    echo "--- $f ---"
    wc -l "$f"
    sed -n '1,120p' "$f"
  fi
done

Repository: makeplane/helm-charts

Length of output: 15004


🌐 Web query:

Helm template Go template hasPrefix string function syntax hasPrefix "traefik" .Values.ingress.ingressClass

💡 Result:

In Helm templates, the hasPrefix function is provided by the Sprig library [1][2]. It tests whether a string begins with a specified prefix and returns a boolean value [1][3]. Syntax The function takes two arguments: the prefix to search for, and the string to search within [1][2]. {{ hasPrefix "prefix" "your-string" }} Alternatively, it can be used in a pipeline: {{ "your-string" | hasPrefix "prefix" }} Example with.Values.ingress.ingressClass If you want to check if the ingressClass value starts with a specific string (for example, "traefik-"), you can use it in your Helm template as follows: {{- if hasPrefix "traefik-".Values.ingress.ingressClass }} # Logic to execute if it matches {{- end }} Or using the pipeline style: {{- if.Values.ingress.ingressClass | hasPrefix "traefik-" }} # Logic to execute if it matches {{- end }} Important Notes 1. Availability: Helm templates include Sprig functions by default [1]. You do not need to register them manually, unlike standard Go text/template which does not include this function natively [4][5]. 2. Traefik Context: While Traefik configuration often deals with ingressClass, ensure that the variable you are checking (.Values.ingress.ingressClass) is defined and of type string to avoid template execution errors [6][7]. If the value might be nil or empty, you may want to provide a default value: {{- if.Values.ingress.ingressClass | default "" | hasPrefix "traefik-" }}

Citations:


Gate HTTPS inference on chart-supported TLS/ingress.

charts/plane-ce/templates/config-secrets/app-env.yaml can emit WEB_URL: "https://..." when .Values.ingress.enabled=false and either .Values.ssl.tls_secret_name is set or .Values.ingress.ingressClass starts with traefik. Only charts/plane-ce/templates/ingress-traefik.yaml and the standard ingress use .Values.ingress.enabled, so an external ingress can receive a chart-generated HTTPS URL for a non-chart endpoint.

Require .Values.ingress.enabled or set env.web_url explicitly for external HTTPS routes.

Proposed fix
-  {{- else if and .Values.ingress.appHost (or .Values.ssl.tls_secret_name (and .Values.ssl.createIssuer .Values.ssl.generateCerts) (hasPrefix "traefik" (.Values.ingress.ingressClass | default ""))) }}
+  {{- else if and .Values.ingress.enabled .Values.ingress.appHost (or .Values.ssl.tls_secret_name (and .Values.ssl.createIssuer .Values.ssl.generateCerts) (hasPrefix "traefik" (.Values.ingress.ingressClass | default ""))) }}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{{- if .Values.env.web_url }}
WEB_URL: {{ .Values.env.web_url | quote }}
{{- else if and .Values.ingress.appHost (or .Values.ssl.tls_secret_name (and .Values.ssl.createIssuer .Values.ssl.generateCerts) (hasPrefix "traefik" (.Values.ingress.ingressClass | default ""))) }}
WEB_URL: "https://{{ .Values.ingress.appHost }}"
{{- if .Values.env.web_url }}
WEB_URL: {{ .Values.env.web_url | quote }}
{{- else if and .Values.ingress.enabled .Values.ingress.appHost (or .Values.ssl.tls_secret_name (and .Values.ssl.createIssuer .Values.ssl.generateCerts) (hasPrefix "traefik" (.Values.ingress.ingressClass | default ""))) }}
WEB_URL: "https://{{ .Values.ingress.appHost }}"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@charts/plane-ce/templates/config-secrets/app-env.yaml` around lines 57 - 60,
Update the WEB_URL inference condition in the app-env template so the generated
HTTPS URL requires .Values.ingress.enabled in addition to the existing supported
TLS/ingress checks. Keep explicit .Values.env.web_url precedence unchanged,
ensuring external HTTPS routes require that explicit value when chart ingress is
disabled.

Comment on lines +28 to +30
# Match full request URL; keep host/scheme, add trailing slash.
regex: "^(https://[^/]+)/(god-mode|spaces|live)$"
replacement: "${1}/${2}/"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

base="${BASE_URL%/}"

for path in /god-mode /spaces /live; do
  headers="$(curl -ksS -D - -o /dev/null --max-redirs 0 "$base${path}?probe=1")"
  status="$(printf '%s\n' "$headers" | awk 'NR == 1 {print $2}')"
  location="$(printf '%s\n' "$headers" | awk -F': ' 'tolower($1) == "location" {sub("\r$", "", $2); print $2; exit}')"

  test "$status" = "302"
  test "$location" = "$base${path}/?probe=1"
done

Repository: makeplane/helm-charts

Length of output: 200


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

echo "== candidate files =="
git ls-files | rg '(^|/)traefik-middleware\.yaml$|traefik|middleware' || true

echo "== file excerpt =="
if [ -f charts/plane-ce/templates/traefik-middleware.yaml ]; then
  cat -n charts/plane-ce/templates/traefik-middleware.yaml | sed -n '1,120p'
fi

echo "== route references =="
rg -n "god-mode|spaces|live|RedirectRegex|redirect" charts/plane-ce/templates || true

Repository: makeplane/helm-charts

Length of output: 6429


🌐 Web query:

Traefik RedirectRegex request URL RequestURI include query string documentation

💡 Result:

In Traefik, the RedirectRegex middleware performs redirection based on regex matching and replacement [1][2]. Regarding the inclusion of query strings, the behavior depends on the version and implementation details of how the redirect is handled: 1. Query String Handling: By default, the RedirectRegex middleware does not automatically append the original request's query string to the new location if the replacement URL is treated as an absolute URL [3][4]. When a redirect occurs, the final destination is determined by the replacement string provided in your configuration [1][5]. 2. Recent Improvements: Traefik has addressed issues where full URL replacements would drop the incoming query string [4]. In updated versions, logic has been introduced to carry over the original request's query string if the replacement URL does not already contain a query string [4]. 3. Implementation Notes: - Regex Capturing: The regex option is used to match and capture elements from the request URL, and the replacement option defines the new target URL [1][5]. - Variable Expansion: Use the ${1} syntax in the replacement field to reference captured groups [1][5]. When defining these in YAML, remember that certain characters might need double escaping [1][5]. - Security: Historically, there was an issue where query parameters could be incorrectly evaluated as template functions; this has been patched to ensure the middleware does not attempt to execute template logic from URL parameters [6]. If you find that your query strings are being dropped, ensure you are using a recent version of Traefik, as fixes for absolute-URL redirection parity with tools like NGINX have been implemented [4]. If the query string is not preserved automatically, you may need to explicitly include the query parameters in your regex/replacement logic or verify that your specific routing configuration allows for query string passthrough [3][4].

Citations:


Preserve query parameters in the trailing-slash redirect.

The middleware regex must match /god-mode?next=%2F, /spaces?probe=1, and /live?x=1. If the query string is captured as an optional group, include it in the replacement so the Location still carries the original parameters after the added trailing slash.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@charts/plane-ce/templates/traefik-middleware.yaml` around lines 28 - 30,
Update the Traefik middleware regex to match optional query strings for the
god-mode, spaces, and live paths, capture those parameters, and include the
captured query portion in the replacement after adding the trailing slash so
redirects preserve the original parameters.

Source: MCP tools

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant