[GH-ISSUE #4424] [FEAT]: Allow AnythingLLM to be served under a subpath #2823

Closed
opened 2026-02-22 18:31:25 -05:00 by yindo · 4 comments
Owner

Originally created by @JMuff22 on GitHub (Sep 22, 2025).
Original GitHub issue: https://github.com/Mintplex-Labs/anything-llm/issues/4424

Originally assigned to: @angelplusultra on GitHub.

What would you like to see?

Hi, this is not a duplicate of already existing closed issues e.g https://github.com/Mintplex-Labs/anything-llm/issues/3732 https://github.com/Mintplex-Labs/anything-llm/issues/2078

I am presenting new evidence that suggest that serving AnythingLLM under a subpath is not currently possible, at least to my understanding and effort.

Setup

Docker image version: mintplexlabs/anythingllm latest image id: 7295dcce9f0f

Nginx

# The events block is required but can be empty for basic configurations.
events {}

http {
    # Define a map to handle WebSocket upgrades.
    map $http_upgrade $connection_upgrade {
        default upgrade;
        ''      close;
    }
    log_format detailed '$remote_addr - $remote_user [$time_local] '
                        '"$request" $status $body_bytes_sent '
                        '"$http_referer" "$http_user_agent" '
                        'upstream_addr: $upstream_addr '
                        'upstream_status: $upstream_status '
                        'upstream_response_time: $upstream_response_time';

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

        access_log /var/log/nginx/access.log detailed;
        error_log /var/log/nginx/error.log;

        ssl_certificate /etc/nginx/ssl/cert.pem;
        ssl_certificate_key /etc/nginx/ssl/key.pem;

        add_header X-Frame-Options "SAMEORIGIN";
        add_header X-Content-Type-Options "nosiff";

        location / {
            proxy_pass http://streamlit:8501;
            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_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $connection_upgrade;
            proxy_read_timeout 300s;
        }

        location /anything-llm/ {
            # --- CRITICAL FIXES START HERE ---

            gunzip on;

            # Force caching headers
            proxy_set_header If-Modified-Since "";
            proxy_set_header If-None-Match "";

            # Explicitly disable backend compression.
            proxy_set_header Accept-Encoding "";

            # Tell Nginx to run substitutions on all content types.
            sub_filter_types *;

            # path rewrites for HTML, CSS, and JS.
            sub_filter_once off;
            sub_filter 'href="/'  'href="/anything-llm/';
            sub_filter 'src="/'   'src="/anything-llm/';
            sub_filter 'action="/' 'action="/anything-llm/';
            sub_filter 'url("/' 'url("/anything-llm/';
            sub_filter "from('/" "from('/anything-llm/";
            sub_filter "'/api/" "'/anything-llm/api/"; # For single quotes in JS
            sub_filter '"/api/' '"/anything-llm/api/'; # For double quotes in JS
            sub_filter '`/api/' '`/anything-llm/api/'; # For backticks in JS
            sub_filter 'url(/'  'url(/anything-llm/';

            proxy_redirect / /anything-llm/;
            proxy_pass http://anything-llm:3001/;

            proxy_http_version 1.1;
            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_read_timeout 300s;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $connection_upgrade;
        }
    }
}

Docker compose

services:
  streamlit:
    build: .
    container_name: streamlit
    ports:
      - "8501:8501"
      - "8001:8001"
    volumes:
      - ~/.ssh:/root/.ssh:ro
      - ./hpc/ssh_config:/root/.ssh/config:ro
      - ./app:/app/app
    env_file:
      - .env

  anything-llm:
    image: mintplexlabs/anythingllm
    container_name: anything-llm
    ports:
      - "3001:3001"
    volumes:
      - ./anythingllm-storage:/app/server/storage
      - ./anythingllm-collector:/app/collector/hotdir
    environment:
      - STORAGE_DIR=/app/server/storage
    cap_add:
      - SYS_ADMIN
    env_file:
      - .env

  nginx:
    image: nginx:latest
    container_name: nginx
    ports:
      - "443:443"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./nginx/cert.pem:/etc/nginx/ssl/cert.pem
      - ./nginx/key.pem:/etc/nginx/ssl/key.pem
    depends_on:
      - streamlit
      - anything-llm

