feat(docker): make BACKEND_HOST and FRONTEND_HOST env-configurable#586
Merged
Conversation
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
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]>
7 tasks
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).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.BACKEND_HOSTuvicorn --host0.0.0.0FRONTEND_HOSTHOSTNAME(consumed by standaloneserver.js)0.0.0.0Why
When
network_mode: hostis used (e.g. for the Ollama-on-host-loopback pattern in podman rootless setups), the container processes bind directly on host interfaces. Today uvicorn binds0.0.0.0:8001and Next.js binds0.0.0.0:3782, which exposes both ports to the LAN. With this PR, settingBACKEND_HOST=127.0.0.1+FRONTEND_HOST=127.0.0.1restricts 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
Caveat
Setting
BACKEND_HOST=127.0.0.1while 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 withnetwork_mode: host(or when you intentionally want loopback-only access inside the container's own netns).Test plan
bash -non both extracted heredocs (pass)0.0.0.0preserved, no other behavior changess -tlnshows127.0.0.1:8001/127.0.0.1:3782instead of0.0.0.0:...Related