[GH-ISSUE #180] [Docs ] - API 502 Bad Gateway - Podman Compatibility - Windows #3644

Closed
opened 2026-07-12 09:11:42 -05:00 by GiteaMirror · 3 comments
Owner

Originally created by @nidorx on GitHub (Jun 6, 2026).
Original GitHub issue: https://github.com/reconurge/flowsint/issues/180

Problem

When running docker-compose.prod.yml with Podman Compose, the frontend nginx fails to resolve the api service hostname, resulting in 502 Bad Gateway on all /api/ requests.

Root cause

The nginx config inside flowsint-app uses Docker's embedded DNS resolver:

resolver 127.0.0.11 valid=10s;

127.0.0.11 is Docker Engine specific - it's a hardcoded IP where Docker runs its internal DNS server inside each container. Podman does not use this address. Instead, Podman's DNS resolver runs on the network gateway (typically 10.89.0.1), which is written into the container's /etc/resolv.conf.

Because 127.0.0.11:53 has nothing listening in a Podman container, DNS resolution fails:

send() failed (111: Connection refused) while resolving, resolver: 127.0.0.11:53
api could not be resolved (110: Operation timed out)

Fix

1. Remove the Docker-specific resolver from nginx.conf

In flowsint-app/nginx.conf, replace the resolver + variable pattern with a direct proxy_pass:

  location /api/ {
-     resolver 127.0.0.11 valid=10s;
-     set $api_upstream http://api:5001;
-     proxy_pass $api_upstream;
+     proxy_pass http://api:5001;
      proxy_http_version 1.1;
      proxy_set_header Host $host;
      ...
  }

This makes nginx resolve api using the system's DNS configuration (/etc/resolv.conf), which Podman sets up correctly.

2. Mount the local nginx.conf into the container

The production compose file pulls a pre-built image from GHCR:

app:
  image: ghcr.io/reconurge/flowsint-app:${FLOWSINT_VERSION:-latest}

Since there is no build: section, the container runs the baked-in nginx.conf from the registry image (which still has 127.0.0.11). Mount the corrected local config as a volume:

app:
  image: ghcr.io/reconurge/flowsint-app:${FLOWSINT_VERSION:-latest}
  volumes:
    - ./flowsint-app/nginx.conf:/etc/nginx/nginx.conf:ro

Then

podman compose -f docker-compose.prod.yml up -d --build --force-recreate

Docker vs Podman DNS comparison

Runtime Resolver IP Source
Docker Engine 127.0.0.11 Hardcoded in Docker daemon
Podman Gateway IP (e.g. 10.89.0.1) Written to /etc/resolv.conf

By removing the hardcoded 127.0.0.11 and letting nginx use the system resolver, the config works on both runtimes.

Trade-off

Using proxy_pass http://api:5001 directly (without resolver + set) means nginx resolves the api hostname once at startup. If the api container is recreated with a different IP, the nginx container must be restarted to pick up the new address. For typical compose deployments this is acceptable.

Originally created by @nidorx on GitHub (Jun 6, 2026). Original GitHub issue: https://github.com/reconurge/flowsint/issues/180 ## Problem When running `docker-compose.prod.yml` with [**Podman Compose**](https://podman.io/), the frontend nginx fails to resolve the `api` service hostname, resulting in `502 Bad Gateway` on all `/api/` requests. ### Root cause The nginx config inside `flowsint-app` uses Docker's embedded DNS resolver: ```nginx resolver 127.0.0.11 valid=10s; ``` `127.0.0.11` is **Docker Engine specific** - it's a hardcoded IP where Docker runs its internal DNS server inside each container. Podman does not use this address. Instead, Podman's DNS resolver runs on the network gateway (typically `10.89.0.1`), which is written into the container's `/etc/resolv.conf`. Because `127.0.0.11:53` has nothing listening in a Podman container, DNS resolution fails: ``` send() failed (111: Connection refused) while resolving, resolver: 127.0.0.11:53 api could not be resolved (110: Operation timed out) ``` ## Fix ### 1. Remove the Docker-specific resolver from `nginx.conf` In `flowsint-app/nginx.conf`, replace the resolver + variable pattern with a direct `proxy_pass`: ```diff location /api/ { - resolver 127.0.0.11 valid=10s; - set $api_upstream http://api:5001; - proxy_pass $api_upstream; + proxy_pass http://api:5001; proxy_http_version 1.1; proxy_set_header Host $host; ... } ``` This makes nginx resolve `api` using the system's DNS configuration (`/etc/resolv.conf`), which Podman sets up correctly. ### 2. Mount the local `nginx.conf` into the container The production compose file pulls a pre-built image from GHCR: ```yaml app: image: ghcr.io/reconurge/flowsint-app:${FLOWSINT_VERSION:-latest} ``` Since there is no `build:` section, the container runs the baked-in `nginx.conf` from the registry image (which still has `127.0.0.11`). Mount the corrected local config as a volume: ```yaml app: image: ghcr.io/reconurge/flowsint-app:${FLOWSINT_VERSION:-latest} volumes: - ./flowsint-app/nginx.conf:/etc/nginx/nginx.conf:ro ``` Then ``` podman compose -f docker-compose.prod.yml up -d --build --force-recreate ``` ### Docker vs Podman DNS comparison | Runtime | Resolver IP | Source | |----------------|-----------------|----------------------------------| | Docker Engine | `127.0.0.11` | Hardcoded in Docker daemon | | Podman | Gateway IP (e.g. `10.89.0.1`) | Written to `/etc/resolv.conf` | By removing the hardcoded `127.0.0.11` and letting nginx use the system resolver, the config works on both runtimes. ### Trade-off Using `proxy_pass http://api:5001` directly (without `resolver` + `set`) means nginx resolves the `api` hostname once at startup. If the `api` container is recreated with a different IP, the nginx container must be restarted to pick up the new address. For typical compose deployments this is acceptable.
GiteaMirror added the bug label 2026-07-12 09:11:42 -05:00
Author
Owner

@dextmorgn commented on GitHub (Jun 8, 2026):

Hey @nidorx,

thank you for this. If you feel like it, could you open a PR ? 🙏

<!-- gh-comment-id:4650289868 --> @dextmorgn commented on GitHub (Jun 8, 2026): Hey @nidorx, thank you for this. If you feel like it, could you open a PR ? 🙏
Author
Owner

@sophymarine commented on GitHub (Jun 19, 2026):

That resolver 127.0.0.11 valid=10s; line in flowsint-app/nginx.conf pulls double duty. It pins nginx to Docker’s embedded DNS and also allows re‑resolution at runtime because proxy_pass is built from a variable. Fine in Docker, where 127.0.0.11 always exists. Podman doesn’t run a DNS listener there, so nginx keeps trying and never resolves api.

Dropping the variable changes the behaviour in a useful way. With proxy_pass http://api:5001; the hostname is resolved once during startup through libc using /etc/resolv.conf. Podman writes that file with the correct nameserver, so the lookup succeeds.

If you later need runtime re‑resolution, I’d template the resolver from /etc/resolv.conf. Hardcoding Docker’s address tends to break the moment the container runtime changes.

<!-- gh-comment-id:4755220263 --> @sophymarine commented on GitHub (Jun 19, 2026): That `resolver 127.0.0.11 valid=10s;` line in `flowsint-app/nginx.conf` pulls double duty. It pins nginx to Docker’s embedded DNS and also allows re‑resolution at runtime because `proxy_pass` is built from a variable. Fine in Docker, where 127.0.0.11 always exists. Podman doesn’t run a DNS listener there, so nginx keeps trying and never resolves `api`. Dropping the variable changes the behaviour in a useful way. With `proxy_pass http://api:5001;` the hostname is resolved once during startup through libc using `/etc/resolv.conf`. Podman writes that file with the correct nameserver, so the lookup succeeds. If you later need runtime re‑resolution, I’d template the resolver from `/etc/resolv.conf`. Hardcoding Docker’s address tends to break the moment the container runtime changes.
Author
Owner

@dextmorgn commented on GitHub (Jun 20, 2026):

fixed with fe8a4a3210

<!-- gh-comment-id:4758837617 --> @dextmorgn commented on GitHub (Jun 20, 2026): fixed with https://github.com/reconurge/flowsint/commit/fe8a4a3210aa792ef3a9bf71a4130480763acf1e
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/flowsint#3644