NextJS static files 404 Not Found when behind NginX reverse proxy

When using NginX as a reverse proxy to a NextJS app, static files (.js, .css, etc) come up as 404 not found. The NextJS app works in dev mode. It works in production mode on my machine. It works as a docker container on my machine. But when I deploy it as a docker container in production behind NginX reverse proxy, it 404’s every static file.

I’ve connected to the running docker image and every file is there, right where it should be. I have no idea what is happening, but it’s super frustrating!

I created a Demo Repo on GitHub that you can clone and reproduce the issue yourself.

Here’s how I set up this demo project:

  • NextJS App created using npx create-next-app@latest.
  • NextJS App is dockerized following NextJS’s docs here: https://github.com/vercel/next.js/tree/canary/examples/with-docker
    • Edit next.config.js to include output: "standalone"
    • Create Dockerfile according to NextJS Documentation
  • The nginx folder at the root of this project has all the nginx config.
  • A docker-compose.yaml file was created to launch both apps.
    • NginX listens on port 80 for incoming traffic, and reverse-proxies traffic to the NextJS app.

Thanks in advance for any help!

This happens when NginX is configured to add caching headers to static files via this config block:

# cache static files for 7 days
location ~* \.(?:css(\.map)?|js(\.map)?|jpe?g|png|gif|ico|cur|heic|webp|tiff?|mp3|m4a|aac|ogg|midi?|wav|mp4|mov|webm|mpe?g|avi|ogv|flv|wmv)$ {
    expires    7d;
    access_log off;
}

When I comment out this block of NginX config, the NextJS app can serve static files again!!

This is kind of dumb. How does this result in 404 files?! This was very difficult to debug, and I hope this post helps at least 1 other person. <3

However, my NginX server serves more than just my NextJS App, including static files on the host machine, so I would like to keep these caching declarations in tact. Some possible solutions are:

  1. Comment out this block in NginX. This is a poor solution, as other web resources benefit from this directive. 2/10 solution.
  2. Declare caching directives in their own file, and include them in server blocks that need them. This would work, but is slightly more tedious. 8/10 solution.
  3. Host NextJS app static files on host machine instead of inside Docker container, and configure NginX to serve those files. I don’t like this solution, as it separates the static files from the server file. Although, it may be more performant, it does add some complexity. 6/10 solution.
    • I’m actually currently doing this, and it was obnoxious to set up, and also obnoxious to wrap my head around it when I came back to it 8 months later.
  4. Upload files to CDN instead of hosting on NginX machine. Same pros and cons as solution 3, but with better performance because CDN. 7/10 solution.

Note: Serving static files through a JS server is SLOW. Use a dedicated file server (NginX, CDN, etc) in a public production application. My specific use case is an internal tool at my company, so I more-highly value a simple deployment strategy. Know the pros and cons and make the right choice for your use case.

Leave a Comment