So I have 3 containers. Nginx on 80/443 proxies to streamlit at root path / and AnythingLLM on path anything-llm .

The problem

According to https://github.com/Mintplex-Labs/anything-llm/issues/3732 it should be possible to do this by configuring nginx to serve it under a subpath.

But as hinted

I still think that static assets like index.js need to move to suburl/index.js, even with proxy settings given above, and this needs some change at frontend code

Originally posted by @nader939 in #3732

The problem is, even with a bloated nginx configuration file like I have attached above, the problem still lies in the anythingLLM frontend requiring it to be served under the root path.

This is indicated by my logs

nginx                  | 172.19.0.1 - - [22/Sep/2025:11:06:22 +0000] "GET /anything-llm/ HTTP/1.1" 200 1767 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0" upstream_addr: 172.19.0.4:3001 upstream_status: 200 upstream_response_time: 0.034
nginx                  | 172.19.0.1 - - [22/Sep/2025:11:06:22 +0000] "GET /anything-llm/index.css HTTP/1.1" 200 286941 "https://localhost/anything-llm/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0" upstream_addr: 172.19.0.4:3001 upstream_status: 200 upstream_response_time: 0.007
nginx                  | 172.19.0.1 - - [22/Sep/2025:11:06:22 +0000] "GET /anything-llm/index.js HTTP/1.1" 200 1535470 "https://localhost/anything-llm/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0" upstream_addr: 172.19.0.4:3001 upstream_status: 200 upstream_response_time: 0.033
nginx                  | 172.19.0.1 - - [22/Sep/2025:11:06:22 +0000] "GET /api/system/logo?theme=default HTTP/1.1" 200 873 "https://localhost/anything-llm/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0" upstream_addr: 172.19.0.3:8501 upstream_status: 200 upstream_response_time: 0.012
nginx                  | 172.19.0.1 - - [22/Sep/2025:11:06:22 +0000] "GET /api/system/logo?theme=default HTTP/1.1" 200 873 "https://localhost/anything-llm/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0" upstream_addr: 172.19.0.3:8501 upstream_status: 200 upstream_response_time: 0.012
nginx                  | 172.19.0.1 - - [22/Sep/2025:11:06:22 +0000] "GET /anything-llm/favicon.png HTTP/1.1" 200 3641 "https://localhost/anything-llm/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0" upstream_addr: 172.19.0.4:3001 upstream_status: 200 upstream_response_time: 0.006
nginx                  | 172.19.0.1 - - [22/Sep/2025:11:06:22 +0000] "GET /anything-llm/favicon.png HTTP/1.1" 200 3641 "https://localhost/anything-llm/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0" upstream_addr: 172.19.0.4:3001 upstream_status: 200 upstream_response_time: 0.007

Here the problem is

| 172.19.0.1 - - [22/Sep/2025:11:06:22 +0000] "GET /api/system/logo?theme=default HTTP/1.1" 200 873 "https://localhost/anything-llm/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0" upstream_addr: 172.19.0.3:8501 upstream_status: 200 upstream_response_time: 0.012

i.e upstream_addr: 172.19.0.3:8501 it is still going to the streamlit served under the root path.

My suggestion

Add the ability for an environment variable to be added to configuration to serve frontend static content under a different subpath. Or otherwise state in the documentation that serving under a subpath is unsupported. At this stage, I think a FAQ entry or some note in the documentation is warranted.

Thanks!

