Bug description

I tried to configure superset to work under a specific path url like the documentation : https://superset.apache.org/docs/configuration/configuring-superset/#configuring-the-application-root//

But it no works. I specify that my superset app works without application root configuration. I'm using docker with docker-compose-image-tag to start superset and I have nginx server to redirect url to superset app.

I set environment variables in .env-local like this :

SUPERSET_APP_ROOT = /analytics
ENABLE_PROXY_FIX = True

My nginx config for superset :

server {
    listen [::]:443 ssl;
    listen 443 ssl;

    server_name mydomain.fr

    include conf.d/ssl.conf;

    location /analytics/ {
        include conf.d/location.conf;
        proxy_set_header X-Script-Name /analytics;
        proxy_pass http://localhost:8088/;
    }

    access_log /var/log/nginx/superset/access.log;
    error_log /var/log/nginx/superset/error.log;
}

My location.conf :

proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $server_name;
proxy_set_header Connection keep-alive;
proxy_set_header Upgrade $http_upgrade;
proxy_cache_bypass $http_upgrade;

If I open "https://mydomain.fr/analytics" I'm redirected to https://mydomain.fr/superset/welcome with a 404 error. If I open "https://mydomain.fr/analytics/superset/welcome/" I have the menu bar, but nothing else, and inside the console, I see an error about a query on "https://mydomain.fr/api" without "analytics" path, and all the links in the menu don't have the path either.

I saw there is trouble with application root feature, is that supposed to work ? and on which version ?

Thanks

Screenshots/recordings

No response

Superset version

5.0.0

Python version

3.9

Node version

16

Browser

Firefox

Additional context

No response

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]

There are known issues with Superset 5.0.0 and earlier versions when deploying under a subpath (using SUPERSET_APP_ROOT or APPLICATION_ROOT), especially with Docker and nginx. The symptoms you describe—redirects to incorrect paths, missing subpath in API calls, and broken links—match these issues. Recent fixes were merged after 5.0.0 that address frontend and API routing bugs related to the application root, including proper handling of login redirects and API endpoints when a subpath is configured. These fixes are not present in 5.0.0, so you are likely hitting these known bugs [PR 34395] [PR 34680].

To reliably run Superset under a subpath, you will need to upgrade to a version that includes these fixes (anything after mid-August 2025). If you must stay on 5.0.0, there is no robust workaround—subpath support is incomplete and buggy in that release.

For reference, the recommended config is to set both APPLICATION_ROOT and STATIC_ASSETS_PREFIX to your subpath (e.g., /analytics), and use ENABLE_PROXY_FIX = True. In nginx, use proxy_set_header X-Forwarded-Prefix /analytics/ instead of X-Script-Name [example]. But even with these settings, 5.0.0 will not fully work under a subpath due to the frontend bugs described above.

Upgrading to a newer Superset version is the only reliable solution for subpath deployments.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other  Chat with Dosu Join Discord Share on X

Comment From: sadpandajoe

@dosu does this work currently in master?

Comment From: dosubot[bot]

Yes, subpath (application root) support works in master, with recent fixes merged to address frontend and API routing issues. The backend and frontend now consistently respect the SUPERSET_APP_ROOT/APPLICATION_ROOT setting for URLs, static assets, and most internal links, and tests confirm correct handling of the app root in both layers PR #34680 code.

However, there are still some known gaps: for example, OAuth login links and a few API endpoints may not yet prepend the app root, so full coverage is still considered BETA and may require further fixes issue discussion. For most use cases, deploying under a subpath now works as expected in master, but thorough testing in your environment is recommended.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other  Chat with Dosu Join Discord Share on X

Comment From: aklein-1s

I tried to build the master branch of superset using docker-compose.yml file but I have another problem : Image

After several tries I did a new install :

docker system prune
docker volume rm -f superset_db_home
docker volume rm -f superset_redis
docker volume rm -f superset_superset_home
docker compose build
docker compose up -d

