Bad Gateway from nginx published with docker-compose - docker

I am learning docker-compose and now I am trying to setup app and nginx in one docker-compose script on my WSL Ubuntu.
I am testing my endpoint with
curl -v http://127.0.0.1/weatherforecast
But I am receiving 502 Bad Gateway from nginx.
If I change port exposing to port publishing in docker-compose, as below, requests bypass nginx and reach my app and I receive an expected response.
ports:
- 5000:8080
My setup:
app's dockerfile
FROM mcr.microsoft.com/dotnet/aspnet:3.1 AS base
WORKDIR /app
ENV ASPNETCORE_URLS=http://+:8080
FROM mcr.microsoft.com/dotnet/sdk:3.1 AS build
WORKDIR /src
COPY ["WebApplication2.csproj", "."]
RUN dotnet restore "./WebApplication2.csproj"
COPY . .
WORKDIR "/src/."
RUN dotnet build "WebApplication2.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "WebApplication2.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "WebApplication2.dll"]
nginx.conf
events {
worker_connections 1024;
}
http {
access_log /var/log/nginx/access.log;
server {
listen 80;
location / {
proxy_pass http://127.0.0.1:8080/;
}
}
}
docker-compose.yml
version: "3.9"
services:
web:
depends_on:
- nginx
build: ./WebApplication2
expose:
- "8080"
nginx:
image: "nginx"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- ./logs:/var/log/nginx/
ports:
- 80:80
>docker-compose ps
Name Command State Ports
-----------------------------------------------------------------------------------------------
composetest_nginx_1 /docker-entrypoint.sh ngin ... Up 0.0.0.0:80->80/tcp,:::80->80/tcp
composetest_web_1 dotnet WebApplication2.dll Up 8080/tcp
/var/log/nginx/error.log
[error] 31#31: *1 connect() failed (111: Connection refused) while connecting to upstream, client: 172.26.0.1, server: , request: "GET /weatherforecast HTTP/1.1", upstream: "http://127.0.0.1:8080/weatherforecast", host: "127.0.0.1"
cURL output:
* Trying 127.0.0.1:80...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 80 (#0)
> GET /weatherforecast HTTP/1.1
> Host: 127.0.0.1
> User-Agent: curl/7.68.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 502 Bad Gateway
< Server: nginx/1.21.1
< Date: Fri, 13 Aug 2021 17:50:56 GMT
< Content-Type: text/html
< Content-Length: 157
< Connection: keep-alive
<
<html>
<head><title>502 Bad Gateway</title></head>
<body>
<center><h1>502 Bad Gateway</h1></center>
<hr><center>nginx/1.21.1</center>
</body>
</html>
* Connection #0 to host 127.0.0.1 left intact

You should redirect your request to your web container instead of 127.0.0.1. Each container is running as separate part of network (each has different IP address) and 127.0.0.1 points to local container. So, in your case, it point to nginx itself. Instead of real IP address of container, you can use DNS name (it is equal to service name in docker-compose). Use something like:
events {
worker_connections 1024;
}
http {
access_log /var/log/nginx/access.log;
server {
listen 80;
location / {
proxy_pass http://web:8080/;
}
}
}
Also, you specified that your web container depends on nginx, but it should be viceversa. Like:
version: "3.9"
services:
web:
build: .
nginx:
image: "nginx"
depends_on:
- web
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
ports:
- 80:80

Related

Nginx file not found while doing simple proxy

I'm trying to configure simple Nginx reverse proxy, here is my nginx.conf file
http {
server {
listen 80 default_server;
listen [::]:80 default_server;
location /api {
proxy_pass http://172.17.0.1:8081/api;
}
}
}
And here is my Dockerfile
FROM openresty/openresty:latest
COPY nginx.conf /etc/nginx/nginx.conf
EXPOSE 80/tcp
ENTRYPOINT ["nginx", "-g", "daemon off;"]
Now, I'm executing docker build . -t my-nginx and then docker run -p 80:80 my-nginx
And I'm calling endpoint at 127.0.0.1:80/api
However, I'm getting 404 back in response and in nginx logs I can see
172.17.0.1 - - [02/Jan/2023:14:39:16 +0000] "POST /api HTTP/1.1" 404 159 "-" "Apache-HttpClient/4.5.13 (Java/17.0.5)" 2023/01/02 14:39:16
[error] 7#7: *1 open() "/usr/local/openresty/nginx/html/api" failed
(2: No such file or directory), client: 172.17.0.1, server: localhost,
request: "POST /api HTTP/1.1", host: "127.0.0.1:80"
Why is that happening? What is wrong with that configuration?
The reason is that by default the openresty docker image won't look for the nginx configuration file under /etc/nginx/nginx.conf, but on /usr/local/openresty/nginx/conf/nginx.conf.
You can verify this by running:
# nginx -t
nginx: the configuration file /usr/local/openresty/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/openresty/nginx/conf/nginx.conf test is successful
This said, the /usr/local/openresty/nginx/conf/nginx.conf file has an include directive for all the files under /etc/nginx/conf.d folder, you can therefore place your nginx server and location configurations under this folder.
Replace Dockerfile to be:
FROM openresty/openresty:latest
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80/tcp
ENTRYPOINT ["nginx", "-g", "daemon off;"]
and remove the http key in your nginx configuration.
Make sure to read docker documentation for openresty image, as you'll find all required information: openresty docker

nginx reverse proxy to other nginx 502 bad gateway

I would like to create two services, both of them having their own nginx. I would like to use third nginx as a reverse proxy to these two but I got
502 Bad Gateway
when I request
http://127.0.0.1:8080/
http://127.0.0.1:8080/one
http://127.0.0.1:8080/two
accessing:
http://127.0.0.1:8081
http://127.0.0.1:8082
works ok
I have this docker-compose.yml
version: "3.3"
services:
nginx-one:
image: nginx:1.17.8
ports:
- "8081:80"
networks:
- frontend
- backend
volumes:
- ./nginx-one/html:/usr/share/nginx/html
nginx-two:
image: nginx:1.17.8
ports:
- "8082:80"
networks:
- frontend
- backend
volumes:
- ./nginx-two/html:/usr/share/nginx/html
nginx-reverse-proxy:
image: nginx:1.17.8
ports:
- "8080:80"
networks:
- frontend
- backend
volumes:
- ./nginx-reverse-proxy/html:/usr/share/nginx/html
- ./nginx-reverse-proxy/conf.d:/etc/nginx/conf.d
debian-network:
image: cslev/debian_networking
stdin_open: true # docker run -i
tty: true # docker run -t
networks:
- frontend
- backend
networks:
frontend:
internal: false
backend:
internal: true
and dir structure
.
├── docker-compose.yml
├── nginx-one
│   └── html
│   └── index.html
├── nginx-reverse-proxy
│   ├── conf.d
│   │   └── default.conf
│   └── html
│   └── index.html
├── nginx-two
   └── html
   └── index.html
nginx.conf content
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
and
conf.d/default.conf
server {
listen 80;
location /one {
proxy_pass http://127.0.0.1:8081/;
}
location /two {
proxy_pass http://127.0.0.1:8082/;
}
}
When I comment this line of docker-compose.yml
# ./nginx-reverse-proxy/conf.d:/etc/nginx/conf.d
so conf.d/default.conf is not used, and I request from the host's browser:
http://127.0.0.1:8080/
it gives a proper response from the nginx-reverse-proxy itself but obviously
http://127.0.0.1:8080/one
http://127.0.0.1:8080/two
don't provide any response from
http://127.0.0.1:8081
http://127.0.0.1:8082
but 404 instead.
docker ps output:
IMAGE COMMAND CREATED STATUS PORTS NAMES
cslev/debian_networking "bash" 25 minutes ago Up 3 minutes nginxproblem_debian-network_1
nginx:1.17.8 "nginx -g 'daemon of…" 47 minutes ago Up 3 minutes 0.0.0.0:8080->80/tcp nginxproblem_nginx-reverse-proxy_1
nginx:1.17.8 "nginx -g 'daemon of…" 14 hours ago Up 3 minutes 0.0.0.0:8082->80/tcp nginxproblem_nginx-two_1
nginx:1.17.8 "nginx -g 'daemon of…" 14 hours ago Up 3 minutes 0.0.0.0:8081->80/tcp nginxproblem_nginx-one_1
runnnig this script:
#!/bin/sh
docker exec nginxproblem_debian-network_1 curl -sS 127.0.0.1:8080
docker exec nginxproblem_debian-network_1 curl -sS nginxproblem_nginx-reverse-proxy_1:8080
docker exec nginxproblem_debian-network_1 curl -sS 127.0.0.1:8080/one
docker exec nginxproblem_debian-network_1 curl -sS nginxproblem_nginx-reverse-proxy_1:8080/one
docker exec nginxproblem_debian-network_1 curl -sS 127.0.0.1:8080/two
docker exec nginxproblem_debian-network_1 curl -sS nginxproblem_nginx-reverse-proxy_1:8080/two
docker exec nginxproblem_debian-network_1 curl -sS 127.0.0.1:8081
docker exec nginxproblem_debian-network_1 curl -sS nginxproblem_nginx-one_1:8080
docker exec nginxproblem_debian-network_1 curl -sS 127.0.0.1:8082
docker exec nginxproblem_debian-network_1 curl -sS nginxproblem_nginx-two_1:8082
gives:
curl: (7) Failed to connect to 127.0.0.1 port 8080: Connection refused
curl: (7) Failed to connect to nginxproblem_nginx-reverse-proxy_1 port 8080: Connection refused
curl: (7) Failed to connect to 127.0.0.1 port 8080: Connection refused
curl: (7) Failed to connect to nginxproblem_nginx-reverse-proxy_1 port 8080: Connection refused
curl: (7) Failed to connect to 127.0.0.1 port 8080: Connection refused
curl: (7) Failed to connect to nginxproblem_nginx-reverse-proxy_1 port 8080: Connection refused
curl: (7) Failed to connect to 127.0.0.1 port 8081: Connection refused
curl: (7) Failed to connect to nginxproblem_nginx-one_1 port 8080: Connection refused
curl: (7) Failed to connect to 127.0.0.1 port 8082: Connection refused
curl: (7) Failed to connect to nginxproblem_nginx-two_1 port 8082: Connection refused
when - ./nginx-reverse-proxy/conf.d:/etc/nginx/conf.d is not commented,
and the same output when - ./nginx-reverse-proxy/conf.d:/etc/nginx/conf.d is commented in contrary to accessing ip addresses from the browser.
Unless you have host networking enabled, 127.0.0.1 is pointing to the container itself. You can refer to the other two containers from inside a container in the same network by the service name, e.g. nginx-one or nginx-two.
You're also mapping the container port 80 to port 8080/8081/8082 on the host machine. This however does nothing for communication between containers in the same network. Check the docs:
By default, when you create or run a container using docker create or docker run, it does not publish any of its ports to the outside world. To make a port available to services outside of Docker, or to Docker containers which are not connected to the container’s network, use the --publish or -p flag. This creates a firewall rule which maps a container port to a port on the Docker host to the outside world.
So, try changing http://127.0.0.1:8081/; to http://nginx-one/; and it should work.

Docker: nginx reverse proxy and how to configure multiple services (i.e on 8080 &8081)

I am a bit stuck with configuring multiple services where nginx is the proxy server.
running :
docker -v
Docker version 19.03.8, build afacb8b7f0
docker-compose -v
docker-compose version 1.23.2, build 1110ad01
I want to start with this test, everything in the same docker-compose.yml-file :
link to jwilder/nginx
proxy : nginx-server (jwilder/nginx-proxy:0.7.0 , which is nginx 1.17.6)
container1 : httpd:2.4
container2 : httpd:2.4
updating my /etc/hosts before I start
127.0.0.1 container1.com
127.0.0.1 container2.com
Here is my docker-compose.yml-file (obs -> version 3.7)
version: '3.7'
services:
proxy:
image: jwilder/nginx-proxy:0.7.0
container_name: proxy-test
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ./nginx-proxy.conf:/etc/nginx/conf.d/nginx-proxy.conf:ro
container1:
image: httpd:2.4
container_name: container-1
environment:
- VIRTUAL_HOST:container1.com
ports:
- 8080:80
container2:
image: httpd:2.4
container_name: container-2
environment:
- VIRTUAL_HOST:container2.com
ports:
- 8081:80
here is my nginx-proxy.conf:
server {
listen 80;
server_name container1.com;
location / {
proxy_pass http://localhost:8080;
}
}
server {
listen 80;
server_name container2.com;
location / {
proxy_pass http://localhost:8081;
}
}
After this I run the
docker exec container-1 sed -i 's/It works!/Container 1/' /usr/local/apache2/htdocs/index.html AND docker exec container-2 sed -i 's/It works!/Container 2/' /usr/local/apache2/htdocs/index.html
Test 1 : with curl to the port 8080 and port 8081
curl localhost:8080
response -> Container 1
curl localhost:8081
response -> Container 2
Test 2 : with curl to container1.com AND container2.com
curl container1.com
status 502
curl container2.com
status 502
Are the settings in my conf wrong ?
Troubleshooting 1:
docker exec -it proxy-test bash
I can see that the nginx-proxy.conf is in the directory (/etc/nginx/conf.d)
/etc/nginx/conf.d/default.conf is there as well
Troubleshooting 2: The proxy-log (Connection refused - while connecting to upstream)
proxy-test | nginx.1 | 2020/04/03 10:52:08 [error] 61#61: *9 connect() failed (111: Connection refused) while connecting to upstream, client: 172.29.0.1, server: container1.com, request: "GET / HTTP/1.1", upstream: "http://127.0.0.1:8080/", host: "container1.com"
proxy-test | nginx.1 | 2020/04/03 10:52:08 [error] 61#61: *9 connect() failed (111: Connection refused) while connecting to upstream, client: 172.29.0.1, server: container1.com, request: "GET / HTTP/1.1", upstream: "http://127.0.0.1:8080/", host: "container1.com"
Found 2 solutions to this.
(1)
the first is to update the nginx-proxy.conf with the name of the containers instead of pointing to http://localhost:8080; and http://localhost:8081; :
new config-file
server {
listen 80;
server_name container1.com;
location / {
proxy_pass http://container-1;
}
}
server {
listen 80;
server_name container2.com;
location / {
proxy_pass http://container-2;
}
}
(2)
Leaving out the nginx-proxy.conf-file , docker-compose.yml will map things correctly.

nginx reverse proxy upstream fails in docker-compose with connection refused message

I have a docker-compose.yaml similar to this (shortened for simplicity):
# ...
services:
my-ui:
# ...
ports:
- 5402:8080
networks:
- my-net
networks:
my-net:
external:
name: my-net
and I'm trying to set up nginx as a reverse proxy with this configuration:
upstream client {
server my-ui:5402;
}
server {
listen 80;
location / {
proxy_pass http://client;
}
}
and this is the docker-compose.yaml I have for nginx:
# ...
services:
reverse-proxy:
# ...
ports:
- 5500:80
networks:
- my-net
networks:
my-net:
external:
name: my-net
What happens now is that when I run my-ui and reverse-proxy (each using its own docker-compose up), and I go to http://localhost:5500, I get a Bad Gateway message, and my nginx logs says this:
connect() failed (111: Connection refused) while connecting to
upstream, client: 172.19.0.1, server: , request: "GET / HTTP/1.1",
upstream: "http://172.19.0.5:5402/", host: "localhost:5500"
If I exec into my nginx container and use ping:
ping my-ui
ping 172.19.0.5
Both are successful, but if I want to, for example, curl:
curl -L http://my-ui
curl -L http://my-ui:5402
curl -L http://172.19.0.1
All of them fail with connection refused message. What am I missing here?
PS: I'm not sure, but it might be useful to add that my-ui is a basic vuejs application, running on Webpack dev server.
PS2: I also tried passing host headers etc. but same result
The name of the container (my-ui) resolves to the IP of the container. Therefor you have to provide in upstream the port of the container and not the port you have mapped to the host.
upstream client {
server my-ui:8080;
}
server {
listen 80;
location / {
proxy_pass http://client;
}
}
You could also configure your upstream with the name of your host machine and use the mapped port. (server <name of host>:5402) But this could get quite messy and you would lose the advantage of isolating services with docker networks.
Furthermore you could also remove the port mapping unless you need to access the webservice without reverse proxy:
# ...
services:
reverse-proxy:
# ...
# ports:
# - 5500:80

Suppervisor - php-fpm leads to 502 Bad Gateway

I have a web application based on php and nginx images ... Everything works great until I set a command under the PHP configuration:
command: /usr/bin/supervisord -c /symfony/supervisord.conf
docker-compose.yml
version: '2'
services:
php:
build: docker/php
tty: true
volumes:
- '.:/symfony'
command: /usr/bin/supervisord -c /symfony/supervisord.conf
nginx:
image: nginx:1.11
tty: true
volumes:
- './public/:/symfony'
- './docker/nginx/default.conf:/etc/nginx/conf.d/default.conf'
ports:
- '80:80'
links:
- php
This is my default.conf
server {
server_name ~.*;
location / {
root /symfony;
try_files $uri /index.php$is_args$args;
}
location ~ ^/index\.php(/|$) {
client_max_body_size 50m;
fastcgi_pass php:9000;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME /symfony/public/index.php;
}
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
}
This is my supervisord.conf
[unix_http_server]
file=/tmp/supervisor.sock
[supervisord]
logfile=/tmp/supervisord.log
pidfile=/var/run/supervisord.pid
nodaemon=true
Nginx logs show me:
nginx_1 | 2018/10/02 00:42:36 [error] 11#11: 1 connect() failed
(111: Connection refused) while connecting to upstream, client:
172.23.0.1, server: ~., request: "GET / HTTP/1.1", upstream: "fastcgi://172.23.0.2:9000", host: "127.0.0.1"
As we see, nginx report a 502 Bad Gateway error. If i remove the last line, CMD, everything works fine. If I remove the line and I acess via docker-compose exec php bash and launch the command manually everything work also.
Any Idea why adding that command leads to 502 Bad Gateway ??
Ok I found a solution It was a problem with supervisor. Because each time we launch our service supervisor, the php-fpm service is stopped automatically that's why it should add a configuration that will relaunch the php-fpm but this time from supervisor configuration.
[program:php-fpm]
command = /usr/local/sbin/php-fpm
autostart=true
autorestart=true
For anyone else with similar problem:
Don't forget that command key in docker-compose.yml file overrides default CMD in Dockerfile, therefore that command won't be run.
For example, if php:7.4-fpm final command is CMD php-fpm, it won't be run.
Therefore if you have some custom logic for running after container is ran, don't forget to include it in your command, e.g.:
command: bash -c "php-fpm & npm run dev"

Resources