Reputation: 1476
I'm trying to use Nginx as a reverse proxy to serve two containers. Here is a part of my Nginx conf file:
upstream dashboard {
server dashboard:80;
}
upstream editor {
server editor:80;
}
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://dashboard;
}
location /editor/ {
rewrite ^/editor(.*)$ $1 break;
proxy_pass http://editor;
}
I'm getting 404 errors when I navigate to the /editor
url in my browser because the page is submitting requests for static resources that reside in the upstream container, "editor".
I'm pretty new to Nginx but I presume when it receives a request with the url:
http://example.com/static/css/2.3d394414.chunk.css
Nginx has no way of knowing that the corresponding css is located inside the editor
container. How can I amend the configuration to fix this problem? I've seen some configurations which provide a common path to any static assets but I need a solution that can handle assets within docker containers.
Upvotes: 5
Views: 3843
Reputation: 379
Actually, for easy configuration, you can follow this:
upstream dashboard {
server dashboard:80;
}
upstream editor {
server editor:80;
}
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://dashboard;
}
location /editor/ {
proxy_pass http://editor;
proxy_set_header Accept-Encoding "";
sub_filter "/static" "/editor/static;
sub_filter_once off;
}
sub_filter
function will change example.com/static/ become example.com/editor/static, but for best configuration you must make one path for all static files. Like:
/var/data/build/dashboard/.. (can be css, js)
/var/data/build/editor/.. (can be css, js)
I think use sub_filter
is good while the app doesn't have many URLs to rewrite with, I hope this helps.
Upvotes: 0
Reputation: 1476
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 builder
WORKDIR /usr/src/app
ENV PATH /usr/src/app/node_modules/.bin:$PATH
COPY package.json .
RUN npm install [email protected] -g
RUN npm install
COPY . .
RUN npm run build
FROM nginx:1.17.2
COPY --from=builder /usr/src/app/build/ /usr/share/nginx/html/dashboard
COPY --from=builder /usr/src/app/build/*.html /usr/share/nginx/html
EXPOSE 80
CMD [ "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/;
}
Upvotes: 2
Reputation: 4721
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.
Upvotes: 1
Reputation: 335
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.
Upvotes: 0