Skip to content

feat(docker): make BACKEND_HOST and FRONTEND_HOST env-configurable#586

Merged
pancacake merged 1 commit into
HKUDS:devfrom
enihcam:feature/bind-host-config
Jun 23, 2026
Merged

feat(docker): make BACKEND_HOST and FRONTEND_HOST env-configurable#586
pancacake merged 1 commit into
HKUDS:devfrom
enihcam:feature/bind-host-config

Conversation

@enihcam

@enihcam enihcam commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Summary

Two new env vars let deployments pin the backend (uvicorn) and frontend (Next.js) to a specific bind address instead of the image-default 0.0.0.0. Defaults preserve current behavior, so the change is non-breaking.

Env var Maps to Default
BACKEND_HOST uvicorn --host 0.0.0.0
FRONTEND_HOST Next.js HOSTNAME (consumed by standalone server.js) 0.0.0.0

Why

When network_mode: host is used (e.g. for the Ollama-on-host-loopback pattern in podman rootless setups), the container processes bind directly on host interfaces. Today uvicorn binds 0.0.0.0:8001 and Next.js binds 0.0.0.0:3782, which exposes both ports to the LAN. With this PR, setting BACKEND_HOST=127.0.0.1 + FRONTEND_HOST=127.0.0.1 restricts both bindings to loopback while keeping host-mode networking intact.

Files changed

  • Dockerfile: two heredoc edits (start-backend.sh, start-frontend.sh). 1 file, +10/-4.

Usage

services:
  deeptutor:
    network_mode: host          # host netns required for the env vars to take effect
    environment:
      - BACKEND_HOST=127.0.0.1
      - FRONTEND_HOST=127.0.0.1

Caveat

