[GH-ISSUE #4221] help with white screen and /api/system/logo?theme=default returning 204 #2685

Closed
opened 2026-02-22 18:30:46 -05:00 by yindo · 6 comments
Owner

Originally created by @olagarde on GitHub (Jul 30, 2025).
Original GitHub issue: https://github.com/Mintplex-Labs/anything-llm/issues/4221

I'm new to the whole llm thing in general and anythingllm in specific. I've implemented many nginx reverse proxies over the years but never really dug into the details that much. This is probably just something dumb I've missed but I'm not seeing much matching this use case and this group seems pretty well versed on this subject, so....

I need to customize SSL client verification around AnythingLLM. I started with https://docs.anythingllm.com/installation-docker/cloud-docker, that assumes either no SSL or wide open CORS depending on viewpoint so I added https://gist.github.com/Stanback/7145487 (just the first I found of many, many identical examples). Anythingllm is being built bare-metal with the goal of developing on it and later curating our own containers. I've also tried the pre-built docker and gotten the same results, thus "probably my dumb".

Both bare-metal v1.8.3 and the latest docker container (mintplexlabs/anythingllm as of 31 Jul) produce effectively the same results. The container is as documented at https://docs.anythingllm.com/installation-docker/local-docker, "Run The Image", linux version and runs without errors. The build process is as documented in BARE_METAL.md and produces no errors. SELINUX and firewalld are off. The tab icon and title are loaded and displayed correctly but there's no page content, just like most "blank page" or "white page" posts on this forum but unlike those cases there's no Cross-Origin errors, bad gateways, or refused/blocked transactions. There are two instances per reload of null returns for the logo?theme=default though.
XHR GETs for

https://{server}/{proxy prefix}/api/system/logo?theme=default

are correctly proxied/rewritten to

https://localhost:3001/api/system/logo?theme=default

but then return 204 for the bare-metal build and 404 for the docker container. Checking that result with 'curl -ski {url}' replicates replies for both pre- and post-proxied URLs, both on the server host and on another Customer box one hop out on the enclave-facing network looking at the server host. Other than the usual "unknown property '-moz-...'" from the css there's no other errors, either in the syslogs or the browser console. As @timothycarambat has noted this is probably a red herring, but there's no other indication of failure; the JS launches appear to all succeed (see below) and there are no additional requests or packets in either direction, for either baremetal or containerized versions. Any ideas?

Redactions:

  • REDACTED (duh)
  • {server}: the server host running the nginx reverse proxy and anythingllm server and collector
  • {project_label}: the Customer-internal label for "this stuff"
  • {server_ipv4}: the ipv4 addr of the server in the Customer's internal network

Server:

Rocky Linux 8.10 updated yesterday
AnythingLLM 1.8.3
nginx 1.14.1-9
nodejs 18.20.8-1
npm 10.8.2-1.18.20.8.1
yarn 1.22.22-9

Client:

OSX 15.5 (24F74
firefox 138.0.1

server/.env:

LLM_PROVIDER='ollama'
EMBEDDING_MODEL_PREF='nomic-embed-text:latest'
OLLAMA_BASE_PATH='http://127.0.0.1:11434'
OLLAMA_MODEL_PREF='llama3'
OLLAMA_MODEL_TOKEN_LIMIT='4096'
EMBEDDING_ENGINE='ollama'
EMBEDDING_BASE_PATH='http://127.0.0.1:11434'
EMBEDDING_MODEL_MAX_CHUNK_LENGTH='8192'
VECTOR_DB='lancedb'
WHISPER_PROVIDER='local'
TTS_PROVIDER='native'
STORAGE_DIR='/var/{project_label}/anythingllm/serverdata'
SERVER_PORT='3001'
SIG_KEY='REDACTED'
SIG_SALT='REDACTED'
PASSWORDMINCHAR='15'
PASSWORDMAXCHAR='15'
PASSWORDLOWERCASE='2'
PASSWORDUPPERCASE='2'
PASSWORDNUMERIC='2'
PASSWORDSYMBOL='2'
PASSWORDREQUIREMENTS='4'
ENABLE_HTTPS='true'
HTTPS_CERT_PATH='/etc/pki/tls/private/anythingllm_cert.pem'
HTTPS_KEY_PATH='/etc/pki/tls/private/anythingllm_key.pem'
SIMPLE_SSO_ENABLED='1'
TARGET_OCR_LANG='eng,deu,ita,spa,fra,por,rus,nld,tur,hun,pol,ita,spa,fra,por,rus,nld,tur,hun,pol'

collector/.env:

SERVER_PORT='8888'
STORAGE_DIR='/var/{project_label}/anythingllm/collectordata'
NODE_ENV='production'

frontend/.env:

VITE_API_BASE='https://{server}/anythingllm/api'

Firefox console:

GET https://{server}/anythingllm/index.js [HTTP/2 200  274ms]
GET https://{server}/anythingllm/index.css [HTTP/2 200  112ms]
Error in parsing value for ‘-webkit-text-size-adjust’.  Declaration dropped. [index.css:1:11397]
Unknown property ‘-moz-column-gap’.  Declaration dropped. [index.css:1:34847]
Unknown property ‘-moz-column-gap’.  Declaration dropped. [index.css:1:34900]
Unknown property ‘-moz-column-gap’.  Declaration dropped. [index.css:1:34953]
Unknown property ‘-moz-column-gap’.  Declaration dropped. [index.css:1:35004]
Unknown property ‘-moz-column-gap’.  Declaration dropped. [index.css:1:35050]
Unknown property ‘-moz-column-gap’.  Declaration dropped. [index.css:1:35101]
Unknown property ‘-moz-column-gap’.  Declaration dropped. [index.css:1:35153]
Unknown property ‘-moz-column-gap’.  Declaration dropped. [index.css:1:35206]
Unknown property ‘-moz-column-gap’.  Declaration dropped. [index.css:1:35258]
Unknown property ‘-moz-column-gap’.  Declaration dropped. [index.css:1:35304]
Unknown property ‘-moz-column-gap’.  Declaration dropped. [index.css:1:35356]
Unknown property ‘-moz-column-gap’.  Declaration dropped. [index.css:1:35406]
Unknown property ‘-moz-column-gap’.  Declaration dropped. [index.css:1:35458]
Unknown property ‘-moz-column-gap’.  Declaration dropped. [index.css:1:35511]
Unknown property ‘-moz-column-gap’.  Declaration dropped. [index.css:1:35563]
Unknown property ‘-moz-column-gap’.  Declaration dropped. [index.css:1:35613]
Unknown property ‘-moz-column-gap’.  Declaration dropped. [index.css:1:35663]
Unknown property ‘-moz-column-gap’.  Declaration dropped. [index.css:1:177385]
Ruleset ignored due to bad selector. [index.css:1:177854]
XHRGET https://{server}/anythingllm/api/system/logo?theme=default [HTTP/2 204  13ms]
XHRGET https://{server}/anythingllm/api/system/logo?theme=default [HTTP/2 204  33ms]
Error: Failed to fetch logo!
    fetchLogo https://{server}/anythingllm/index.js:67
    promise callback*fetchLogo https://{server}/anythingllm/index.js:67
    c https://{server}/anythingllm/index.js:397
    JL https://{server}/anythingllm/index.js:397
    $o https://{server}/anythingllm/index.js:40
    wi https://{server}/anythingllm/index.js:40
    Bk https://{server}/anythingllm/index.js:40
    A https://{server}/anythingllm/index.js:25
    Z https://{server}/anythingllm/index.js:25
    EventHandlerNonNull* https://{server}/anythingllm/index.js:25
    <anonymous> https://{server}/anythingllm/index.js:25 [index.js:67:45782]
Error: Failed to fetch logo!
    fetchLogo https://{server}/anythingllm/index.js:67
    promise callback*fetchLogo https://{server}/anythingllm/index.js:67
    c https://{server}/anythingllm/index.js:397
    os https://{server}/anythingllm/index.js:397
    $o https://{server}/anythingllm/index.js:40
    wi https://{server}/anythingllm/index.js:40
    Bk https://{server}/anythingllm/index.js:40
    A https://{server}/anythingllm/index.js:25
    Z https://{server}/anythingllm/index.js:25
    EventHandlerNonNull* https://{server}/anythingllm/index.js:25
    <anonymous> https://{server}/anythingllm/index.js:25 [index.js:67:45782]
GET https://{server}/anythingllm/favicon.png [HTTP/2 200  17ms]
GET https://{server}/anythingllm/favicon.png [HTTP/2 200  16ms]

nginx config (yeah, yeah, "and the prize for most uselessly wordy inline documentation goes to..."):

##
## /etc/nginx/conf.d/{project_label}-{server}-{interface}.conf
##
## {project_label} application service definitions for {server}:{interface}.
##

# This is a pre-listener declaration of a local variable holding the
# CN portion of authenticated clients' SSL_CLIENT_S_DN;  it will be
# passed to proxy targets as the Remote_User.  Those targets will be
# configured to trust users as their session $Remote_User, in effect
# offloading authn and authz from target apps to this SSL listener.

map $ssl_client_s_dn $remote_user_cn {
    ~,CN=(?<CN>[^,]+) $CN;
}

# This is a pre-listener declaration of a local variable holding the
# header string(s) for CORS handling;  it will be passed to location
# blocks handing sessions needing CORS (proxying an SSL frontend on
# an externally facing network to a localhost listener is inherently
# Cross-Origin).  This is the first half of CORS handling, the other
# half being to include the stub (containing the if() blocks that
# assemble the CORS header strings) into appropriate location blocks.
# Most Cross-Origin refusals can be seen in a brower's Console panel
# (ie, the bottom panel of the Firefox Developer Tools builtin) via
# a pair of errors:
#
# - failed XHR GET (NS_ERROR_CONNECTION_REFUSED)
# - "Cross-Origin Request Blocked:...(Reason: CORS request did not
#   succeed). Status code: (null)."

map "$http_origin" $cors_headers {
    default '';
    ~^https?://{server}(:[0-9]+)? $http_origin;
    ~^https?://localhost(:[0-9]+)?$ $http_origin;
}

# This is the non-SSL listener.  It exists only to provide a way to
# present users with pre-authentication messages (ie, banner text),
# instructions ("Authentication Required"), and options (a "PIV Card"
# button).

server {

    # Listen on port 80 of the enclave interface as the default
    # server, rooted at /var/www.

    listen {server_ipv4}:80 default_server;
    server_name '{server}';
    root /var/www;

    # The non-SSL listener gets it's own access and error logs.

    access_log /var/log/nginx/www-access.log;
    error_log /var/log/nginx/www-error.log;

    # Common error pages are redefined;  these are just copies of
    # the stock files at /usr/share/nginx/html but with the server
    # make/model/version info removed.

    error_page 404 /404.html;
    location = /404.html { }
    error_page 500 502 503 504 /50x.html;
    location = /50x.html { }

    # If the user asks specifically for / then the server should
    # try to return all files itself, with server-side includes,
    # and autoindexing only for "index.php".  This provides the
    # non-SSL pre-authentication landing page.

    location = / {
        try_files $uri/ =404;
        ssi on;
        autoindex on;
        index index.php;
    }

    # URIs containing a path node starting in '.ht' are silently
    # denied all access.

    location ~ /\.ht {
        deny all;
    }

    # User requests for files in a "/stylesheets" directory (all
    # detached stylesheets should be stored like this) should be
    # fetched by exact reference, returning Not Found otherwise.

    location ~ ^/stylesheets/ {
        try_files $uri =404;
    }

    # Any request URI containing "private" as a directory in the
    # path should be denied all access and given a 404 Not Found
    # instead.  This creates a placeholder directory for content
    # that needs to be under the document root and referenced by
    # other content but should not be exposed to user requests.
    # Examples include common or shared functions called by PHP,
    # CGI, JS, etc, embedded in user-accessible html pages.

    location ~ /private/ {
        deny all;
        return 404;
    }

    # URIs with PHP extension are passed to a local FCGI service
    # for handling with the usual options.

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_pass unix:/run/php-fpm/www.sock;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }

    # Individual NRLGPT applications get a location block here.
    # Each application should have a block to handle clever users
    # making direct-path requests and to make presentation of
    # applications as easy as a list of buttons, each referencing
    # a named "/{label}" location.  All blocks for applications
    # requiring PIV authentication should redirect to the SSL
    # listener where a matching block applies the SSL restrictions
    # and requires checking against the Root CA chain.  These
    # locations should go last because they should only be
    # matched after everything else defined for this server() has
    # been ruled out (regex matches are tried after exact matches
    # and in appearance order).

    location ~ ^/anythingllm {
        return 301 https://$host$request_uri;
    }

}

# This is the SSL listener.  It exists to serve everything
# except the non-SSL landing page, and primarily to reverse
# proxy one or more internally listening {project_label} Workspace
# Manager applications (AnythingLLM, Open-WebUI, etc), enforcing
# PIV authentication and encryption and applying rewriting
# as required.

server {

    # Listen on port 443 of the enclave interface as the
    # default server, rooted at /var/www.

    listen {server ipv4}:443 ssl http2 default_server;
    server_name '{server}';
    root /var/www;

    # Identify with a project-specific cert/key, restrict
    # TLS versions and ciphers, and require the Customer
    # PIV options.

    ssl_certificate /etc/pki/tls/private/nginx_cert.pem;
    ssl_certificate_key /etc/pki/tls/private/nginx_key.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;
# temporarily disabled to allow testing via 'curl -k' 
#    ssl_verify_client on;
    ssl_verify_depth 4;
    ssl_client_certificate /etc/pki/CA/certs/{root_ca_chainfile}.pem;

    # Set the HSTS policy with a one year age, applied to
    # this and all subdomains, with domain preloading.

    add_header Strict-Transport-Security max-age=15768000,includeSubDomains,preload;

    # The SSL listener gets it's own access and error logs.

    access_log /var/log/nginx/www-ssl-access.log;
    error_log /var/log/nginx/www-ssl-error.log;

    # Common error pages are redefined;  these are just copies of
    # the stock files at /usr/share/nginx/html but with the server
    # make/model/version info removed.

    error_page 404 /404.html;
    location = /404.html { }
    error_page 500 502 503 504 /50x.html;
    location = /50x.html { }

    # If the user asks specifically for the document root then
    # redirect them to the non-SSL landing page.

    location = / {
        rewrite ^ http://$host$request_uri? permanent;
    }

    # URIs containing a path node starting in '.ht' are silently
    # denied all access.  By being defined as the first regex
    # match after all exact matches for this server() this block
    # overrides all "{path}/.ht{access,etc}" references generated
    # by anything else in this server().

    location ~ /\.ht {
        deny all;
    }

    # Individual {project_label} applications get a location block here
    # corresponding to the "/{application}" locations in the non-SSL
    # server() block.  Applications needing CORS should include
    # the CORS headers stub that in turn populates CORS headers
    # if the CORS map() at the top of this file has a matching
    # pattern for the current $http_origin;  this is to allow
    # one CORS handler mechanism to support multiple domains
    # where the CORS header itself only supports one.  Proxy
    # handling options and any rewrites -- ie, for applications
    # which can not otherwise be made aware that their document
    # root relative to users is "/{application}", not "/" -- must be
    # defined per application.  These locations are last in this
    # server() because all other location() are either exact
    # matches (eg block order doesn't matter) or regex matches
    # that should never be superceeded by {project_label} applications.

    location ~ ^/anythingllm {
        include 'conf.d/cors_headers.inc';
        proxy_http_version 1.1;
        proxy_set_header Connection Upgrade;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Remote_User $remote_user_cn;
        sub_filter 'href="/' 'href="/anythingllm/';
        sub_filter 'src="/' 'src="/anythingllm/';
        sub_filter_once off;
        location ~ ^/anythingllm/?$ {
            autoindex on;
            index index.js;
            proxy_pass https://localhost:3001;
        }
        location ~ ^/anythingllm(/.+)$ {
            proxy_pass https://localhost:3001$1;
        }
    }

    location ~ ^/llama_cpp {
    }

    location ~ ^/openwebui {
    }

}

conf/cors_headers.inc:

# /etc/nginx/conf.d/cors_headers.inc:  add CORS headers for specific
# origins such that Cross-Origin "remote" resource loading is allowed
# for multiple Origins.  This stub should be 'include'-ed in location
# blocks using Cross-Origin requests.
#
# These conditional header adds reference the custom $cors_headers
# variable, which should be defined by the following map block at the
# top level of configs, and in turn sets the variable only for specific
# origins which are to be allowed to Cross-Origin load. The following
# is an example allowing "localhost" and "{server}", SSL optional for
# both, port optional for the former.
#
#     map "$http_origin" $cors_headers {
#         default '';
#         ~^https?://localhost(:[0-9]+)?$ $http_origin;
#         ~^https?://{server}(:[0-9]+)?$ $http_origin;
#     }

if ($cors_headers != "") {
    add_header 'Access-Control-Allow-Origin' "$cors_headers" always;
    add_header 'Access-Control-Allow-Credentials' 'true' always;
    add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
    add_header 'Access-Control-Allow-Headers' 'Accept, Authorization, Cache-Control, Content-Type, DNT, If-Modified-Since, Keep-Alive, Origin, User-Agent, X-Requested-With' always;
}

if ($request_method = 'OPTIONS') {
    add_header 'Access-Control-Max-Age' 1728000;
    add_header 'Content-Type' 'text/plain charset=UTF-8';
    add_header 'Content-Length' 0;
    return 204;
}
Originally created by @olagarde on GitHub (Jul 30, 2025). Original GitHub issue: https://github.com/Mintplex-Labs/anything-llm/issues/4221 I'm new to the whole llm thing in general and anythingllm in specific. I've implemented many nginx reverse proxies over the years but never really dug into the details that much. This is probably just something dumb I've missed but I'm not seeing much matching this use case and this group seems pretty well versed on this subject, so.... I need to customize SSL client verification around AnythingLLM. I started with https://docs.anythingllm.com/installation-docker/cloud-docker, that assumes either no SSL or wide open CORS depending on viewpoint so I added https://gist.github.com/Stanback/7145487 (just the first I found of many, many identical examples). Anythingllm is being built bare-metal with the goal of developing on it and later curating our own containers. I've also tried the pre-built docker and gotten the same results, thus "probably my dumb". Both bare-metal v1.8.3 and the latest docker container (mintplexlabs/anythingllm as of 31 Jul) produce effectively the same results. The container is as documented at https://docs.anythingllm.com/installation-docker/local-docker, "Run The Image", linux version and runs without errors. The build process is as documented in BARE_METAL.md and produces no errors. SELINUX and firewalld are off. The tab icon and title are loaded and displayed correctly but there's no page content, just like most "blank page" or "white page" posts on this forum but unlike those cases there's no Cross-Origin errors, bad gateways, or refused/blocked transactions. There are two instances per reload of null returns for the logo?theme=default though. XHR GETs for > https://{server}/{proxy prefix}/api/system/logo?theme=default are correctly proxied/rewritten to > https://localhost:3001/api/system/logo?theme=default but then return 204 for the bare-metal build and 404 for the docker container. Checking that result with 'curl -ski {url}' replicates replies for both pre- and post-proxied URLs, both on the server host and on another Customer box one hop out on the enclave-facing network looking at the server host. Other than the usual "unknown property '-moz-...'" from the css there's no other errors, either in the syslogs or the browser console. As @timothycarambat has noted this is probably a red herring, but there's no other indication of failure; the JS launches appear to all succeed (see below) and there are no additional requests or packets in either direction, for either baremetal or containerized versions. Any ideas? Redactions: - REDACTED (duh) - {server}: the server host running the nginx reverse proxy and anythingllm server and collector - {project_label}: the Customer-internal label for "this stuff" - {server_ipv4}: the ipv4 addr of the server in the Customer's internal network Server: ``` Rocky Linux 8.10 updated yesterday AnythingLLM 1.8.3 nginx 1.14.1-9 nodejs 18.20.8-1 npm 10.8.2-1.18.20.8.1 yarn 1.22.22-9 ``` Client: ``` OSX 15.5 (24F74 firefox 138.0.1 ``` server/.env: ``` LLM_PROVIDER='ollama' EMBEDDING_MODEL_PREF='nomic-embed-text:latest' OLLAMA_BASE_PATH='http://127.0.0.1:11434' OLLAMA_MODEL_PREF='llama3' OLLAMA_MODEL_TOKEN_LIMIT='4096' EMBEDDING_ENGINE='ollama' EMBEDDING_BASE_PATH='http://127.0.0.1:11434' EMBEDDING_MODEL_MAX_CHUNK_LENGTH='8192' VECTOR_DB='lancedb' WHISPER_PROVIDER='local' TTS_PROVIDER='native' STORAGE_DIR='/var/{project_label}/anythingllm/serverdata' SERVER_PORT='3001' SIG_KEY='REDACTED' SIG_SALT='REDACTED' PASSWORDMINCHAR='15' PASSWORDMAXCHAR='15' PASSWORDLOWERCASE='2' PASSWORDUPPERCASE='2' PASSWORDNUMERIC='2' PASSWORDSYMBOL='2' PASSWORDREQUIREMENTS='4' ENABLE_HTTPS='true' HTTPS_CERT_PATH='/etc/pki/tls/private/anythingllm_cert.pem' HTTPS_KEY_PATH='/etc/pki/tls/private/anythingllm_key.pem' SIMPLE_SSO_ENABLED='1' TARGET_OCR_LANG='eng,deu,ita,spa,fra,por,rus,nld,tur,hun,pol,ita,spa,fra,por,rus,nld,tur,hun,pol' ``` collector/.env: ``` SERVER_PORT='8888' STORAGE_DIR='/var/{project_label}/anythingllm/collectordata' NODE_ENV='production' ``` frontend/.env: ``` VITE_API_BASE='https://{server}/anythingllm/api' ``` Firefox console: ```GET https://{server}/anythingllm [HTTP/2 200 96ms] GET https://{server}/anythingllm/index.js [HTTP/2 200 274ms] GET https://{server}/anythingllm/index.css [HTTP/2 200 112ms] Error in parsing value for ‘-webkit-text-size-adjust’. Declaration dropped. [index.css:1:11397] Unknown property ‘-moz-column-gap’. Declaration dropped. [index.css:1:34847] Unknown property ‘-moz-column-gap’. Declaration dropped. [index.css:1:34900] Unknown property ‘-moz-column-gap’. Declaration dropped. [index.css:1:34953] Unknown property ‘-moz-column-gap’. Declaration dropped. [index.css:1:35004] Unknown property ‘-moz-column-gap’. Declaration dropped. [index.css:1:35050] Unknown property ‘-moz-column-gap’. Declaration dropped. [index.css:1:35101] Unknown property ‘-moz-column-gap’. Declaration dropped. [index.css:1:35153] Unknown property ‘-moz-column-gap’. Declaration dropped. [index.css:1:35206] Unknown property ‘-moz-column-gap’. Declaration dropped. [index.css:1:35258] Unknown property ‘-moz-column-gap’. Declaration dropped. [index.css:1:35304] Unknown property ‘-moz-column-gap’. Declaration dropped. [index.css:1:35356] Unknown property ‘-moz-column-gap’. Declaration dropped. [index.css:1:35406] Unknown property ‘-moz-column-gap’. Declaration dropped. [index.css:1:35458] Unknown property ‘-moz-column-gap’. Declaration dropped. [index.css:1:35511] Unknown property ‘-moz-column-gap’. Declaration dropped. [index.css:1:35563] Unknown property ‘-moz-column-gap’. Declaration dropped. [index.css:1:35613] Unknown property ‘-moz-column-gap’. Declaration dropped. [index.css:1:35663] Unknown property ‘-moz-column-gap’. Declaration dropped. [index.css:1:177385] Ruleset ignored due to bad selector. [index.css:1:177854] XHRGET https://{server}/anythingllm/api/system/logo?theme=default [HTTP/2 204 13ms] XHRGET https://{server}/anythingllm/api/system/logo?theme=default [HTTP/2 204 33ms] Error: Failed to fetch logo! fetchLogo https://{server}/anythingllm/index.js:67 promise callback*fetchLogo https://{server}/anythingllm/index.js:67 c https://{server}/anythingllm/index.js:397 JL https://{server}/anythingllm/index.js:397 $o https://{server}/anythingllm/index.js:40 wi https://{server}/anythingllm/index.js:40 Bk https://{server}/anythingllm/index.js:40 A https://{server}/anythingllm/index.js:25 Z https://{server}/anythingllm/index.js:25 EventHandlerNonNull* https://{server}/anythingllm/index.js:25 <anonymous> https://{server}/anythingllm/index.js:25 [index.js:67:45782] Error: Failed to fetch logo! fetchLogo https://{server}/anythingllm/index.js:67 promise callback*fetchLogo https://{server}/anythingllm/index.js:67 c https://{server}/anythingllm/index.js:397 os https://{server}/anythingllm/index.js:397 $o https://{server}/anythingllm/index.js:40 wi https://{server}/anythingllm/index.js:40 Bk https://{server}/anythingllm/index.js:40 A https://{server}/anythingllm/index.js:25 Z https://{server}/anythingllm/index.js:25 EventHandlerNonNull* https://{server}/anythingllm/index.js:25 <anonymous> https://{server}/anythingllm/index.js:25 [index.js:67:45782] GET https://{server}/anythingllm/favicon.png [HTTP/2 200 17ms] GET https://{server}/anythingllm/favicon.png [HTTP/2 200 16ms] ``` nginx config (yeah, yeah, "and the prize for most uselessly wordy inline documentation goes to..."): ``` ## ## /etc/nginx/conf.d/{project_label}-{server}-{interface}.conf ## ## {project_label} application service definitions for {server}:{interface}. ## # This is a pre-listener declaration of a local variable holding the # CN portion of authenticated clients' SSL_CLIENT_S_DN; it will be # passed to proxy targets as the Remote_User. Those targets will be # configured to trust users as their session $Remote_User, in effect # offloading authn and authz from target apps to this SSL listener. map $ssl_client_s_dn $remote_user_cn { ~,CN=(?<CN>[^,]+) $CN; } # This is a pre-listener declaration of a local variable holding the # header string(s) for CORS handling; it will be passed to location # blocks handing sessions needing CORS (proxying an SSL frontend on # an externally facing network to a localhost listener is inherently # Cross-Origin). This is the first half of CORS handling, the other # half being to include the stub (containing the if() blocks that # assemble the CORS header strings) into appropriate location blocks. # Most Cross-Origin refusals can be seen in a brower's Console panel # (ie, the bottom panel of the Firefox Developer Tools builtin) via # a pair of errors: # # - failed XHR GET (NS_ERROR_CONNECTION_REFUSED) # - "Cross-Origin Request Blocked:...(Reason: CORS request did not # succeed). Status code: (null)." map "$http_origin" $cors_headers { default ''; ~^https?://{server}(:[0-9]+)? $http_origin; ~^https?://localhost(:[0-9]+)?$ $http_origin; } # This is the non-SSL listener. It exists only to provide a way to # present users with pre-authentication messages (ie, banner text), # instructions ("Authentication Required"), and options (a "PIV Card" # button). server { # Listen on port 80 of the enclave interface as the default # server, rooted at /var/www. listen {server_ipv4}:80 default_server; server_name '{server}'; root /var/www; # The non-SSL listener gets it's own access and error logs. access_log /var/log/nginx/www-access.log; error_log /var/log/nginx/www-error.log; # Common error pages are redefined; these are just copies of # the stock files at /usr/share/nginx/html but with the server # make/model/version info removed. error_page 404 /404.html; location = /404.html { } error_page 500 502 503 504 /50x.html; location = /50x.html { } # If the user asks specifically for / then the server should # try to return all files itself, with server-side includes, # and autoindexing only for "index.php". This provides the # non-SSL pre-authentication landing page. location = / { try_files $uri/ =404; ssi on; autoindex on; index index.php; } # URIs containing a path node starting in '.ht' are silently # denied all access. location ~ /\.ht { deny all; } # User requests for files in a "/stylesheets" directory (all # detached stylesheets should be stored like this) should be # fetched by exact reference, returning Not Found otherwise. location ~ ^/stylesheets/ { try_files $uri =404; } # Any request URI containing "private" as a directory in the # path should be denied all access and given a 404 Not Found # instead. This creates a placeholder directory for content # that needs to be under the document root and referenced by # other content but should not be exposed to user requests. # Examples include common or shared functions called by PHP, # CGI, JS, etc, embedded in user-accessible html pages. location ~ /private/ { deny all; return 404; } # URIs with PHP extension are passed to a local FCGI service # for handling with the usual options. location ~ \.php$ { try_files $uri =404; fastcgi_pass unix:/run/php-fpm/www.sock; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; } # Individual NRLGPT applications get a location block here. # Each application should have a block to handle clever users # making direct-path requests and to make presentation of # applications as easy as a list of buttons, each referencing # a named "/{label}" location. All blocks for applications # requiring PIV authentication should redirect to the SSL # listener where a matching block applies the SSL restrictions # and requires checking against the Root CA chain. These # locations should go last because they should only be # matched after everything else defined for this server() has # been ruled out (regex matches are tried after exact matches # and in appearance order). location ~ ^/anythingllm { return 301 https://$host$request_uri; } } # This is the SSL listener. It exists to serve everything # except the non-SSL landing page, and primarily to reverse # proxy one or more internally listening {project_label} Workspace # Manager applications (AnythingLLM, Open-WebUI, etc), enforcing # PIV authentication and encryption and applying rewriting # as required. server { # Listen on port 443 of the enclave interface as the # default server, rooted at /var/www. listen {server ipv4}:443 ssl http2 default_server; server_name '{server}'; root /var/www; # Identify with a project-specific cert/key, restrict # TLS versions and ciphers, and require the Customer # PIV options. ssl_certificate /etc/pki/tls/private/nginx_cert.pem; ssl_certificate_key /etc/pki/tls/private/nginx_key.pem; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on; # temporarily disabled to allow testing via 'curl -k' # ssl_verify_client on; ssl_verify_depth 4; ssl_client_certificate /etc/pki/CA/certs/{root_ca_chainfile}.pem; # Set the HSTS policy with a one year age, applied to # this and all subdomains, with domain preloading. add_header Strict-Transport-Security max-age=15768000,includeSubDomains,preload; # The SSL listener gets it's own access and error logs. access_log /var/log/nginx/www-ssl-access.log; error_log /var/log/nginx/www-ssl-error.log; # Common error pages are redefined; these are just copies of # the stock files at /usr/share/nginx/html but with the server # make/model/version info removed. error_page 404 /404.html; location = /404.html { } error_page 500 502 503 504 /50x.html; location = /50x.html { } # If the user asks specifically for the document root then # redirect them to the non-SSL landing page. location = / { rewrite ^ http://$host$request_uri? permanent; } # URIs containing a path node starting in '.ht' are silently # denied all access. By being defined as the first regex # match after all exact matches for this server() this block # overrides all "{path}/.ht{access,etc}" references generated # by anything else in this server(). location ~ /\.ht { deny all; } # Individual {project_label} applications get a location block here # corresponding to the "/{application}" locations in the non-SSL # server() block. Applications needing CORS should include # the CORS headers stub that in turn populates CORS headers # if the CORS map() at the top of this file has a matching # pattern for the current $http_origin; this is to allow # one CORS handler mechanism to support multiple domains # where the CORS header itself only supports one. Proxy # handling options and any rewrites -- ie, for applications # which can not otherwise be made aware that their document # root relative to users is "/{application}", not "/" -- must be # defined per application. These locations are last in this # server() because all other location() are either exact # matches (eg block order doesn't matter) or regex matches # that should never be superceeded by {project_label} applications. location ~ ^/anythingllm { include 'conf.d/cors_headers.inc'; proxy_http_version 1.1; proxy_set_header Connection Upgrade; proxy_set_header Upgrade $http_upgrade; proxy_set_header Remote_User $remote_user_cn; sub_filter 'href="/' 'href="/anythingllm/'; sub_filter 'src="/' 'src="/anythingllm/'; sub_filter_once off; location ~ ^/anythingllm/?$ { autoindex on; index index.js; proxy_pass https://localhost:3001; } location ~ ^/anythingllm(/.+)$ { proxy_pass https://localhost:3001$1; } } location ~ ^/llama_cpp { } location ~ ^/openwebui { } } ``` conf/cors_headers.inc: ``` # /etc/nginx/conf.d/cors_headers.inc: add CORS headers for specific # origins such that Cross-Origin "remote" resource loading is allowed # for multiple Origins. This stub should be 'include'-ed in location # blocks using Cross-Origin requests. # # These conditional header adds reference the custom $cors_headers # variable, which should be defined by the following map block at the # top level of configs, and in turn sets the variable only for specific # origins which are to be allowed to Cross-Origin load. The following # is an example allowing "localhost" and "{server}", SSL optional for # both, port optional for the former. # # map "$http_origin" $cors_headers { # default ''; # ~^https?://localhost(:[0-9]+)?$ $http_origin; # ~^https?://{server}(:[0-9]+)?$ $http_origin; # } if ($cors_headers != "") { add_header 'Access-Control-Allow-Origin' "$cors_headers" always; add_header 'Access-Control-Allow-Credentials' 'true' always; add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always; add_header 'Access-Control-Allow-Headers' 'Accept, Authorization, Cache-Control, Content-Type, DNT, If-Modified-Since, Keep-Alive, Origin, User-Agent, X-Requested-With' always; } if ($request_method = 'OPTIONS') { add_header 'Access-Control-Max-Age' 1728000; add_header 'Content-Type' 'text/plain charset=UTF-8'; add_header 'Content-Length' 0; return 204; } ```
yindo closed this issue 2026-02-22 18:30:46 -05:00
Author
Owner

@timothycarambat commented on GitHub (Jul 30, 2025):

Closing this because this is a config/deployment issue and not a real "bug". Also at the top of BARE_METAL it says

Warning

This method of deployment is not supported by the core-team and is to be used as a reference for your deployment.
You are fully responsible for securing your deployment and data in this mode.
Any issues experienced from bare-metal or non-containerized deployments will be not answered or supported.

That being said, this is a very complex deployment with a ton of information. There are several things worth highlight though to simplify this process greatly.

  1. You have SSL for localhost and NGINX. Just use a reverse proxy. I know you are running everything under and additional path /anythingllm - but you can do the same reverse proxy here. You can keep the SSL config and remove the HTTPS_CERT stuff from the ENVs. Just run AnythingLLM in http, but use a reverse proxy with SSL to point to that local endpoint. Then, on firewall, just block free access to port 3001 and rewrite 80 -> 443.
server {
   # Enable websocket connections for agent protocol.
   location ~* ^/api/agent-invocation/(.*) {
      proxy_pass http://0.0.0.0:3001;
      proxy_http_version 1.1;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "Upgrade";
   }

   listen 80;
   server_name [insert FQDN here];
   location / {
      # Prevent timeouts on long-running requests.
      proxy_connect_timeout       605;
      proxy_send_timeout          605;
      proxy_read_timeout          605;
      send_timeout                605;
      keepalive_timeout           605;

      # Enable readable HTTP Streaming for LLM streamed responses
      proxy_buffering off; 
      proxy_cache off;

      # Proxy your locally running service
      proxy_pass  http://0.0.0.0:3001;
    }
}
  1. STORAGE_DIR stuff looks okay, but it is using a top level /var mount so just make sure that folder is read/write enabled so the process can access it.

  2. Returning 204 on the image is not the end of the world and likely is not causing your white screen - something else is (likely CORS?). There is handling in the frontend to fallback to a default image if the image is not found - the 204 is a symptom, but not the problem.

Open the Chrome inspector and see in the Network tab if all your requests are being dropped/lost/etc. That will likely reveal the true error.

@timothycarambat commented on GitHub (Jul 30, 2025): Closing this because this is a config/deployment issue and not a real "bug". Also at the top of BARE_METAL it says > [!WARNING] > This method of deployment is **not supported** by the core-team and is to be used as a reference for your deployment. > You are fully responsible for securing your deployment and data in this mode. > **Any issues** experienced from bare-metal or non-containerized deployments will be **not** answered or supported. That being said, this is a very complex deployment with a ton of information. There are several things worth highlight though to simplify this process greatly. 1. You have SSL for localhost **and** NGINX. Just use a reverse proxy. I know you are running everything under and additional path `/anythingllm` - but you can do the same reverse proxy here. You can keep the SSL config and remove the `HTTPS_CERT` stuff from the ENVs. Just run AnythingLLM in http, but use a reverse proxy with SSL to point to that local endpoint. Then, on firewall, just block free access to port `3001` and rewrite 80 -> 443. ``` server { # Enable websocket connections for agent protocol. location ~* ^/api/agent-invocation/(.*) { proxy_pass http://0.0.0.0:3001; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "Upgrade"; } listen 80; server_name [insert FQDN here]; location / { # Prevent timeouts on long-running requests. proxy_connect_timeout 605; proxy_send_timeout 605; proxy_read_timeout 605; send_timeout 605; keepalive_timeout 605; # Enable readable HTTP Streaming for LLM streamed responses proxy_buffering off; proxy_cache off; # Proxy your locally running service proxy_pass http://0.0.0.0:3001; } } ``` 2. STORAGE_DIR stuff looks okay, but it is using a top level `/var` mount so just make sure that folder is read/write enabled so the process can access it. 3. Returning 204 on the image is not the end of the world and likely is not causing your white screen - something else is (likely CORS?). There is handling in the frontend to fallback to a default image if the image is not found - the 204 is a symptom, but not the problem. Open the Chrome inspector and see in the `Network` tab if all your requests are being dropped/lost/etc. That will likely reveal the true error.
Author
Owner

@olagarde commented on GitHub (Jul 30, 2025):

Sorry to re-post but I can't get any site to accept this question unless I can prove fault with anythingllm itself, you're the only one who's responded at all.

Can nginx, proxying, and the browser be a factor when they're bypassed entirely?

$ lsof -ni :3001
COMMAND   PID        USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
node    47491 anythingllm   19u  IPv6 220051      0t0  TCP *:origo-native (LISTEN)

$  curl -ski 'https://localhost:3001/api/system/logo?theme=default'
HTTP/1.1 204 No Content
X-Powered-By: Express
Vary: Origin
ETag: W/"a-bAsFyilMr4Ra1hIU5PyoyFRunpI"
Date: Thu, 31 Jul 2025 00:21:51 GMT
Connection: keep-alive
Keep-Alive: timeout=5

$ echo $?
0
@olagarde commented on GitHub (Jul 30, 2025): Sorry to re-post but I can't get any site to accept this question unless I can prove fault with anythingllm itself, you're the only one who's responded at all. Can nginx, proxying, and the browser be a factor when they're bypassed entirely? ``` $ lsof -ni :3001 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME node 47491 anythingllm 19u IPv6 220051 0t0 TCP *:origo-native (LISTEN) $ curl -ski 'https://localhost:3001/api/system/logo?theme=default' HTTP/1.1 204 No Content X-Powered-By: Express Vary: Origin ETag: W/"a-bAsFyilMr4Ra1hIU5PyoyFRunpI" Date: Thu, 31 Jul 2025 00:21:51 GMT Connection: keep-alive Keep-Alive: timeout=5 $ echo $? 0 ```
Author
Owner

@timothycarambat commented on GitHub (Jul 30, 2025):

When you load the white page in the browser, what does the Chrome/Browser Network inspector show?

@timothycarambat commented on GitHub (Jul 30, 2025): When you load the white page in the browser, what does the Chrome/Browser Network inspector show?
Author
Owner

@olagarde commented on GitHub (Jul 30, 2025):

Chrome at developer tools network tab, no filters, all records, after a page refresh of "https://{server}/anythingllm":

anythingllm          | 200  | document    | Other                                 | 1.9 kB   | 20 ms
index.js             | 304  | script      | anythingllm:22                        | 0.3 kB   | 18 ms
index.css            | 304  | stylesheet  | anythingllm:23                        | 0.2 kB   | 17 ms
local-storage.js     | 200  | script      | content-script-utils.js:18            | 2.3 kB   | 4 ms
fte-utils.js         | 200  | script      | EmbeddedPDFTouchPointCoachMark.js:18  | 3.8 kB   | 3 ms
express-fte.js       | 200  | script      | ShowOneChild.js:18                    | 7.1 kB   | 12 ms
express-fte-utils.js | 200  | script      | express-fte.js:18                     | 1.7 kB   | 9 ms
logo?theme=light     | 204  | fetch       | index.js:67                           | 0.2 kB   | 51 ms
logo?theme=light     | 204  | fetch       | index.js:67                           | 0.2 kB   | 56 ms
favicon.png          | 200  | png         | Other                                 | 3.9 kB   | 19 ms
sidePanelUtil.js     | 200  | script      | GenAIWebpageEligibilityService.js:18  | 1.8 kB   | 19 ms
readability.js       | 200  | script      | sidePanelUtil.js:18                   | 94.0 kB  | 3 ms

and the console reports

Error: Failed to fetch logo!
    at index.js:67:45727
    at async Object.fetchLogo (index.js:67:45508)
    at async c (index.js:397:47678)

followed several minutes later by

Uncaught (in promise) Error: A listener indicated an asynchronous response by returning true, but the message channel closed before a response was received

The latter doesn't show up incognito and doesn't have an associated syslog record so I'm guessing it's just the cross-origin requests plus Chrome Extensions being overly protective.

The server-side syslogs report this in access and no errors, which matches the non-script-call records above, so I'm assuming this is kosher:

[30/Jul/2025:22:34:13 -0400] "GET /anythingllm HTTP/2.0" 200 1750 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36"
[30/Jul/2025:22:34:13 -0400] "GET /anythingllm/index.js HTTP/2.0" 304 0 "https://nrlgpt.cmf.nrl.navy.mil/anythingllm" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36"
[30/Jul/2025:22:34:13 -0400] "GET /anythingllm/index.css HTTP/2.0" 304 0 "https://nrlgpt.cmf.nrl.navy.mil/anythingllm" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36"
[30/Jul/2025:22:34:13 -0400] "GET /anythingllm/api/system/logo?theme=light HTTP/2.0" 204 0 "https://nrlgpt.cmf.nrl.navy.mil/anythingllm" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36"
[30/Jul/2025:22:34:13 -0400] "GET /anythingllm/api/system/logo?theme=light HTTP/2.0" 204 0 "https://nrlgpt.cmf.nrl.navy.mil/anythingllm" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36"
[30/Jul/2025:22:34:13 -0400] "GET /anythingllm/favicon.png HTTP/2.0" 200 3624 "https://nrlgpt.cmf.nrl.navy.mil/anythingllm" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36"
@olagarde commented on GitHub (Jul 30, 2025): Chrome at developer tools network tab, no filters, all records, after a page refresh of "https://{server}/anythingllm": ``` anythingllm | 200 | document | Other | 1.9 kB | 20 ms index.js | 304 | script | anythingllm:22 | 0.3 kB | 18 ms index.css | 304 | stylesheet | anythingllm:23 | 0.2 kB | 17 ms local-storage.js | 200 | script | content-script-utils.js:18 | 2.3 kB | 4 ms fte-utils.js | 200 | script | EmbeddedPDFTouchPointCoachMark.js:18 | 3.8 kB | 3 ms express-fte.js | 200 | script | ShowOneChild.js:18 | 7.1 kB | 12 ms express-fte-utils.js | 200 | script | express-fte.js:18 | 1.7 kB | 9 ms logo?theme=light | 204 | fetch | index.js:67 | 0.2 kB | 51 ms logo?theme=light | 204 | fetch | index.js:67 | 0.2 kB | 56 ms favicon.png | 200 | png | Other | 3.9 kB | 19 ms sidePanelUtil.js | 200 | script | GenAIWebpageEligibilityService.js:18 | 1.8 kB | 19 ms readability.js | 200 | script | sidePanelUtil.js:18 | 94.0 kB | 3 ms ``` and the console reports ``` Error: Failed to fetch logo! at index.js:67:45727 at async Object.fetchLogo (index.js:67:45508) at async c (index.js:397:47678) ``` followed several minutes later by ``` Uncaught (in promise) Error: A listener indicated an asynchronous response by returning true, but the message channel closed before a response was received ``` The latter doesn't show up incognito and doesn't have an associated syslog record so I'm guessing it's just the cross-origin requests plus Chrome Extensions being overly protective. The server-side syslogs report this in access and no errors, which matches the non-script-call records above, so I'm assuming this is kosher: ``` [30/Jul/2025:22:34:13 -0400] "GET /anythingllm HTTP/2.0" 200 1750 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36" [30/Jul/2025:22:34:13 -0400] "GET /anythingllm/index.js HTTP/2.0" 304 0 "https://nrlgpt.cmf.nrl.navy.mil/anythingllm" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36" [30/Jul/2025:22:34:13 -0400] "GET /anythingllm/index.css HTTP/2.0" 304 0 "https://nrlgpt.cmf.nrl.navy.mil/anythingllm" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36" [30/Jul/2025:22:34:13 -0400] "GET /anythingllm/api/system/logo?theme=light HTTP/2.0" 204 0 "https://nrlgpt.cmf.nrl.navy.mil/anythingllm" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36" [30/Jul/2025:22:34:13 -0400] "GET /anythingllm/api/system/logo?theme=light HTTP/2.0" 204 0 "https://nrlgpt.cmf.nrl.navy.mil/anythingllm" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36" [30/Jul/2025:22:34:13 -0400] "GET /anythingllm/favicon.png HTTP/2.0" 200 3624 "https://nrlgpt.cmf.nrl.navy.mil/anythingllm" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36" ```
Author
Owner

@olagarde commented on GitHub (Jul 31, 2025):

Adding a note here in case someone else runs into the same issue...

OP updated: latest docker tried alongside bare-metal, same results (ie, only the 'logo?theme=default' fails), there are no refused or blocked transactions and no other failures of any kind. Non-SSL worls but the whole point here is PIV CERT auth via ssl_client_verify, so non-SSL results only point to nginx, which we already knew.

@olagarde commented on GitHub (Jul 31, 2025): Adding a note here in case someone else runs into the same issue... OP updated: latest docker tried alongside bare-metal, same results (ie, only the 'logo?theme=default' fails), there are no refused or blocked transactions and no other failures of any kind. Non-SSL worls but the whole point here is PIV CERT auth via ssl_client_verify, so non-SSL results only point to nginx, which we already knew.
Author
Owner

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

I am also seeing this issue. I am investigating but I think the fact is that the frontend is built to serve under the root path. So subpaths will not work. See https://github.com/Mintplex-Labs/anything-llm/blob/master/frontend/.env.example

This is my browser error from Console

Error: Failed to fetch logo!
    fetchLogo https://localhost/anything-llm/index.js:67
    promise callback*fetchLogo https://localhost/anything-llm/index.js:67
    c https://localhost/anything-llm/index.js:419
    ij https://localhost/anything-llm/index.js:419
    Wl https://localhost/anything-llm/index.js:40
    wi https://localhost/anything-llm/index.js:40
    k https://localhost/anything-llm/index.js:40
    A https://localhost/anything-llm/index.js:25
    Z https://localhost/anything-llm/index.js:25
    EventHandlerNonNull* https://localhost/anything-llm/index.js:25
    <anonymous> https://localhost/anything-llm/index.js:25

This is my network tab in browser

Image

This is my nginx log output

nginx                  | 172.19.0.1 - - [22/Sep/2025:10:29:10 +0000] "GET /anything-llm/ HTTP/1.1" 200 1772 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0"
nginx                  | 172.19.0.1 - - [22/Sep/2025:10:29:11 +0000] "GET /anything-llm/index.css HTTP/1.1" 200 286914 "https://localhost/anything-llm/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0"
nginx                  | 172.19.0.1 - - [22/Sep/2025:10:29:11 +0000] "GET /anything-llm/index.js HTTP/1.1" 200 1535464 "https://localhost/anything-llm/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0"
nginx                  | 172.19.0.1 - - [22/Sep/2025:10:29:11 +0000] "GET /api/system/logo?theme=default HTTP/1.1" 204 0 "https://localhost/anything-llm/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0"
nginx                  | 172.19.0.1 - - [22/Sep/2025:10:29:11 +0000] "GET /api/system/logo?theme=default HTTP/1.1" 204 0 "https://localhost/anything-llm/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0"
nginx                  | 172.19.0.1 - - [22/Sep/2025:10:29:11 +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"
nginx                  | 172.19.0.1 - - [22/Sep/2025:10:29:11 +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"

My nginx

http {
    # Define a map to handle WebSocket upgrades.
    map $http_upgrade $connection_upgrade {
        default upgrade;
        ''      close;
    }

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

        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 "nosniff";


        # Catch-all for API calls that the frontend JS might make to the wrong path.
        location /api/ {
            proxy_pass http://anything-llm:3001;
            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;
        }

        location /anything-llm/ {
            # Disable caching between Nginx and the backend.
            proxy_set_header If-Modified-Since "";
            proxy_set_header If-None-Match "";

            sub_filter_types *;

            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/"; 
            sub_filter '"/api/' '"/anything-llm/api/';
            sub_filter '`/api/' '`/anything-llm/api/'; 

            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;
        }
    }
}
@JMuff22 commented on GitHub (Sep 22, 2025): I am also seeing this issue. I am investigating but I think the fact is that the frontend is built to serve under the root path. So subpaths will not work. See https://github.com/Mintplex-Labs/anything-llm/blob/master/frontend/.env.example This is my browser error from Console ``` Error: Failed to fetch logo! fetchLogo https://localhost/anything-llm/index.js:67 promise callback*fetchLogo https://localhost/anything-llm/index.js:67 c https://localhost/anything-llm/index.js:419 ij https://localhost/anything-llm/index.js:419 Wl https://localhost/anything-llm/index.js:40 wi https://localhost/anything-llm/index.js:40 k https://localhost/anything-llm/index.js:40 A https://localhost/anything-llm/index.js:25 Z https://localhost/anything-llm/index.js:25 EventHandlerNonNull* https://localhost/anything-llm/index.js:25 <anonymous> https://localhost/anything-llm/index.js:25 ``` This is my network tab in browser <img width="2548" height="215" alt="Image" src="https://github.com/user-attachments/assets/8332b8fe-fbea-4e94-872a-004d1dc17e4f" /> This is my nginx log output ```sh nginx | 172.19.0.1 - - [22/Sep/2025:10:29:10 +0000] "GET /anything-llm/ HTTP/1.1" 200 1772 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0" nginx | 172.19.0.1 - - [22/Sep/2025:10:29:11 +0000] "GET /anything-llm/index.css HTTP/1.1" 200 286914 "https://localhost/anything-llm/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0" nginx | 172.19.0.1 - - [22/Sep/2025:10:29:11 +0000] "GET /anything-llm/index.js HTTP/1.1" 200 1535464 "https://localhost/anything-llm/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0" nginx | 172.19.0.1 - - [22/Sep/2025:10:29:11 +0000] "GET /api/system/logo?theme=default HTTP/1.1" 204 0 "https://localhost/anything-llm/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0" nginx | 172.19.0.1 - - [22/Sep/2025:10:29:11 +0000] "GET /api/system/logo?theme=default HTTP/1.1" 204 0 "https://localhost/anything-llm/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0" nginx | 172.19.0.1 - - [22/Sep/2025:10:29:11 +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" nginx | 172.19.0.1 - - [22/Sep/2025:10:29:11 +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" ``` My nginx ``` http { # Define a map to handle WebSocket upgrades. map $http_upgrade $connection_upgrade { default upgrade; '' close; } server { listen 443 ssl; listen [::]:443 ssl; server_name localhost; 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 "nosniff"; # Catch-all for API calls that the frontend JS might make to the wrong path. location /api/ { proxy_pass http://anything-llm:3001; 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; } location /anything-llm/ { # Disable caching between Nginx and the backend. proxy_set_header If-Modified-Since ""; proxy_set_header If-None-Match ""; sub_filter_types *; 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/"; sub_filter '"/api/' '"/anything-llm/api/'; sub_filter '`/api/' '`/anything-llm/api/'; 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; } } } ```
yindo changed title from help with white screen and /api/system/logo?theme=default returning 204 to [GH-ISSUE #4221] help with white screen and /api/system/logo?theme=default returning 204 2026-06-05 14:47:57 -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#2685