Originally created by @JMuff22 on GitHub (Sep 22, 2025). Original GitHub issue: https://github.com/Mintplex-Labs/anything-llm/issues/4424 Originally assigned to: @angelplusultra on GitHub. ### What would you like to see? Hi, this is not a duplicate of already existing closed issues e.g https://github.com/Mintplex-Labs/anything-llm/issues/3732 https://github.com/Mintplex-Labs/anything-llm/issues/2078 I am presenting new evidence that suggest that serving AnythingLLM under a subpath is not currently possible, at least to my understanding and effort. ## Setup Docker image version: `mintplexlabs/anythingllm` `latest` image id: `7295dcce9f0f` Nginx ``` # The events block is required but can be empty for basic configurations. events {} http { # Define a map to handle WebSocket upgrades. map $http_upgrade $connection_upgrade { default upgrade; '' close; } log_format detailed '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent" ' 'upstream_addr: $upstream_addr ' 'upstream_status: $upstream_status ' 'upstream_response_time: $upstream_response_time'; server { listen 443 ssl; listen [::]:443 ssl; server_name localhost; access_log /var/log/nginx/access.log detailed; error_log /var/log/nginx/error.log; ssl_certificate /etc/nginx/ssl/cert.pem; ssl_certificate_key /etc/nginx/ssl/key.pem; add_header X-Frame-Options "SAMEORIGIN"; add_header X-Content-Type-Options "nosiff"; location / { proxy_pass http://streamlit:8501; 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_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_read_timeout 300s; } location /anything-llm/ { # --- CRITICAL FIXES START HERE --- gunzip on; # Force caching headers proxy_set_header If-Modified-Since ""; proxy_set_header If-None-Match ""; # Explicitly disable backend compression. proxy_set_header Accept-Encoding ""; # Tell Nginx to run substitutions on all content types. sub_filter_types *; # path rewrites for HTML, CSS, and JS. sub_filter_once off; sub_filter 'href="/' 'href="/anything-llm/'; sub_filter 'src="/' 'src="/anything-llm/'; sub_filter 'action="/' 'action="/anything-llm/'; sub_filter 'url("/' 'url("/anything-llm/'; sub_filter "from('/" "from('/anything-llm/"; sub_filter "'/api/" "'/anything-llm/api/"; # For single quotes in JS sub_filter '"/api/' '"/anything-llm/api/'; # For double quotes in JS sub_filter '`/api/' '`/anything-llm/api/'; # For backticks in JS sub_filter 'url(/' 'url(/anything-llm/'; proxy_redirect / /anything-llm/; proxy_pass http://anything-llm:3001/; proxy_http_version 1.1; 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_read_timeout 300s; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; } } } ``` Docker compose ```yaml services: streamlit: build: . container_name: streamlit ports: - "8501:8501" - "8001:8001" volumes: - ~/.ssh:/root/.ssh:ro - ./hpc/ssh_config:/root/.ssh/config:ro - ./app:/app/app env_file: - .env anything-llm: image: mintplexlabs/anythingllm container_name: anything-llm ports: - "3001:3001" volumes: - ./anythingllm-storage:/app/server/storage - ./anythingllm-collector:/app/collector/hotdir environment: - STORAGE_DIR=/app/server/storage cap_add: - SYS_ADMIN env_file: - .env nginx: image: nginx:latest container_name: nginx ports: - "443:443" volumes: - ./nginx/nginx.conf:/etc/nginx/nginx.conf - ./nginx/cert.pem:/etc/nginx/ssl/cert.pem - ./nginx/key.pem:/etc/nginx/ssl/key.pem depends_on: - streamlit - anything-llm ``` So I have 3 containers. Nginx on 80/443 proxies to streamlit at root path `/` and AnythingLLM on path `anything-llm` . ## The problem According to https://github.com/Mintplex-Labs/anything-llm/issues/3732 it should be possible to do this by configuring nginx to serve it under a subpath. But as hinted > I still think that static assets like index.js need to move to suburl/index.js, even with proxy settings given above, and this needs some change at frontend code _Originally posted by @nader939 in [#3732](https://github.com/Mintplex-Labs/anything-llm/issues/3732#issuecomment-3000427560)_ The problem is, even with a bloated nginx configuration file like I have attached above, the problem still lies in the anythingLLM frontend requiring it to be served under the root path. This is indicated by my logs ```sh nginx | 172.19.0.1 - - [22/Sep/2025:11:06:22 +0000] "GET /anything-llm/ HTTP/1.1" 200 1767 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0" upstream_addr: 172.19.0.4:3001 upstream_status: 200 upstream_response_time: 0.034 nginx | 172.19.0.1 - - [22/Sep/2025:11:06:22 +0000] "GET /anything-llm/index.css HTTP/1.1" 200 286941 "https://localhost/anything-llm/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0" upstream_addr: 172.19.0.4:3001 upstream_status: 200 upstream_response_time: 0.007 nginx | 172.19.0.1 - - [22/Sep/2025:11:06:22 +0000] "GET /anything-llm/index.js HTTP/1.1" 200 1535470 "https://localhost/anything-llm/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0" upstream_addr: 172.19.0.4:3001 upstream_status: 200 upstream_response_time: 0.033 nginx | 172.19.0.1 - - [22/Sep/2025:11:06:22 +0000] "GET /api/system/logo?theme=default HTTP/1.1" 200 873 "https://localhost/anything-llm/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0" upstream_addr: 172.19.0.3:8501 upstream_status: 200 upstream_response_time: 0.012 nginx | 172.19.0.1 - - [22/Sep/2025:11:06:22 +0000] "GET /api/system/logo?theme=default HTTP/1.1" 200 873 "https://localhost/anything-llm/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0" upstream_addr: 172.19.0.3:8501 upstream_status: 200 upstream_response_time: 0.012 nginx | 172.19.0.1 - - [22/Sep/2025:11:06:22 +0000] "GET /anything-llm/favicon.png HTTP/1.1" 200 3641 "https://localhost/anything-llm/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0" upstream_addr: 172.19.0.4:3001 upstream_status: 200 upstream_response_time: 0.006 nginx | 172.19.0.1 - - [22/Sep/2025:11:06:22 +0000] "GET /anything-llm/favicon.png HTTP/1.1" 200 3641 "https://localhost/anything-llm/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0" upstream_addr: 172.19.0.4:3001 upstream_status: 200 upstream_response_time: 0.007 ``` Here the problem is `| 172.19.0.1 - - [22/Sep/2025:11:06:22 +0000] "GET /api/system/logo?theme=default HTTP/1.1" 200 873 "https://localhost/anything-llm/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0" upstream_addr: 172.19.0.3:8501 upstream_status: 200 upstream_response_time: 0.012` i.e `upstream_addr: 172.19.0.3:8501` it is still going to the streamlit served under the root path. ## My suggestion Add the ability for an environment variable to be added to configuration to serve frontend static content under a different subpath. Or otherwise state in the documentation that serving under a subpath is unsupported. At this stage, I think a FAQ entry or some note in the documentation is warranted. Thanks!
yindo added the enhancementdocumentationDockerfeature request labels 2026-02-22 18:31:25 -05:00
yindo closed this issue 2026-02-22 18:31:25 -05:00
Author
Owner