Setting BACKEND_HOST=127.0.0.1 while running in bridge mode will silently break the published port forward — uvicorn binds to the container's loopback and the host-side port mapping can't reach it. Only set these env vars together with network_mode: host (or when you intentionally want loopback-only access inside the container's own netns).

Test plan

  • bash -n on both extracted heredocs (pass)
  • Diff reviewed: defaults 0.0.0.0 preserved, no other behavior change
  • Maintainer can validate end-to-end by setting the env vars in a host-mode compose and checking ss -tln shows 127.0.0.1:8001 / 127.0.0.1:3782 instead of 0.0.0.0:...

Related

The production image's start-backend.sh and start-frontend.sh previously
hard-coded --host 0.0.0.0 (uvicorn) and HOSTNAME (Next.js standalone
default). That's fine for bridge-mode deployments where the port
publish binds to the host, but in network_mode: host the container's
processes bind directly on the host's interfaces — exposing :8001 and
:3782 to the LAN.

This change makes both bind addresses env-configurable:

  start-backend.sh:  --host ${BACKEND_HOST:-0.0.0.0}
  start-frontend.sh: export HOSTNAME=${FRONTEND_HOST:-0.0.0.0}

Defaults preserve the current behavior. Setting
BACKEND_HOST=127.0.0.1 and FRONTEND_HOST=127.0.0.1 in compose.yaml
under a host-mode service gives loopback-only bindings.

Note: setting BACKEND_HOST=127.0.0.1 in bridge mode breaks the
port publish (uvicorn binds inside the container's loopback). Use
this env var only with network_mode: host.
pancacake added a commit that referenced this pull request Jun 23, 2026
… knobs

Make the two env vars from #586 discoverable and scope-warn (host-mode
only) in the authoritative container doc.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@pancacake
pancacake merged commit 9506638 into HKUDS:dev Jun 23, 2026
pancacake added a commit that referenced this pull request Jun 23, 2026
… networking

The host-networking note already warns that --network=host exposes the
container ports on the host; point to the BACKEND_HOST/FRONTEND_HOST env vars
(added in #586) as the loopback-only mitigation, with details in
CONTAINERIZATION.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
pancacake pushed a commit that referenced this pull request Jun 27, 2026
…ss keep-id

Removes `user=root` from the [supervisord] section in both production and
development supervisord configs, and rewrites the entrypoint comment to
explain why.

Background: under rootless podman + userns_mode: keep-id, container PID 1
runs as the host user (UID 1000) instead of root. The previous design
explicitly forced supervisord to drop privileges to root (`user=root`),
which works under rootful daemons (PID 1 is root, has CAP_SETUID) but
fails under rootless + keep-id — supervisord sees `user=root` in its
config, tries to setuid(0), lacks CAP_SETUID, and exits with
"Error: Can't drop privilege as nonroot user" (per supervisord
options.py: refuses to drop privileges when not running as root).

Fix: omit `user=` from the [supervisord] section so supervisord inherits
PID 1's UID (root in rootful; UID 1000 in rootless + keep-id). The
backend and frontend programs still drop to the unprivileged deeptutor
user via per-program `user=deeptutor` — setuid(1000) works because
either PID 1 is root (rootful) or PID 1 is already UID 1000 (rootless
keep-id, where the setuid is a no-op). /dev/fd/1,2 ownership matches
PID 1's UID in both runtimes, so supervisord's stdout/stderr writes
succeed without an explicit setuid dance.

Verified locally: clean heredoc indentation; supervisord config parses;
both [supervisord] sections confirmed without `user=root`.

Closes the rootless-podman + read-only-rootfs follow-up to PR #577
(reported by the user after #577 + #586 merged).
vaskoyudha added a commit to vaskoyudha/deeptutor-for-programmer-fork that referenced this pull request Jul 25, 2026
feat(docker): make BACKEND_HOST and FRONTEND_HOST env-configurable

Two opt-in env vars (default 0.0.0.0, non-breaking) let host-network
deployments pin uvicorn and Next.js to a specific bind address — e.g.
127.0.0.1 to keep both off the host LAN when running network_mode: host.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
vaskoyudha added a commit to vaskoyudha/deeptutor-for-programmer-fork that referenced this pull request Jul 25, 2026
… knobs

Make the two env vars from HKUDS#586 discoverable and scope-warn (host-mode
only) in the authoritative container doc.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
vaskoyudha added a commit to vaskoyudha/deeptutor-for-programmer-fork that referenced this pull request Jul 25, 2026
… networking

The host-networking note already warns that --network=host exposes the
container ports on the host; point to the BACKEND_HOST/FRONTEND_HOST env vars
(added in HKUDS#586) as the loopback-only mitigation, with details in
CONTAINERIZATION.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
vaskoyudha added a commit to vaskoyudha/deeptutor-for-programmer-fork that referenced this pull request Jul 25, 2026
…ss keep-id

Removes `user=root` from the [supervisord] section in both production and
development supervisord configs, and rewrites the entrypoint comment to
explain why.

Background: under rootless podman + userns_mode: keep-id, container PID 1
runs as the host user (UID 1000) instead of root. The previous design
explicitly forced supervisord to drop privileges to root (`user=root`),
which works under rootful daemons (PID 1 is root, has CAP_SETUID) but
fails under rootless + keep-id — supervisord sees `user=root` in its
config, tries to setuid(0), lacks CAP_SETUID, and exits with
"Error: Can't drop privilege as nonroot user" (per supervisord
options.py: refuses to drop privileges when not running as root).

Fix: omit `user=` from the [supervisord] section so supervisord inherits
PID 1's UID (root in rootful; UID 1000 in rootless + keep-id). The
backend and frontend programs still drop to the unprivileged deeptutor
user via per-program `user=deeptutor` — setuid(1000) works because
either PID 1 is root (rootful) or PID 1 is already UID 1000 (rootless
keep-id, where the setuid is a no-op). /dev/fd/1,2 ownership matches
PID 1's UID in both runtimes, so supervisord's stdout/stderr writes
succeed without an explicit setuid dance.

Verified locally: clean heredoc indentation; supervisord config parses;
both [supervisord] sections confirmed without `user=root`.

Closes the rootless-podman + read-only-rootfs follow-up to PR HKUDS#577
(reported by the user after HKUDS#577 + HKUDS#586 merged).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants