nginx docker container: 502 bad gateway response - nginx

I've a service listening to 8080 port. This one is not a container.
Then, I've created a nginx container using official image:
docker run --name nginx -d -v /root/nginx/conf:/etc/nginx/conf.d -p 443:443 -p 80:80 nginx
After all:
# netstat -tupln | grep 443
tcp6 0 0 :::443 :::* LISTEN 3482/docker-proxy
# netstat -tupln | grep 80
tcp6 0 0 :::80 :::* LISTEN 3489/docker-proxy
tcp6 0 0 :::8080 :::* LISTEN 1009/java
Nginx configuration is:
upstream eighty {
server 127.0.0.1:8080;
}
server {
listen 80;
server_name eighty.domain.com;
location / {
proxy_pass http://eighty;
}
}
I've checked I'm able to connect with with this server with # curl http://127.0.0.1:8080
<html><head><meta http-equiv='refresh'
content='1;url=/login?from=%2F'/><script>window.location.replace('/login?from=%2F');</script></head><body
style='background-color:white; color:white;'>
...
It seems running well, however, when I'm trying to access using my browser, nginx tells bt a 502 bad gateway response.
I'm figuring out it can be a problem related with the visibility between a open by a non-containerized process and a container. Can I container stablish connection to a port open by other non-container process?
EDIT
Logs where upstream { server 127.0.0.1:8080; }:
2016/07/13 09:06:53 [error] 5#5: *1 connect() failed (111: Connection refused) while connecting to upstream, client: 62.57.217.25, server: eighty.domain.com, request: "GET / HTTP/1.1", upstream: "http://127.0.0.1:8080/", host: "eighty.domain.com"
62.57.217.25 - - [13/Jul/2016:09:06:53 +0000] "GET / HTTP/1.1" 502 173 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0" "-"
Logs where upstream { server 0.0.0.0:8080; }:
62.57.217.25 - - [13/Jul/2016:09:00:30 +0000] "GET / HTTP/1.1" 502 173 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0" "-" 2016/07/13 09:00:30 [error] 5#5: *1 connect() failed (111: Connection refused) while connecting to upstream, client:
62.57.217.25, server: eighty.domain.com, request: "GET / HTTP/1.1", upstream: "http://0.0.0.0:8080/", host: "eighty.domain.com" 2016/07/13 09:00:32 [error] 5#5: *3 connect() failed (111: Connection refused) while connecting to upstream, client: 62.57.217.25, server: eighty.domain.com, request: "GET / HTTP/1.1", upstream: "http://0.0.0.0:8080/", host: "eighty.domain.com"
62.57.217.25 - - [13/Jul/2016:09:00:32 +0000] "GET / HTTP/1.1" 502 173 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0" "-"
Any ideas?

The Problem
Localhost is a bit tricky when it comes to containers. Within a docker container, localhost points to the container itself.
This means, with an upstream like this:
upstream foo{
server 127.0.0.1:8080;
}
or
upstream foo{
server 0.0.0.0:8080;
}
you are telling nginx to pass your request to the local host.
But in the context of a docker-container, localhost (and the corresponding ip addresses) are pointing to the container itself:
by addressing 127.0.0.1 you will never reach your host machine, if your container is not on the host network.
Solutions
Host Networking
You can choose to run nginx on the same network as your host:
docker run --name nginx -d -v /root/nginx/conf:/etc/nginx/conf.d --net=host nginx
Note that you do not need to expose any ports in this case.
This works though you lose the benefit of docker networking. If you have multiple containers that should communicate through the docker network, this approach can be a problem. If you just want to deploy nginx with docker and do not want to use any advanced docker network features, this approach is fine.
Access the hosts remote IP Address
Another approach is to reconfigure your nginx upstream directive to directly connect to your host machine by adding its remote IP address:
upstream foo{
//insert your hosts ip here
server 192.168.99.100:8080;
}
The container will now go through the network stack and resolve your host correctly:
You can also use your DNS name if you have one. Make sure docker knows about your DNS server.

For me helped this line of code proxy_set_header Host $http_host;
server {
listen 80;
server_name localhost;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_redirect off;
proxy_pass http://myserver;
}

