Bug description
The bug is that when I set custom app root with SUPERSET_APP_ROOT but some endpoints was generated incorrect.
SUPERSET_APP_ROOT: /analytics
1) Export dashboard -> http://hostname/analytics/analytics/api/v1/chart/data, but should be http://hostname/analytics/api/v1/chart/data (duplicate prefix)
2) Userinfo -> http://hostname/user_info/, but should be http://hostname/analytics/user_info/ (missing prefix)
3) Icon png -> https://hostname/static/assets/images/superset-logo-horiz.png, but should be https://hostname/analytics/static/assets/images/superset-logo-horiz.png (missing prefix)
### Screenshots/recordings
### Superset version
master / latest-dev
### Python version
3.9
### Node version
16
### Browser
Chrome
### Additional context
My full hem values.yaml
# https://github.com/apache/superset/tree/master/helm/superset
ingress:
enabled: true
ingressClassName: nginx
hosts:
- <hostname>
path: /
pathType: Prefix
tls: []
annotations:
nginx.ingress.kubernetes.io/proxy-connect-timeout: "300"
nginx.ingress.kubernetes.io/proxy-read-timeout: "300"
nginx.ingress.kubernetes.io/proxy-send-timeout: "300"
nginx.ingress.kubernetes.io/proxy-body-size: 100M
nginx.ingress.kubernetes.io/configuration-snippet: |
if ($request_uri = "/") {
return 301 /analytics;
}
if ($request_uri = "/static/assets/images/superset-logo-horiz.png") {
return 301 /analytics/static/assets/images/superset-logo-horiz.png;
}
image:
tag: 6.0.0rc1
redis:
enabled: true
persistence:
enabled: false
postgresql:
enabled: true
primary:
persistence:
enabled: false
bootstrapScript: |
#!/bin/bash
apt-get update && apt-get install -y gcc && \
uv pip install \
psycopg2-binary==2.9.10 \
clickhouse-connect==0.7.7 \
PyJWT==2.10.1 \
authlib
configOverrides:
secret: |
from flask import g
from jinja2 import pass_context
from flask_appbuilder.security.manager import AUTH_DB
SECRET_KEY = 's/lfxyPiVXz1H/mkCueBTJuTH7FlVoqCWVLCmOPqsCdE21pxoq4H4LNo'
@pass_context
def current_tenant(context, *args, **kwargs):
return getattr(g, "tenant_id", None) or "-1"
JINJA_CONTEXT_ADDONS = {
"current_tenant": current_tenant,
}
AUTH_TYPE = AUTH_DB
OAUTH_PROVIDERS = []
AUTH_USER_REGISTRATION = False
FEATURE_FLAGS = {
"ALLOW_FULL_CSV_EXPORT": True,
"ALERT_REPORTS": True,
"DASHBOARD_RBAC": True,
"ENABLE_TEMPLATE_PROCESSING" : True,
}
SQL_MAX_ROW = 300000
ROW_LIMIT = 300000
SESSION_COOKIE_SAMESITE = 'Lax'
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SECURE = False
TALISMAN_ENABLED = False
PUBLIC_ROLE_LIKE = "Gamma"
supersetNode:
env:
SUPERSET_APP_ROOT: /analytics
KEYCLOAK_BASE_URL: http://keycloak.dev.svc.cluster.local
livenessProbe:
httpGet:
path: /analytics/health
readinessProbe:
httpGet:
path: /analytics/health
startupProbe:
httpGet:
path: /analytics/health
configOverridesFiles:
custom_security_manager: files/custom_security_manager.py
custom_jwt_middleware: files/custom_jwt_middleware.py
custom_app_initialyzer: files/custom_app_initialyzer.py
clickhouse_connect_uri: host
extraConfigs:
import_datasources.yaml: |
{{ tpl (.Files.Get "files/import_datasources.yaml") . }}
Workaround with extra Ingress
``` apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: superset-fix namespace: {{ .Release.Namespace }} annotations: meta.helm.sh/release-name: superset-fix meta.helm.sh/release-namespace: {{ .Release.Namespace }} nginx.ingress.kubernetes.io/proxy-body-size: 100M nginx.ingress.kubernetes.io/proxy-connect-timeout: '300' nginx.ingress.kubernetes.io/proxy-read-timeout: '300' nginx.ingress.kubernetes.io/proxy-send-timeout: '300' nginx.ingress.kubernetes.io/rewrite-target: /analytics/$2 nginx.ingress.kubernetes.io/use-regex: 'true' spec: ingressClassName: nginx rules: - host: hostname http: paths: - path: /analytics/analytics(/|$)(.*) pathType: ImplementationSpecific backend: service: name: superset port: number: 8088
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: superset-userinfo-redirect namespace: {{ .Release.Namespace }} annotations: nginx.ingress.kubernetes.io/use-regex: "true" # Permanent redirect to /analytics/user_info/ nginx.ingress.kubernetes.io/permanent-redirect: "https://hostname/analytics/user_info/" spec: ingressClassName: nginx rules: - host: hostname http: paths: # Only match /user_info - path: "/user_info(/|$)" pathType: ImplementationSpecific backend: service: name: superset port: number: 8088 ```
Checklist
- [x] I have searched Superset docs and Slack and didn't find a solution to my problem.
- [x] I have searched the GitHub issue tracker and didn't find a similar bug report.
- [x] I have checked Superset's logs for errors and if I found a relevant Python stacktrace, I included it here as text in the "additional context" section.
Comment From: dosubot[bot]
Hi @Nurshinov! I'm Dosu and I’m helping the superset team.
Recent changes in Superset's frontend and backend have addressed issues with incorrect URL generation when using a custom SUPERSET_APP_ROOT. The frontend now consistently includes the appRoot prefix in endpoint URLs, preventing duplicate or missing prefixes for actions like login redirects and API calls (PR #34395). The bootstrap data handling was also improved to ensure application_root and static_assets_prefix are always set and normalized (PR #34680).
On the backend, setting SUPERSET_APP_ROOT triggers middleware that adjusts routing and automatically sets STATIC_ASSETS_PREFIX and APPLICATION_ROOT if not explicitly configured (app.py). For deployments under a subpath, it's important to set ENABLE_PROXY_FIX=True and configure your proxy (e.g., nginx) to set the X-Forwarded-Prefix header and route both static assets and API endpoints correctly (issue #34773).
If you're running the latest-dev branch, these fixes should be included. Double-check your environment variables and proxy configuration to ensure STATIC_ASSETS_PREFIX and APPLICATION_ROOT match your SUPERSET_APP_ROOT, and that your ingress/proxy sets X-Forwarded-Prefix. If you still see issues, make sure your frontend build is up-to-date and not caching old bootstrap data.
To reply, just mention @dosu.
How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other
Comment From: Nurshinov
@dosu No, it still doesn't work even with:
ENABLE_PROXY_FIX=True
STATIC_ASSETS_PREFIX: /analytics
APPLICATION_ROOT: /analytics
and X-Forwarded-Prefix
Comment From: dosubot[bot]
Your config matches the documented approach, but there are still known edge cases and ongoing fixes for subpath deployments. Here are some key points and troubleshooting steps:
- If you set both STATIC_ASSETS_PREFIX and APPLICATION_ROOT manually, and also set SUPERSET_APP_ROOT, you can get double prefixing (e.g., /analytics/analytics/...) if the values are not aligned. Try setting only SUPERSET_APP_ROOT and let Superset auto-populate the others, or ensure all three are set to exactly /analytics (no trailing slash) and not /analytics/ or /analytics/analytics.
- The order of middleware matters: AppRootMiddleware must run before ProxyFix for correct SCRIPT_NAME/path handling. This is handled in the default code, but custom app initializers or WSGI wrappers can break it.
- Hardcoded endpoints or static files (like /user_info/ or /static/assets/...) that don't use the bootstrapped prefix will miss the prefix unless rewritten at the proxy/ingress layer. Some open PRs are still fixing these cases (example, example).
- The frontend must receive the correct application_root and static_assets_prefix in the bootstrap data. If the frontend is caching old bootstrap data or assets, you can get inconsistent URLs—try a hard reload or clear your browser cache.
- This feature is still marked as BETA and some edge cases (like Swagger UI, OAuth/LDAP login, or certain links) may not fully respect SUPERSET_APP_ROOT yet (see open PRs).
If you still see issues, check the actual bootstrap data in your browser's dev tools (look for application_root and static_assets_prefix in the main page's JSON payload) and confirm they match your config. Also, verify that your ingress/proxy is not rewriting or stripping prefixes unexpectedly.
If you want to try the most robust config, set only SUPERSET_APP_ROOT=/analytics and ENABLE_PROXY_FIX=True, and let Superset auto-fill the other values. Make sure your proxy sets X-Forwarded-Prefix: /analytics and does not rewrite paths in a way that could cause double prefixing.
References:
- Backend config and middleware order
- Frontend fixes for appRoot in URLs
- Known edge cases and open PRs
- Official docs (feature is BETA)
To reply, just mention @dosu.
How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other
Comment From: msyavuz
I think the work for this was done by @martyngigg so maybe they have an input on this?