Docker-Compose, SSL, Nginx - getting 502

I’ve tried working through several examples of getting SSL working with Nginx on here and elsehwere and am currently a bit lost. My current file configurations and the error are all below. Without having a working example, I don’t know which files are right or wrong or how close I am to getting it working.

There’s a very long message about enabling SSL in the default runtime.exs file as well, but I believe I’m meant to ignore it when enabling SSL through nginx? I haven’t seen any of the guides mention it so I’m hoping its not that.

I’m getting a 502 with the following:

project-web-1    | The database for Myapp.Repo has already been created
project-web-1    |
project-web-1    | 07:12:39.218 [info] Migrations already up
project-web-1    |
project-web-1    | 07:12:41.030 [info] Running MyappWeb.Endpoint with cowboy 2.10.0 at 127.0.0.1:4000 (http)
project-web-1    | 07:12:41.044 [info] Access MyappWeb.Endpoint at https://example.com
project-web-1    | Database myapp created.
project-web-1    | 07:12:42.908 [info] Running MyappWeb.Endpoint with cowboy 2.10.0 at 127.0.0.1:4000 (http)
project-web-1    | 07:12:42.922 [info] Access MyappWeb.Endpoint at https://example.com
project-nginx-1  | 2023/08/30 07:12:53 [error] 22#22: *1 connect() failed (111: Connection refused) while connecting to upstream, client: 95.145.175.160, server: example.com, request: "GET / HTTP/1.1", upstream: "http://127.0.0.1:4000/", host: "example.com"
project-nginx-1  | 95.145.175.160 - - [30/Aug/2023:07:12:53 +0000] "GET / HTTP/1.1" 502 559 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36"
project-nginx-1  | 2023/08/30 07:12:53 [error] 22#22: *1 connect() failed (111: Connection refused) while connecting to upstream, client: 95.145.175.160, server: example.com, request: "GET /favicon.ico HTTP/1.1", upstream: "http://127.0.0.1:4000/favicon.ico", host: "example.com", referrer: "https://example.com/"
project-nginx-1  | 95.145.175.160 - - [30/Aug/2023:07:12:53 +0000] "GET /favicon.ico HTTP/1.1" 502 559 "https://example.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36"

My runtime.exs

import Config

  config :myapp, MyappWeb.Endpoint, server: true

if config_env() == :prod do
  config :myapp, Myapp.Repo,
    url: "postgresql://#{(System.get_env("PG_USER"))}:#{(System.get_env("PG_PASSWORD"))}@#{(System.get_env("PG_HOST"))}:#{(System.get_env("PG_PORT"))}/#{(System.get_env("PG_DATABASE"))}",
    pool_size: 10,
    socket_options: if System.get_env("ECTO_IPV6") in ~w(true 1), do: [:inet6], else: []

  config :myapp, MyappWeb.Endpoint,
    url: [host: "example.com" , port: 443, scheme: "https"],
    http: [ip: {127, 0, 0, 1}, port: 4000],
    secret_key_base: System.get_env("SECRET_KEY_BASE")
end

My config.exs

config :myapp,
  ecto_repos: [Myapp.Repo]

config :myapp, MyappWeb.Endpoint,
  url: [host: "example.com"],
  render_errors: [
    formats: [html: MyappWeb.ErrorHTML, json: MyappWeb.ErrorJSON],
    layout: false
  ],
  pubsub_server: Myapp.PubSub,
  live_view: [signing_salt: "vYTu2RHp"]

config :myapp, Myapp.Mailer, adapter: Swoosh.Adapters.Local

config :esbuild,
  version: "0.17.11",
  default: [
    args:
      ~w(js/app.js --bundle --target=es2017 --outdir=../priv/static/assets --external:/fonts/* --external:/images/*),
    cd: Path.expand("../assets", __DIR__),
    env: %{"NODE_PATH" => Path.expand("../deps", __DIR__)}
]

config :logger, :console,
  format: "$time $metadata[$level] $message\n",
  metadata: [:request_id]

config :phoenix, :json_library, Jason

import_config "#{config_env()}.exs"

my docker-compose.yml

version: '3.8'
services:
  web:
    build: .
    ports:
       - '4000:4000'
    depends_on:
       - db
    env_file:
      - Myapp.env
  db:
    image: postgres:latest
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
    ports:
      - "5432:5432"
    restart: always
    volumes:
      - /pg-data:/var/lib/postgresql/data
  nginx:
      image: nginx:latest
      volumes:
        - ./nginx.conf:/etc/nginx/nginx.conf
        - /etc/nginx/ssl:/etc/nginx/ssl
      ports:
        - "80:80"
        - "443:443"
      depends_on:
        - web
      restart: always

my nginx.conf

events {
    worker_connections 1024;
  }
  
  http {
    upstream phoenix {
      server 127.0.0.1:4000;
    }
  
    server {
      listen 80;
      server_name example.com;
      return 301 https://$server_name$request_uri;
    }
  
    server {
      listen  443 ssl;
      server_name example.com;
  
      ssl_certificate /etc/nginx/ssl/fullchain.pem;
      ssl_certificate_key /etc/nginx/ssl/privkey.pem;
  
      location / {
        proxy_redirect off;
        proxy_pass http://phoenix;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
      }
    }
  }

Any info greatly appreciated.

As an update if I set my upstream to the web container of my compose

upstream phoenix {
      server web:4000;
    }

and my http to

http: [ip: {0, 0, 0, 0, 0, 0, 0, 0}, port: 4000],

I fix the 502 and get the connection secure icon.

I don’t know if this is acceptable though as it seems like its probably too open?
All the guides I’ve followed have used 127.0.0.1 so I assume thats the standard method but, I don’t believe any of them are using compose.

Any info appreciated