Just to complete other answers, I'm using mac for development and using host.docker.internal directly on upstream worked for me and no need to pass the host remote IP address. Here is config of the proxy nginx:
events { worker_connections 1024; }
http {
upstream app1 {
server host.docker.internal:81;
}
upstream app1 {
server host.docker.internal:82;
}
server {
listen 80;
server_name app1.com;
location / {
proxy_pass http://app1;
}
}
server {
listen 80;
server_name app2.com;
location / {
proxy_pass http://app2;
}
}
}
As you can see, I used different ports for different apps behind the nginx proxy. I used port 81 for the app1 and port 82 for the app2 and both app1 and app2 have their own nginx containers:
For app1:
docker run --name nginx -d -p 81:80 nginx
For app2:
docker run --name nginx -d -p 82:80 nginx
Also, please refer to this link for more details:
docker doc for mac

What you can do is configure proxy_pass that from container perspective the adress will be pointing to your real host.
To get host address from container perspective you can do as following on Windows with docker 18.03 (or more recent):
Run bash on container from host where image name is nginx (works on Alpine Linux distribution):
docker run -it nginx /bin/ash
Then run inside container
/ # nslookup host.docker.internal
Name: host.docker.internal
Address 1: 192.168.65.2
192.168.65.2 is the host's IP - not the bridge IP like in spinus accepted answer.
I am using here host.docker.internal:
The host has a changing IP address (or none if you have no network access). From 18.03 onwards our recommendation is to connect to the special DNS name host.docker.internal, which resolves to the internal IP address used by the host. This is for development purpose and will not work in a production environment outside of Docker for Windows.
Then you can change nginx config to:
proxy_pass http://192.168.65.2:{your_app_port};
and it should work fine.
Remember to provide the same port as your local application runs with.

# the upstream component nginx needs to connect to
upstream django {
# server unix:///path/to/your/mysite/mysite.sock; # for a file socket
server 127.0.0.1:8001; # for a web port socket (we'll use this first)
}
location / {
uwsgi_pass django;
include /path/to/your/mysite/uwsgi_params; # the uwsgi_params file you installed
}
complete reference: https://uwsgi-docs.readthedocs.io/en/latest/tutorials/Django_and_nginx.html

