0

I have a maintenance config I created with nginx which I simply swap for my prod one. It is meant to call an index.html which is based on an Angular SPA and route to the /maintenance page created within the application.

If I use try_files /index.html $uri $uri/;, I receive mime type errors in my browser's console (though in the network tab I'm getting 200 responses for the exact same files).

If I swap try_files /index.html $uri $uri/; with try_files $uri $uri/ /index.html ; , I get a too many indirect error and its equivalent within the nginx logs.

Maintenance Config file

user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

events {
    worker_connections 768;
    # multi_accept on;
}

http {

    ##
    # Basic Settings
    ##
    add_header Access-Control-Allow-Origin *;

    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;
    # server_tokens off;

    # server_names_hash_bucket_size 64;
    # server_name_in_redirect off;

    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    ##
    # SSL Settings
    ##

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;

    ##
    # Logging Settings
    ##

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

    ##
    # Gzip Settings
    ##

    gzip on;

    ##
    #Original IP Forwarding
    ##
    proxy_set_header X-Forwarded-For $remote_addr;

    ##
    # Virtual Host Configs
    ##
    server {
            listen       80 default_server;
            listen       [::]:80 default_server;
            server_name  _;
            return 301   https://$host$request_uri;
    }

    server{
        listen 443 ssl;
        server_name mysite.com;
        root /etc/mysite/enabled-sites/ngbuild/browser; 

        location / {
            if ($uri != /maintenance) {
                return 302 https://$host/maintenance; 
            }
            try_files /index.html $uri $uri/;
        }

    }
    
}

Additionally, my prod config uses try_files $uri $uri/ /index.html; for its locations which serves the production application just fine. If I swap that to try_files /index.html $uri $uri/; I then also get mime type errors in production.

1 Answer 1

0

Did you read the try_files directive documentation at all? The last argument in try_files is treated completely differently from the others:

If none of the files were found, an internal redirect to the uri specified in the last parameter is made.
...
The last parameter can also point to a named location ... Starting from version 0.7.51, the last parameter can also be a code.

An internal redirect to the uri specified in the last parameter is made is the key point here.

So what happens with your configuration? Using the try_files /index.html $uri $uri/; directive, you are causing all your asset requests - most importantly the /main.<build_id>.js request - to return the same index.html file. This response includes the Content-Type HTTP header set to text/html instead of the expected text/javascript. Of course, your browser will complain about the incorrect MIME type, but the main issue here is that your JavaScript file is not being retrieved at all.

Now, using the try_files $uri $uri/ /index.html; directive more interesting things happen. Let's break it down:

  1. Assume you receive a root request to your application. Since the requested URI is not /maintenance, a 302 redirect to /maintenance is issued.
  2. Next, a /maintenance request is received. The most suitable location, which is the only location / { ... } block, is chosen to handle it. At this point, the $uri internal variable is equal to /maintenance, so no additional 302 redirect is issued this time. However, because maintenance is neither a physical file nor a directory, an internal redirect to /index.html occurs.
  3. Now, nginx determines the most suitable location again (and, once again, it's the only location / { ... } block available). However, the $uri internal variable has now changed to /index.html. What happens next? Another 302 redirect is issued.

How this can be solved? Use the $request_uri variable instead, as its value does not change during internal redirects. Additionally, define two separate location blocks to ensure that your assets are loaded correctly:

location / {
    # all the asset requests will be handled here
    try_files $uri /index.html;
}
location = /index.html {
    if ($request_uri != /maintenance) {
        return 302 https://$host/maintenance; 
    }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.