I have the same problem.

I just update the port of nginx to 18080 because I already have a nginx server on the host binded on port 80.

The compose logs :

superset_app          | 2025-08-21 08:20:39,848:INFO:werkzeug:172.18.0.1 - - [21/Aug/2025 08:20:39] "GET /login/ HTTP/1.1" 200 -
superset_nginx        | 172.18.0.1 - - [21/Aug/2025:08:20:39 +0000] "GET /login/ HTTP/1.0" 200 3127 [1] "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:141.0) Gecko/20100101 Firefox/141.0" "172.16.20.3"
superset_app          | 2025-08-21 08:20:39,916:INFO:werkzeug:172.18.0.1 - - [21/Aug/2025 08:20:39] "GET /static/appbuilder/css/flags/flags16.css HTTP/1.1" 200 -
superset_nginx        | 2025/08/21 08:20:39 [warn] 35#35: *115 upstream sent duplicate header line: "Date: Thu, 21 Aug 2025 08:20:39 GMT", previous value: "Date: Thu, 21 Aug 2025 08:20:39 GMT", ignored while reading response header from upstream, client: 172.18.0.1, server: _, request: "GET /static/appbuilder/css/flags/flags16.css HTTP/1.0", upstream: "http://172.17.0.1:8088/static/appbuilder/css/flags/flags16.css", host: "mydomain.fr", referrer: "https://mydomain.fr/login/"
superset_nginx        | 172.18.0.1 - - [21/Aug/2025:08:20:39 +0000] "GET /static/appbuilder/css/flags/flags16.css HTTP/1.0" 200 1378 [1] "https://mydomain.fr/login/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:141.0) Gecko/20100101 Firefox/141.0" "172.16.20.3"
superset_app          | 2025-08-21 08:20:39,938:WARNING:superset.views.error_handling:HTTPException
superset_app          | Traceback (most recent call last):
superset_app          |   File "/app/.venv/lib/python3.11/site-packages/flask/app.py", line 1484, in full_dispatch_request
superset_app          |     rv = self.dispatch_request()
superset_app          |          ^^^^^^^^^^^^^^^^^^^^^^^
superset_app          |   File "/app/.venv/lib/python3.11/site-packages/flask/app.py", line 1469, in dispatch_request
superset_app          |     return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
superset_app          |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
superset_app          |   File "/app/.venv/lib/python3.11/site-packages/flask/app.py", line 502, in <lambda>
superset_app          |     view_func=lambda **kw: self_ref().send_static_file(**kw),  # type: ignore # noqa: B950
superset_app          |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
superset_app          |   File "/app/superset/app.py", line 97, in send_static_file
superset_app          |     return super().send_static_file(filename)
superset_app          |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
superset_app          |   File "/app/.venv/lib/python3.11/site-packages/flask/scaffold.py", line 317, in send_static_file
superset_app          |     return send_from_directory(
superset_app          |            ^^^^^^^^^^^^^^^^^^^^
superset_app          |   File "/app/.venv/lib/python3.11/site-packages/flask/helpers.py", line 557, in send_from_directory
superset_app          |     return werkzeug.utils.send_from_directory(  # type: ignore[return-value]
superset_app          |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
superset_app          |   File "/app/.venv/lib/python3.11/site-packages/werkzeug/utils.py", line 575, in send_from_directory
superset_app          |     raise NotFound()
superset_app          | werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
superset_app          | 2025-08-21 08:20:39,939:INFO:werkzeug:172.18.0.1 - - [21/Aug/2025 08:20:39] "GET /static/assets/images/loading.gif HTTP/1.1" 404 -
superset_nginx        | 172.18.0.1 - - [21/Aug/2025:08:20:39 +0000] "GET /static/assets/images/loading.gif HTTP/1.0" 404 334 [1] "https://mydomain.fr/login/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:141.0) Gecko/20100101 Firefox/141.0" "172.16.20.3"
superset_app          | 2025-08-21 08:20:39,970:WARNING:superset.views.error_handling:HTTPException
superset_app          | Traceback (most recent call last):
superset_app          |   File "/app/.venv/lib/python3.11/site-packages/flask/app.py", line 1484, in full_dispatch_request
superset_app          |     rv = self.dispatch_request()
superset_app          |          ^^^^^^^^^^^^^^^^^^^^^^^
superset_app          |   File "/app/.venv/lib/python3.11/site-packages/flask/app.py", line 1469, in dispatch_request
superset_app          |     return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
superset_app          |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
superset_app          |   File "/app/.venv/lib/python3.11/site-packages/flask/app.py", line 502, in <lambda>
superset_app          |     view_func=lambda **kw: self_ref().send_static_file(**kw),  # type: ignore # noqa: B950
superset_app          |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
superset_app          |   File "/app/superset/app.py", line 97, in send_static_file
superset_app          |     return super().send_static_file(filename)
superset_app          |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
superset_app          |   File "/app/.venv/lib/python3.11/site-packages/flask/scaffold.py", line 317, in send_static_file
superset_app          |     return send_from_directory(
superset_app          |            ^^^^^^^^^^^^^^^^^^^^
superset_app          |   File "/app/.venv/lib/python3.11/site-packages/flask/helpers.py", line 557, in send_from_directory
superset_app          |     return werkzeug.utils.send_from_directory(  # type: ignore[return-value]
superset_app          |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
superset_app          |   File "/app/.venv/lib/python3.11/site-packages/werkzeug/utils.py", line 575, in send_from_directory
superset_app          |     raise NotFound()
superset_app          | werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
superset_app          | 2025-08-21 08:20:39,971:INFO:werkzeug:172.18.0.1 - - [21/Aug/2025 08:20:39] "GET /static/assets/images/favicon.png HTTP/1.1" 404 -
superset_nginx        | 172.18.0.1 - - [21/Aug/2025:08:20:39 +0000] "GET /static/assets/images/favicon.png HTTP/1.0" 404 334 [1] "https://mydomain.fr/login/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:141.0) Gecko/20100101 Firefox/141.0" "172.16.20.3"

Comment From: aklein-1s

@dosu I finally found a part of solution for my problem, I use the main docker-compose.yml to deploy the solution, but without nginx container. However, I took and adapted its configuration (docker/nginx/templates/superset.conf) to deploy on my nginx server on the host :

server {
    listen [::]:443 ssl;
    listen 443 ssl;
    server_name mydomain.fr;

    include conf.d/ssl.conf;

    location /ws {
        proxy_pass http://superset_websocket;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_set_header Host $host;
    }

    location /analytics/static {
        proxy_pass http://localhost:9000;  # Proxy to superset-node
        proxy_http_version 1.1;
        proxy_set_header Host $host;
    }

    location /analytics {
        proxy_pass http://superset_app;
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_http_version 1.1;
        port_in_redirect off;
        proxy_connect_timeout 300;
    }

    access_log /var/log/nginx/superset/access.log;
    error_log /var/log/nginx/superset/error.log;
}

And in the .env-local :

SUPERSET_APP_ROOT = /analytics
STATIC_ASSETS_PREFIX = /analytics
ENABLE_PROXY_FIX = True

I tried to go to https://mydomain.fr/analytics

It no longer works like this, but I noticed errors in the firefox console : Image

So I update my superset.conf replacing location /analytics/static by location /static And in the .env-local STATIC_ASSETS_PREFIX = /analytics by STATIC_ASSETS_PREFIX = /static

The UI is now loading. I don't understand the logic how it can work in this configuration, while the first config seems more correct to me. How the line location /static can work with url https://mydomain.fr/analytics/static ? Do you have any explanation ?

I still have a problem with websocket : Image For this problem I don't have any idea yet.

Comment From: bxter

Image

i found the application icon . not support application_root setting in 6.0.0rc

Comment From: aklein-1s

@dosu I follow the thread to find a solution to my problem, and I understand why the url https://mydomain.fr/analytics/static works with my config, because I set the environment variable BUILD_SUPERSET_FRONTEND_IN_DOCKER to false and I ran npm i && npm run dev like the documentation said https://superset.apache.org/docs/installation/docker-compose/#option-1---for-an-interactive-development-environment

I deduced that I don't need the container superset-node from docker-compose.yml in this way, is that correct ?? So I will delete it from the compose file if it is useless. Furthermore I'm asking what is the use of containers superset-worker, superset-worker-beat and superset-tests-worker and how can I configure my nginx server to work with them with SUPERSET_APP_ROOT. For now I still have the access problem of ws : Image

So I shared my actual config of nginx :

upstream superset_app {
    server localhost:8088;
    keepalive 100;
}

upstream superset_websocket {
    server localhost:8080;
    keepalive 100;
}

server {
    listen [::]:443 ssl;
    listen 443 ssl;
    server_name mydomain.fr;

    include conf.d/ssl.conf;

    location /analytics/ws {
        proxy_pass http://superset_websocket;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Prefix /analytics/ws/;
    }

    location /analytics { 
        proxy_pass http://superset_app;
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Prefix /analytics/;
        proxy_http_version 1.1;
        port_in_redirect off;
        proxy_connect_timeout 300;
    }

    access_log /var/log/nginx/superset/access.log;
    error_log /var/log/nginx/superset/error.log;
}

Do you have any idea ?

@bxter I have the same problem with the logo

Comment From: dosubot[bot]

You're correct: when you set BUILD_SUPERSET_FRONTEND_IN_DOCKER=false and run npm i && npm run dev locally, the frontend assets are served by your local dev server on port 9000, so you do not need the superset-node container and can safely remove it from your docker-compose.yml (source).

The containers superset-worker, superset-worker-beat, and superset-tests-worker are for background tasks (Celery workers and schedulers). They do not expose any ports and do not serve HTTP traffic, so nginx does not need to proxy requests to them—they just communicate internally with the main app via Redis and the database (source).

For static assets and logo issues: Superset uses STATIC_ASSETS_PREFIX and APPLICATION_ROOT to determine asset paths. If you're running under a subpath (like /analytics), set both to /analytics and ensure nginx proxies /analytics/static to the correct frontend server. The logo path is hardcoded as /static/assets/images/superset-logo-horiz.png, so if asset prefixing or routing is inconsistent, you may see broken images (source). In dev mode, the frontend server may expect /static directly, which is why your config with location /static works.

For WebSocket (ws) issues: nginx must proxy /analytics/ws to the WebSocket backend (usually port 8080), with correct upgrade headers and path prefixing. Make sure the WebSocket service is running and reachable, and that your nginx config matches the expected path and headers (source). Double-check that your frontend is trying to connect to the right ws URL (including the /analytics prefix if set).

Let me know if you need help with a specific nginx config or debugging the WebSocket connection!

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other  Chat with Dosu Join Discord Share on X

Comment From: aklein-1s

I tried to access to https://mydomain.fr/analytics/ws but I get a not found result : Image

I watch the query in the container log : superset_websocket | {"level":"info","message":"Received unexpected request: GET /analytics/ws"}

So is it right to have this result accessing ws subpath ?

Comment From: aklein-1s

@dosu Have you any idea of my problem ?

I notice these comments in docker-compose.yml :

# Mounting a config file that contains a dummy secret required to boot up.
# do not use this docker compose in production/

Why can't we use docker in production ??

Comment From: dosubot[bot]

The default docker-compose.yml for Superset is only meant for development and testing, not production. There are several reasons for this:

  • It uses dummy secrets and weak default passwords (like SUPERSET_SECRET_KEY=TEST_NON_DEV_SECRET, POSTGRES_PASSWORD=superset, etc.), which are insecure and should never be used in production. The .env file even warns you to set unique, secure values for production use example.
  • Some containers (like superset-websocket) mount config files with dummy secrets and include explicit warnings not to use the setup in production example.
  • The environment is set to development mode (DEV_MODE=true, SUPERSET_ENV=development), and security features like CSRF and TALISMAN may be disabled or misconfigured, making the stack vulnerable example.
  • The docker-compose setup is designed for easy local development: it mounts source code, exposes ports, and relaxes security for convenience, not for operational safety or scalability.
  • The maintainers intentionally show a "Development" banner in the UI when running with docker-compose, and recommend using Kubernetes with Helm or Minikube for production deployments discussion.

If you want to use Docker in production, you must create your own docker-compose or orchestration setup with strong, unique secrets, production-ready configs, and hardened security. The default files are just a starting point for local development.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other  Chat with Dosu Join Discord Share on X

Comment From: aklein-1s

@dosu Ok I already customize my compose file, the application root seems to work, but I still have problems with websocket container : Image I get the logs from superset-websocket :

superset_websocket  |
superset_websocket  | > superset-websocket@0.0.1 start
superset_websocket  | > node dist/index.js start
superset_websocket  |
superset_websocket  | {"level":"info","message":"Server started on port 8080"}

Do you know how to resolve this ?

Comment From: dosubot[bot]

Your WebSocket connection is being refused because the superset-websocket container expects connections on port 8080 at the root path (not /analytics/ws or any subpath). If nginx proxies /analytics/ws directly to the websocket container without stripping the /analytics/ws prefix, the backend will log "Received unexpected request" and return 404 for normal HTTP GETs, and WebSocket upgrades will fail.

To fix this, update your nginx config so that requests to /analytics/ws are proxied to ws://superset_websocket:8080/ (the root), stripping the /analytics/ws prefix. You can do this by adding a rewrite rule:

location /analytics/ws {
    proxy_pass http://superset_websocket/;  # Note the trailing slash
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    # Do NOT set X-Forwarded-Prefix for the websocket location
    rewrite ^/analytics/ws/?(.*)$ /$1 break;
}

Make sure your frontend is connecting to wss://mydomain.fr/analytics/ws (not including any extra subpath after /ws). Also, confirm that nginx can reach the websocket container on port 8080 (test with curl http://localhost:8080/health from the nginx host).

If you still get connection refused, check for Docker network issues or firewall rules blocking port 8080. The websocket container must be reachable from nginx, and the proxy_pass must point to the correct internal Docker address.

The backend does not handle subpath prefixes for WebSocket connections—nginx must strip them before proxying. This is a common source of connection issues in subpath deployments. For more details, see the websocket server code and config here and here.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other  Chat with Dosu Join Discord Share on X

Comment From: aklein-1s

@dosu I test this nginx configuration for websocket container, but I still have the problem I check the command curl http://localhost:8080/health and it returns OK, How can I test that my frontend is connecting to wss://mydomain.fr/analytics/ws ?

Comment From: dosubot[bot]

To check if your frontend is connecting to wss://mydomain.fr/analytics/ws, open your browser’s developer tools (F12), go to the Network tab, and filter by “WS” or “WebSocket”. Reload the Superset page and look for any WebSocket connection attempts—note the exact URL, status (like “101 Switching Protocols” for success or an error), and any error messages. You can also check the browser console for WebSocket-related errors.

Superset’s frontend uses the WebSocket URL provided by the backend config (GLOBAL_ASYNC_QUERIES_WEBSOCKET_URL) and does not build it dynamically based on your app root or subpath—so if the connection is failing or the URL is wrong, you’ll need to set this config to the correct external URL (including your subpath) in your backend config (e.g., superset_config.py) source.

If you see failed connections or errors, share the exact error and URL shown in your browser’s network tab or console, and I can help interpret what’s happening. Also, check your nginx logs for requests to /analytics/ws to confirm they’re being proxied and rewritten correctly.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other  Chat with Dosu Join Discord Share on X