nginx.sh
ip=$(ifconfig | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1' | head -n 1)
docker run --name nginx --add-host="host:${ip}" -p 80:80 -d nginx
nginx.conf
location / {
...
proxy_pass http://host:8080/;
}
It‘s works for me

I had this issue and it turned out to be an issue with the docker container not starting up due to a permissions issue.
In my case running
docker-compose ps
showed that the container had not started and exited with status 1. Turns out the permissions had been lost in migrating to a new machine. Adjusting the permissions to a know staff user on the parent directory fixed the problem for me and I was then able to start docker service where as previously I was getting
nginx_1_c18a7f6f7d6d | chown: /var/www/html: Operation not permitted

Related

nginx proxy_pass could not be resolved (3: Host not found)

I have the following nginx configuration which returns 502
server {
listen 2052;
listen 2082;
server_name good.abc.com;
location / {
proxy_pass http://goodServer:$server_port;
}
}
Testing:
proxy_pass http://goodServer:2052; When the fixed port is 2052
curl good.abc.com:2052 It can be accessed normally.
Question:
The port I want to forward user requests to
For example.
curl good.abc.com:2052 ---> goodServer:2052
curl good.abc.com:2082 ---> goodServer:2082
So the port must be a variable, just like $server_port
Log:
2021/04/04 14:10:11 [error] 24#24: *19 good could not be resolved (3: Host not found), client: 162.158.91.119, server: good.abc.com, request: "GET / HTTP/1.1", host: "good.abc.com:2052"

Wildlfy with Nginx not working properly

We had installed wildfly for a couple of time working correctly. We configured right now Nginx as reverse proxy for wildfly.
We're getting on OPTIONS method 405 Method Not Allowed. Here is the configuration of nginx.
/etc/nginx/conf.d/wildfly.conf
upstream wildfly {
server 127.0.0.1:8081;
}
server {
listen 8080;
server_name guest1;
location/ {
proxy_pass http://wildfly;
}
}
Error obtained after installing nginx:
This is the error got by nginx:
2017/06/23 08:16:54 [crit] 1386#0: *9 connect() to 127.0.0.1:8081 failed (13: Permission denied) while connecting to upstream, client: 172.28.128.1, server: guest1, request: "OPTIONS /commty/cmng/users HTTP/1.1", upstream: "http://127.0.0.1:8081/commty/cmng/users", host: "guest1:8080"
What I'm missing?
I've done the following to finally make it work on CentOS7 + Wildfly.
Vagrant up
Install NGINX
yum install epel-release
yum install nginx
Configure /etc/nginx/nginx.conf (default configuration)
Configure /etc/nginx/conf.d/wildfly.conf (using port 80 for nginx and 8080 for wildfly)
upstream wildfly {
server 127.0.0.1:8080;
}
server {
listen 80;
server_name guest1;
location / {
proxy_pass http://wildfly;
}
}
Also set SELinux permissive for let nginx work.
$ setenforce permissive
After that wildfly is working properly through nginx.

docker compose: rebuild of one linked container breaks nginx's upstream

I'm using docker-compose with "Docker for Mac" and I have two containers: one NGINX, one container serving a node-app on port 3000.
docker-compose.yml looks like this:
version: "2"
services:
nginx:
build: ./nginx
ports:
- "80:80"
links:
- api
api:
build: ./api
volumes:
- "./api:/opt/app"
In the NGINX's config I say:
upstream api {
server api:3000;
}
server {
# ....
location ~ ^/api/?(.*) {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_pass http://api;
proxy_redirect off;
}
}
Now, when I change something in the node code and rebuild the container
$ docker-compose stop api && docker-compose up -d --build --no-deps api
the container is getting rebuilt and started. The problem is, that sometimes the internal IP of the container changes and NGINX won't know about that. Funny enough, when I go into the NGINX container and ping api I get the new IP address
$ ping api
PING api (172.19.0.3): 56 data bytes
64 bytes from 172.19.0.3: icmp_seq=0 ttl=64 time=0.236 ms
but NGINX logs still say
2016/10/20 14:20:53 [error] 9#9: *9 connect() failed (113: No route to host) while connecting to upstream, client: 172.19.0.1, server: localhost, request: "GET /api/test HTTP/1.1", upstream: "http://172.19.0.7:3000/api/test", host: "localhost"
where the upstream's 172.19.0.7 is still the old IP address.
PS: this doesn't happen every time I rebuild the container.
This is because Nginx caches the DNS response for upstream servers - in your workflow you're only restarting the app container, so Nginx doesn't reload and always uses its cached IP address for the api container.
When you run a new api container, as you've seen, it can have a different IP address so the cache in Nginx is not valid. The ping works because it doesn't cache Docker's DNS response.
Assuming this is just for dev and downtime isn't an issue, docker-compose restart nginx after you rebuild the app container will restart Nginx and clear the DNS cache.

Dynamic proxy_pass in nginx to another pod in Kubernetes

I'm trying to create an nginx proxy that forwards requests to /<service> to http://<service>. I first tried the following:
location ~ ^/(.+)$ {
set $backend "http://$1:80";
proxy_pass $backend;
}
But it fails saying something like (when calling /myservice):
[error] 7741#0: *1 no resolver defined to resolve http://myservice
Since myservice is not externally accessible I've tried to install go-dnsmasq as a sidecar in the same pod and I try to use it for DNS resolution (like I've seen in this example) and change my nginx config to look like this:
location ~ ^/(.+)$ {
resolver 127.0.0.1:53;
set $backend "http://$1:80";
proxy_pass $backend;
}
But now nginx fails with:
[error] 9#9: *734 myservice could not be resolved (2: Server failure), client: 127.0.0.1, server: nginx-proxy, request: "GET /myservice HTTP/1.1", host: "localhost:8080"
127.0.0.1 - xxx [30/May/2016:10:34:23 +0000] "GET /myservice HTTP/1.1" 502 173 "-" "curl/7.38.0" "-"
My Kubernetes pod looks like this:
spec:
containers:
- name: nginx
image: "nginx:1.10.0"
ports:
- containerPort: 8080
name: "external"
protocol: "TCP"
- name: dnsmasq
image: "janeczku/go-dnsmasq:release-1.0.5"
args:
- --listen
- "0.0.0.0:53"
Running netstat -ntlp in the dnsmasq container gives me:
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:8080 0.0.0.0:* LISTEN -
tcp 0 0 :::53 :::* LISTEN 1/go-dnsmasq
And running nmap --min-parallelism 100 -sT -sU localhost in the nginx container:
Starting Nmap 6.47 ( http://nmap.org ) at 2016-05-30 10:33 UTC
Nmap scan report for localhost (127.0.0.1)
Host is up (0.00055s latency).
Other addresses for localhost (not scanned): 127.0.0.1
Not shown: 1997 closed ports
PORT STATE SERVICE
53/tcp open domain
8080/tcp open http-proxy
53/udp open domain
So it seems that dnsmasq and nginx are indeed up and running? What could I be doing wrong?
After much research and trial and error I managed to solve this. First I changed the pod specification to:
spec:
containers:
- name: nginx
image: "nginx:1.10.0"
ports:
- containerPort: 8080
name: "external"
protocol: "TCP"
- name: dnsmasq
image: "janeczku/go-dnsmasq:release-1.0.5"
args:
- --listen
- "127.0.0.1:53"
- --default-resolver
- --append-search-domains
- --hostsfile=/etc/hosts
- --verbose
then I also had to disable the ipv6 for the resolver in nginx:
location ~ ^/(.+)$ {
resolver 127.0.0.1:53 ipv6=off;
set $backend "http://$1:80";
proxy_pass $backend;
}
Then it works as expected!
I resolved this by coredns docker :
my nginx and coredns are all deploy on host
step1: config Corefile
in Corefile maybe you should change k8s master config refer: https://coredns.io/plugins/kubernetes/
sudo mkdir /etc/coredns; sudo tee /etc/coredns/Corefile <<-'EOF' .:53 {
log
errors
health
kubernetes cluster.local in-addr.arpa ip6.arpa {
endpoint http://172.31.88.71:8080
pods insecure
upstream
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
forward . /etc/resolv.conf
cache 30
loop
reload
loadbalance } EOF
step2:config docker and then start it
tee coreos.sh <<-'EOF'
docker run --restart=always -idt --name coredns \
-v /etc/coredns/Corefile:/etc/coredns/Corefile \
-v /home/ec2-user/.kube/config:/etc/coredns/kubeconfig \
-p 53:53/udp \
coredns/coredns:1.6.9 \
-conf /etc/coredns/Corefile
EOF
step3: config nginx and then reload
resolver 127.0.0.1 valid=60s ipv6=off;

Convert uWSGI HTTP server to work behind Nginx instead

I'm serving my app with uWSGI using uwsgi --http-socket 127.0.0.1:3031 -w app:app, which works when I go to 127.0.0.1:3031 in a browser. I want to use Nginx, so I told it to uwsgi_pass to that url, but now I get a 502 Bad Gateway error. How do I put uWSGI behind Nginx?
server {
listen 8080;
server_name 127.0.0.1;
location / {
uwsgi_pass 127.0.0.1:3031;
include uwsgi_params;
}
location /static {
alias /static/folder/location;
}
}
2016/05/16 19:50:09 [error] 6810#0: *4 upstream prematurely closed
connection while reading response header from upstream, client:
127.0.0.1, server: 127.0.0.1, request: "GET / HTTP/1.1", upstream:
"uwsgi://127.0.0.1:3031", host: "127.0.0.1:8080"
You can use http-socket between nginx and uWSGI.
For example, if you launch your python app with uWSGI:
uwsgi --http-socket 127.0.0.1:3031 --wsgi-file application.py --callable app --processes 4 --threads 2 --stats 127.0.0.1:9191
Configure Nginx with:
location / {
proxy_pass http://127.0.0.1:3031/;
}
Use socket, not http-socket.
uwsgi --socket 127.0.0.1:3031 -w app:app
http-socket makes uWSGI act like a web server that speaks HTTP, and is not correct if you're using Nginx, since it understands uWSGI directly.

Resources