I have a angular application running in a docker ubuntu image that has nginx installed. I want to deploy this image to Kubernetes and use a nginx proxy to redirect all calls to /api to my backend service in Kubernetes.
My static web resources lie in /var/www/html and I add the following config to /etc/nginx/conf.d:
upstream backend-service {
server backend-service:8080;
}
server {
listen 80;
location / {
try_files $uri $uri/ /index.html;
}
location ^~ /api {
proxy_pass http://backend-service;
}
}
Accessing the frontend service on / or /#/dashboard returns the expected component of my Angular page, but a call to /api/v1/data only shows the default nginx 404 Not Found page.
What do I need to modify to have my backend calls redirected to my backend?
I use nginx 1.10.3 on ubuntu 16.04 and my frontend Dockerfile looks like this:
FROM ubuntu:16.04
# Install curl, nodejs and nginx
RUN apt-get update && \
apt-get install -y curl && \
curl -sL https://deb.nodesource.com/setup_8.x | bash - && \
apt-get install -y nodejs nginx && \
rm -rf /var/lib/apt/lists/*
# Create directory
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
# Copy and build rest of the app
COPY . /usr/src/app
RUN npm install
RUN node_modules/@angular/cli/bin/ng build --prod
RUN cp -a dist/. /var/www/html
# Configure and start nginx
COPY frontend.conf /etc/nginx/conf.d
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
Edit: Information about backend-service
The backend service listens to get and post requests on /api/v1/data and is reachable in Kubernetes via a Service named backend-service.
Edit2: Nginx access.log
https://gist.github.com/Steffen911/a56e3175bf12e511048d01359a475724
172.17.0.1 - - [13/Aug/2017:13:11:40 +0000] "GET / HTTP/1.1" 200 380 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36"
172.17.0.1 - - [13/Aug/2017:13:11:40 +0000] "GET /styles.d41d8cd98f00b204e980.bundle.css HTTP/1.1" 200 0 "http://192.168.99.100:30497/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36"
172.17.0.1 - - [13/Aug/2017:13:11:40 +0000] "GET /inline.c9a1a6b995c65c13f605.bundle.js HTTP/1.1" 200 1447 "http://192.168.99.100:30497/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36"
172.17.0.1 - - [13/Aug/2017:13:11:40 +0000] "GET /polyfills.117078cae3e3d00fc376.bundle.js HTTP/1.1" 200 97253 "http://192.168.99.100:30497/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36"
172.17.0.1 - - [13/Aug/2017:13:11:40 +0000] "GET /main.3e9a37b4dd0f3bf2465f.bundle.js HTTP/1.1" 200 64481 "http://192.168.99.100:30497/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36"
172.17.0.1 - - [13/Aug/2017:13:11:40 +0000] "GET /vendor.146173c1a99cc2172a5f.bundle.js HTTP/1.1" 200 661261 "http://192.168.99.100:30497/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36"
172.17.0.1 - - [13/Aug/2017:13:11:40 +0000] "GET /api/v1/data/ HTTP/1.1" 404 209 "http://192.168.99.100:30497/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36"
172.17.0.1 - - [13/Aug/2017:13:11:40 +0000] "GET /assets/home.jpg HTTP/1.1" 200 2608 "http://192.168.99.100:30497/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36"
172.17.0.1 - - [13/Aug/2017:13:11:40 +0000] "GET /assets/busy.gif HTTP/1.1" 200 48552 "http://192.168.99.100:30497/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36"
172.17.0.1 - - [13/Aug/2017:13:11:40 +0000] "GET /assets/background_light.png HTTP/1.1" 200 170599 "http://192.168.99.100:30497/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36"
172.17.0.1 - - [13/Aug/2017:13:11:40 +0000] "GET /assets/google.svg HTTP/1.1" 200 2232 "http://192.168.99.100:30497/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36"
172.17.0.1 - - [13/Aug/2017:13:11:40 +0000] "GET /assets/email.svg HTTP/1.1" 200 1596 "http://192.168.99.100:30497/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36"
172.17.0.1 - - [13/Aug/2017:13:11:40 +0000] "GET /favicon.ico HTTP/1.1" 200 198 "http://192.168.99.100:30497/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36"
172.17.0.1 - - [13/Aug/2017:13:11:44 +0000] "GET /api/v1/data/ HTTP/1.1" 404 209 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36"
The error.log file is empty.
Edit3: New nginx version and other SO thread
I also tried nginx 1.12.1 and it shows the same behaviour. The answers to this question also haven't helped: nginx proxy_pass 404 error, don't understand why
Edit4: I uploaded a minimal example that reproduces my problem on GitHub
From your troubleshooting of nginx, it appears that the nginx configuration file you have has effectively no effect — you report getting
404 Not Found
errors for everything other than the index page, with all the directives, fromtry_files
inlocation /
, toproxy_pass
andreturn 200 test
in a more specificlocation ^~ /api
, having no effect.As such, the problem appears to be in the
Dockerfile
— it appears that most other NGINX + Docker tutorials remove default configurations (e.g., withRUN rm /etc/nginx/conf.d/default.conf
), whereas your file is missing any such removal.In fact, Debian/Ubuntu appear to have the non-standard directories of questionable utility called
/etc/nginx/sites-available
and/etc/nginx/sites-enabled
, which, by default, must contain adefault
file with a presumptuouslisten 80 default_server
, effectively taking precedence over any otherlisten
of the same port in the absence of a more specificserver_name
.As such, there are multiple independent solutions:
Do not use fundamentally broken packages like those offered by Debian/Ubuntu. I once spent a good amount of time pulling my hair trying to figure out why my configs don't work, only to notice that even the backup files from
emacs
liketest.conf~
get included in Debian through Debian's defaultinclude /etc/nginx/sites-enabled/*;
. Sites-Enabled Is Evil.Note that NGINX provides official binary packages for most distributions, which wouldn't have had this issue, as it doesn't try to define a
default_server
in its/etc/nginx/conf.d/default.conf
, instead doing alisten 80;
withserver_name localhost;
, getting out of your way automatically by itself in most circumstances.E.g., replace
FROM ubuntu:16.04
withFROM nginx
in yourDockerfile
to be using NGINX official image.RUN rm /etc/nginx/sites-enabled/default
in yourDockerfile
to remove thedefault_server
listen
.Use the
server_name
directive to define hostname-based servers, possibly together with thelisten
directive with thedefault_server
parameter, too.Note that a duplicate
server_name
specification results in a configuration warning (with the[warn]
severity), but a duplicatedefault_server
is a configuration error ([emerg]
severity), which might help troubleshoot the issue earlier.The
proxy_pass
directive is highly unlikely to be generating the default nginx404 Not Found
error page itself.The
404
might be generated by the upstream, in which case, absent further instructions, nginx will simply propagate the message from upstream. If you get an nginx signature in your 404, then it means that the upstream is also running nginx, possibly to your surprise, revealing the configuration culprit.If the
404
is actually generated by nginx indeed, then it might be the case that thelocation
doesn't match. Try puttingreturn 200 thisisatest;
in place ofproxy_pass
to troubleshoot the issue.However, in your specific case,
location ^~ /api {
is an almost-impossible directive to not match a/api/v1/data/
request URI — the only thing I could think of is if you possibly have atry_files
in yourserver
config outside of any otherlocation
directive, which could then possibly make all location directives null and void. Are you sure yourtry_files
is fully contained within thelocation /
context?