@timothycarambat commented on GitHub (Sep 22, 2025):

The docker image is built with this .env in docker, which once it is compiled, we dont have a flag for it because the frontend it already compiled.

Right now, if you wanted to do this you would need to run the code outside of docker since we dont have an override for that value.

@timothycarambat commented on GitHub (Sep 22, 2025): The docker image is built with [this .env](https://github.com/Mintplex-Labs/anything-llm/blob/9466f671620366272228cfcc43d015aa7251a28d/frontend/.env.example#L3) in docker, which once it is compiled, we dont have a flag for it because the frontend it already compiled. Right now, if you wanted to do this you would need to run the code outside of docker since we dont have an override for that value.
Author
Owner

@angelplusultra commented on GitHub (Oct 6, 2025):

Thank you for the detailed issue report and the comprehensive configuration context you provided. We appreciate the time you took to document the problem and your suggested solution.

After careful consideration, we've decided to close this issue for the following reasons:

  1. Complexity and Risk: Implementing subpath support would require significant changes across multiple parts of the application (frontend build process, server routing, static asset serving, React Router configuration, and Docker build process). These changes could introduce unexpected side effects and break existing functionality.

  2. Limited Resources: Our development team has limited bandwidth, and we need to prioritize features that benefit the majority of our users. Subpath serving is a relatively niche use case compared to other requested features.

  3. Maintenance Burden: Adding this feature would increase the complexity of our codebase and create additional maintenance overhead for testing and support.

Alternative Solutions

While we can't implement native subpath support at this time, here are some alternative approaches you can use:

Option 1: Use a Subdomain Instead

Instead of serving at https://yoursite.com/anything-llm/, consider using a subdomain like https://anything-llm.yoursite.com/.

Option 2: Use a Reverse Proxy with Path Rewriting

You could use a more sophisticated reverse proxy setup that handles the path rewriting at the proxy level, though this would require more complex nginx configuration.

Option 3: Run AnythingLLM on a Different Port

Simply run AnythingLLM on a different port (e.g., 3001) and proxy to it directly without trying to serve it under a subpath.

Thank you for your understanding, and we hope one of these alternatives works for your use case!

@angelplusultra commented on GitHub (Oct 6, 2025): Thank you for the detailed issue report and the comprehensive configuration context you provided. We appreciate the time you took to document the problem and your suggested solution. After careful consideration, we've decided to close this issue for the following reasons: 1. **Complexity and Risk**: Implementing subpath support would require significant changes across multiple parts of the application (frontend build process, server routing, static asset serving, React Router configuration, and Docker build process). These changes could introduce unexpected side effects and break existing functionality. 2. **Limited Resources**: Our development team has limited bandwidth, and we need to prioritize features that benefit the majority of our users. Subpath serving is a relatively niche use case compared to other requested features. 3. **Maintenance Burden**: Adding this feature would increase the complexity of our codebase and create additional maintenance overhead for testing and support. ## Alternative Solutions While we can't implement native subpath support at this time, here are some alternative approaches you can use: ### Option 1: Use a Subdomain Instead Instead of serving at `https://yoursite.com/anything-llm/`, consider using a subdomain like `https://anything-llm.yoursite.com/`. ### Option 2: Use a Reverse Proxy with Path Rewriting You could use a more sophisticated reverse proxy setup that handles the path rewriting at the proxy level, though this would require more complex nginx configuration. ### Option 3: Run AnythingLLM on a Different Port Simply run AnythingLLM on a different port (e.g., 3001) and proxy to it directly without trying to serve it under a subpath. Thank you for your understanding, and we hope one of these alternatives works for your use case!
Author
Owner

@johnmcbride commented on GitHub (Oct 10, 2025):

Hi @angelplusultra

I was reading this and wanted to comment about the alternative solutions. Alot of companies try to use a single point of entry with subpath to front end alot of services. Especially those self hosting services. Couple things to note.

  1. For option 2, its nots a path rewriting issue. Anything LLM is hard coded to serve up the scripts and css off of the root url "/" so rewriting isnt really an option unless your talking about adding the subpath prior on initial load of the site. Generally you would want to remove paths not the other way.

  2. Different ports are not really an option for companies and can be blocked by firwalls, etc. Not really a good idea for a external service to run on anything other than 443 IMHO.

  3. SubDomain - acceptable but again, some companies/network admin wont allow this and most times is out of the control of someone trying to set this up, especially if they already have an existing nginx setup and approved certs,etc

Hopefully you'll reconsider opening this back up as lots of other projects enable an environment variable to specific a subpath

@johnmcbride commented on GitHub (Oct 10, 2025): Hi @angelplusultra I was reading this and wanted to comment about the alternative solutions. Alot of companies try to use a single point of entry with subpath to front end alot of services. Especially those self hosting services. Couple things to note. 1. For option 2, its nots a path rewriting issue. Anything LLM is hard coded to serve up the scripts and css off of the root url "/" so rewriting isnt really an option unless your talking about adding the subpath prior on initial load of the site. Generally you would want to remove paths not the other way. 2. Different ports are not really an option for companies and can be blocked by firwalls, etc. Not really a good idea for a external service to run on anything other than 443 IMHO. 3. SubDomain - acceptable but again, some companies/network admin wont allow this and most times is out of the control of someone trying to set this up, especially if they already have an existing nginx setup and approved certs,etc Hopefully you'll reconsider opening this back up as lots of other projects enable an environment variable to specific a subpath
Author
Owner

@VBota1 commented on GitHub (Dec 28, 2025):

Hello @angelplusultra

I know the issue is closed but would you be open to considering a PR for this?
I started working on one here: https://github.com/VBota1/anything-llm/tree/feature/subpath_support

@VBota1 commented on GitHub (Dec 28, 2025): Hello @angelplusultra I know the issue is closed but would you be open to considering a PR for this? I started working on one here: https://github.com/VBota1/anything-llm/tree/feature/subpath_support
yindo changed title from [FEAT]: Allow AnythingLLM to be served under a subpath to [GH-ISSUE #4424] [FEAT]: Allow AnythingLLM to be served under a subpath 2026-06-05 14:48:45 -04:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Mintplex-Labs/anything-llm#2823