Nginx – Fixing Incorrect MIME Type When Reverse Proxying Node.js App

nginxnode.js

I'm self-hosting a jekyll site with jekyll-admin for editing.

jekyll-admin adds a nodejs based admin panel. I want to be able to access this over the internet via a nginx reverse-proxy.

  • jekyll 4.0.0
  • jekyll-admin 0.9.6
  • node 10.16.3
  • nginx 1.17.4

This configuration works :

server {
     listen 80;

     server_name www.example.com;
     root /home/foo/_site;

     location ^~ /admin {
         auth_basic "Administration";
         auth_basic_user_file /foo/htpasswd;

         proxy_pass http://127.0.0.1:4000/admin;

         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
         proxy_set_header X-Forwarded-Proto $scheme;
         proxy_set_header X-Real-IP $remote_addr;
         proxy_set_header Host $http_host;
     }

     location ^~ /_api {
         auth_basic "Administration";
         auth_basic_user_file /foo/htpasswd;

         proxy_pass http://127.0.0.1:4000/_api;

         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
         proxy_set_header X-Forwarded-Proto $scheme;
         proxy_set_header X-Real-IP $remote_addr;
         proxy_set_header Host $http_host;
     }

     # caching for static site

     location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc)$ {
       expires 1M;
       add_header Cache-Control "public";
     }

     location ~* \.(?:css|js)$ {
       expires 1h;
       add_header Cache-Control "public";
     }
 }

However I want to remove the duplication so I merge the two location blocks for the proxy and use a regex:

server {
     listen 80;
     listen [::]:80;

     server_name www.example.com;
     root /home/foo/_site;

     location ~ ^/(admin|_api)(/.*)? {
          auth_basic_user_file /foo/htpasswd;
          auth_basic "Administration";

          proxy_pass http://127.0.0.1:4000$1;

          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
          proxy_set_header X-Forwarded-Proto $scheme;
          proxy_set_header X-Real-IP $remote_addr;
          proxy_set_header Host $http_host;
     }
}

But my site no longer works – I now get a blank page and the browser error console shows

The resource from “http://www.example.com/admin/styles.css” was blocked due to MIME type (“text/html”) mismatch (X-Content-Type-Options: nosniff).
admin

The resource from “http://www.example.com/admin/bundle.js” was blocked due to MIME type (“text/html”) mismatch (X-Content-Type-Options: nosniff).
admin

Loading failed for the with source “http://www.example.com/admin/bundle.js”. admin:11:1

What is causing the js and css content to get the wrong MIME type here?

The nginx logs show nothing unusual.

Best Answer

dumb error in proxy_pass

   location ~ ^/(admin|_api)(/.*)? {
      ...
      proxy_pass http://127.0.0.1:4000/$1$2;
    }