Docker-Compose with nginx on different port

Hey guys. I have two docker-compose.yml each with different applications and each with a nginx reverse proxy container. In the one docker-compose the nginx is running on ports 80:80 / 443:443 …so everything is standard and it runs fine. I want to start another application in the second docker compose file and run the nginx container on 81:80 / 445:443. Unfortunately I consistently get 502 bad gateway.

Heres my docker-compose.yml

version: '3.9'

services:
  demo_db:
    image: mongo:7.0.0-rc10
    container_name: demo_database
    restart: always
    ports:
      - "27017:27017"
    volumes:
      - demo_data:/data/db
      - /var/www/demo/backup/backup:/backup/demo
    networks:
      demo_network:

  demo_reverse_proxy:
    image: registry.gitlab.com/demorepo/demo-reverse-proxy:latest
    container_name: demo-reverse-proxy
    restart: always
    tty: true
    volumes:
      - ./demo_nginx.conf:/var/www/demo/demo_proxy.conf
      - /etc/letsencrypt/live/demo.demo.com/fullchain.pem:/etc/nginx/ssl/demo/fullchain.pem
      - /etc/letsencrypt/live/demo.demo.com/privkey.pem:/etc/nginx/ssl/demo/privkey.pem
    ports:
      - "81:80"
      - "445:443"
    depends_on:
      - demo_frontend
    networks:
      demo_network:
        ipv4_address: 172.19.0.10
  demo_frontend:
    container_name: demo_frontend
    image: registry.gitlab.com/demorepo/demo-frontend:latest
    restart: always
    ports:
      - "14440:80"
    networks:
      demo_network:
        ipv4_address: 172.19.0.4
  demo_backend:
    container_name: demo_backend
    image: registry.gitlab.com/demorepo/demo-backend:latest
    restart: always
    ports:
      - "14441:14441"
    depends_on:
      - demo_db
    networks:
      demo_network:
        ipv4_address: 172.19.0.6

volumes:
  demo_data:

networks:
  demo_network:
    driver: bridge
    ipam:
      driver: default
      config:
        - subnet: 172.19.0.0/16

Here is my proxy.conf

  server {
    listen 80;
    server_name demo.demo.com;
    location / {
        return 301 https://$host$request_uri;
    }
  }

    server {
    listen 443 ssl;
    server_name demo.demo.com;

    ssl_certificate /etc/nginx/ssl/demo/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/demo/privkey.pem;

    location / {
      proxy_pass http://demo_frontend;
      add_header Cache-Control 'no-store, no-cache';
      proxy_set_header Host $host;
      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;
    }
    location /api {
        proxy_pass http://demo_backend:14441;
        proxy_set_header Host $host;
        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;
    }
    location ~ /\.(?!well-known).* {
        deny all;
    }

}

Additional information: The certificates are valid and are in the container

What’s the result of curl --include --verbose --location http://localhost:14441?
Since your post is not in any Docker Desktop category, I assume it’s a Linux system.

Hey meyay ! Thanks for your time.

curl --include --verbose --location http://localhost:14440 seems fine:

* Trying 127.0.0.1:14440...

* Connected to localhost (127.0.0.1) port 14440 (#0)

> GET / HTTP/1.1

> Host: localhost:14440

> User-Agent: curl/7.81.0

> Accept: */*

>

* Mark bundle as not supporting multiuse

< HTTP/1.1 200 OK

HTTP/1.1 200 OK

< Server: nginx/1.25.2

**Server**: nginx/1.25.2

< Date: Mon, 11 Sep 2023 20:26:05 GMT

**Date**: Mon, 11 Sep 2023 20:26:05 GMT

< Content-Type: text/html

**Content-Type**: text/html

< Content-Length: 907

**Content-Length**: 907

< Last-Modified: Thu, 07 Sep 2023 19:55:55 GMT

**Last-Modified**: Thu, 07 Sep 2023 19:55:55 GMT

< Connection: keep-alive

**Connection**: keep-alive

< ETag: "64fa2acb-38b"

**ETag**: "64fa2acb-38b"

< Accept-Ranges: bytes

**Accept-Ranges**: bytes

So I would exclude a firewall problem.

And yes you are exactly right…it is an Ubuntu 22.04 server

If the service is reachable by it’s published host port, you confirmed the container port is correct, and the application actually responds with a http staus code 200.

Though, from what I remember domain names are not allowed to have underscore characters. You might want to rename your service to use a dash instead of underscore, and update the hostname in your nginx.conf.

I have tested both variants…it makes no difference

It makes a difference: one is not compliant with the rfc that defines hostnames, the other is not

If the outcome is the same, I have no futher ideas. Judging by your compose file, your nginx.conf and and the fixed hostname in both files, it should work.

I am running another docker-compose.yml with ports 80:80 / 443:443. Could this lead to complications?

We had cases of people running windows container on Windows server with such kind of problems. You can run as many containers using the same container ports as you like, it shouldn’t matter. The host port on the other hand must be unique.

I have set the application to the default port 443:443 and it works fine. The problem is not with the certificates or configurations on the Ubuntu server. Am I doing something wrong when I set the port to 445:443? The port 445 is released by the firewall. I would expect the application in the container to continue listening on 443 and I would not need to change anything in the proxy conf. Also in the docker compose I would keep the port of the frontend running on xxxx:80.

Maybe it is a simple error in thinking?

Hey guys… an update of my problem. The problem was never the configuration. I just wasn’t aware that if the application wasn’t running on the default port, it had to be called through the port. (https://domain.com:port). Is there any way to avoid this !?! Since I want to use multiple ports 44x in the long run a forwarding via iptables to 44x falls out.

It does

If I understand you correctly, you expected the webbrowser find out that you have port 445 open and use that port for specific domains. the default port for HTTP is 80 and the default port for HTTPS is 443. In any other cases you have to add the port after the domain name or ip address. Domains are handled only by the application on server side. Your browser just sends the request to the IP address and also sends the hostname as a HTTP header. If you want use a single port (443) for HTTPS requests, you need a single reverse proxy as a separate project and use a common docker network for the proxy and all the containers you want to be handled by the proxy…

1 Like

Here is a simple Traefike example that demonstrates how Traefik reverse proxy is used with Docker with Configuration Discovery.

Every Docker service you run gets a label with the (sub-)domain used and Traefik will automatically forward requests to the matching service/container inside the Docker network. And on top it will create LetsEncrypt TLS certs for https for every domain.

Traefik is a complex tool, has the advantage that it supports Docker Swarm if you grow to multi nodes. If you just use a single server, nginx-proxy might be easier, you use env vars to declare the domain per service/container (doc). It also supports LE TLS (doc).