Can't serve static assets from docker containers behind Nginx reverse proxy
In case anyone else encounters the same problem, here's an additional answer as well as the one posted by @b0gusb. This is a solution when you have docker containers as the upstream applications. dashboard
and editor
, for example, are containers comprising of create-react-app applications and an nginx server.
Firstly, change the directory where the index.html
file, generated by create-react-app
, searches of the static assets by setting the homepage
field in the package.json:
{ "name": "dashboard", "homepage": "https://example.com/dashboard", "version": "0.1.0", "private": true, "dependencies": { "react": "^16.9.0", "react-dom": "^16.9.0", "react-scripts": "3.1.1" }, "scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject" }, "eslintConfig": { "extends": "react-app" }, "browserslist": { "production": [ ">0.2%", "not dead", "not op_mini all" ], "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ] }}
Using the current latest version of react-scripts
(3.1.1) this will generate an index.html file with links to your static assets which are expected to reside inside the dashboard
directory (or whatever name you choose after the slash in the homepage
field).
Now in your docker file you need to do some moving of build assets so that the links in the index.html
do not break. The following is my Dockerfile
:
FROM node:12.2.0-alpine as builderWORKDIR /usr/src/appENV PATH /usr/src/app/node_modules/.bin:$PATHCOPY package.json .RUN npm install react-scripts@3.1.1 -gRUN npm installCOPY . .RUN npm run buildFROM nginx:1.17.2COPY --from=builder /usr/src/app/build/ /usr/share/nginx/html/dashboardCOPY --from=builder /usr/src/app/build/*.html /usr/share/nginx/htmlEXPOSE 80CMD [ "nginx", "-g", "daemon off;" ]
Notice that the static assets generated by create-react-app
build, are located inside the dashboard
directory and the index.html
in the /usr/share/nginx/html
directory. Now your nginx reverse proxy can differentiate requests for different static assets of your various containers:
# location to handle calls by the editor app for assets location /editor/ { proxy_pass http://editor/editor/; } # location to handle calls by the dashboard app for assets location /dashboard/ { proxy_pass http://dashboard/dashboard/; } # location to handle navigation to the editor app location /editor-path/ { access_log /var/logs/nginx/access.log; rewrite ^/editor-path(.*)$ $1 break; proxy_pass http://editor/; } # location to handle calls to the rest/graphql api location /api/ { access_log /var/logs/nginx/access.log; rewrite ^/api(.*)$ $1 break; proxy_pass http://restserver/; } # location to handle navigation to the dashboard app location / { access_log /var/logs/nginx/access.log; proxy_pass http://dashboard/; }
If I understood correctly you have static resources on editor
and dashboard
upstreams and in both cases the URL is the same /static/some.resource
Because you cannot differentiate based on the URL you could configure nginx
to try if the file exists on dashboard
first and proxy the request to editor
if not found.
upstream editor { server editor:80; } upstream dashboard { server dashboard:80; } server { location /static { # Send 404s to editor error_page 404 = @editor; proxy_intercept_errors on; proxy_pass http://dashboard } location @editor { # If dashboard does not have the file try with editor proxy_pass http://editor } }
See also nginx – try files on multiple named location or server
Hope it helps.
put the /editor configuration above the / configuration.
Nginx perform checks from top to bottom, so it's possible that having the root configuration ( / ) on top will route all contents to the wrong server.
Switch the blocks location and restart/reload nginx configuration.