Skip to content

desktop: let containers reach this machine's loopback under rootless Podman - #880

Merged
dustywusty merged 3 commits into
dustywusty/local-eval-on-upstreamfrom
dustywusty/linux-podman-host-loopback
Oct 29, 2026
Merged

dustywusty merged 3 commits into
dustywusty/local-eval-on-upstreamfrom
dustywusty/linux-podman-host-loopback

Conversation

@dustywusty

Copy link
Copy Markdown
Collaborator

Follow-up to #852, which was merged into #832's branch: under rootless Podman on Linux, the server container could not reach the person's browser or a local Intelligence.

Root cause

  • Where it came from: desktop: run the server and worker from the published image instead of building on the host #852 (merged into this branch) moved the server from a host process into a container. On main the server runs on the host, so 127.0.0.1 just worked.
  • What broke: two things the server calls on this machine listen on 127.0.0.1 only:
    • the person's OpenBot Browser, deliberately (agent-computer/src/browser-runtime.ts);
    • a local Intelligence.
  • Why only Linux: Docker Desktop and the Podman machines on macOS and Windows forward host.docker.internal to the host's loopback. Rootless Podman on Linux does not:
    • slirp4netns runs with host loopback disabled;
    • Podman 5 starts pasta with --no-map-gw.
  • Why CI didn't catch it: nothing in CI runs the stack under rootless Podman on Linux.

Evidence

Measured on Ubuntu 24.04 (Podman 4.9.3, slirp4netns) and Fedora 44 (Podman 5.8.9, pasta), with a listener bound only to 127.0.0.1 and a container on a Compose network:

Ubuntu (slirp4netns) Fedora (pasta)
Without this change, any address (host.docker.internal, 10.0.2.2, 169.254.1.2, the gateway) unreachable unreachable
With the drop-in plus OPENBOT_HOST_GATEWAY=10.0.2.2, via docker compose against the Podman API service reached reached
Outbound internet unchanged unchanged
A person's own pasta_options / network_cmd_options ({append=true}) kept kept

Measured on both distros: the options only apply to a new rootless network namespace. Written while any container held the namespace, they changed nothing; once the last one stopped, they applied.

The fix

  • engine::local_api: under rootless Podman, the Desktop writes ~/.config/containers/containers.conf.d/90-openbot-host.conf:
    • slirp4netns: allow_host_loopback=true, which serves the host's loopback at its fixed gateway, 10.0.2.2;
    • pasta: --map-host-loopback 10.0.2.2;
    • both appended, so the person's own options are kept. The file is written whole through a sibling file and rename, so Podman never reads half of it.
    • A change restarts the Podman API service this session owns.
  • Start: after a change, Start brings OpenBot's stack down once, so the containers about to start build a new namespace.
  • env::compose: sets OPENBOT_HOST_GATEWAY=10.0.2.2 whenever ENGINE_SOCKET marks rootless Podman. It is purged when the engine changes, so a later Docker setup goes back to host-gateway.
  • docker-compose.yml: the three extra_hosts use host.docker.internal:${OPENBOT_HOST_GATEWAY:-host-gateway}.

This also fixes Bots and a picked harness calling a model endpoint on this machine that listens on loopback only, such as Ollama's default.

Scope and limits

  • User-wide setting: the drop-in lives in the person's Podman configuration, so the loopback mapping is open to their other rootless containers too. Those containers would have to target 10.0.2.2 by number, though: host_containers_internal_ip is deliberately left unset, so their host.containers.internal is unchanged.
  • A shared namespace can delay the fix: if the person's own containers keep the rootless network namespace alive, the options apply only once those stop.
  • A long-running Podman API service the person runs (rather than socket-activated) is reused, as before, and is not restarted.
  • Rootful Docker Engine on Linux has no equivalent setting and is unchanged by this PR.

Tests

  • Rust:
    • drop-in content: both backends, {append=true}, and the shared address;
    • written once, restored when changed, the person's own file untouched;
    • a change restarts only the owned API service and is reported to Start once;
    • OPENBOT_HOST_GATEWAY is set only under rootless Podman and is purged otherwise.
  • tests/compose.test.ts: all three services resolve host.docker.internal to OPENBOT_HOST_GATEWAY when it is set.
  • macOS: cargo fmt --check, cargo clippy --all-targets -D warnings, and cargo test --lib --bins (763 + 191) pass.
  • Linux (Ubuntu 24.04 VM):
    • clippy passes;
    • the same tests pass except two that also fail on the base in that VM, because bun and lsof were not installed;
    • one parallel-run flake in local_eval passed 3/3 when run alone.

…Podman

The server is a container now, and what it calls on this machine listens
only on 127.0.0.1: the person's browser, deliberately, and a local
Intelligence. Docker Desktop and the Podman machines on macOS and Windows
forward host.docker.internal to the host's loopback. Rootless Podman on
Linux does not: slirp4netns runs with host loopback disabled and pasta
with --no-map-gw, so neither was reachable at any address.

- Under rootless Podman, the Desktop writes
  containers.conf.d/90-openbot-host.conf: allow_host_loopback for
  slirp4netns and --map-host-loopback 10.0.2.2 for pasta, both appended so
  the person's own options are kept. A change restarts the API service
  this session owns.
- The first Start after a change brings OpenBot's stack down once, since
  the rootless network namespace keeps its old options while any
  container holds it.
- OPENBOT_HOST_GATEWAY=10.0.2.2 points OpenBot's own services'
  host.docker.internal there. The person's other containers keep their
  host.containers.internal.

Measured on Ubuntu 24.04 (Podman 4.9.3, slirp4netns) and Fedora 44
(Podman 5.8.9, pasta), through Docker Compose and the Podman API service:
a loopback-only listener was unreachable without this and reached with
it, with outbound traffic unaffected.
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 29, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-29T07:49:59.048291Z 6d75ec5 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6d75ec58d4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread desktop/src-tauri/src/main.rs Outdated
The reset was a flag in memory, taken before the teardown. A Start whose
teardown failed had already cleared it, so "Try Start again" skipped the
teardown and left the old rootless network namespace in place; quitting
between writing the drop-in and starting forgot it the same way.

It is now a file beside Podman's configuration, written before the
drop-in changes and removed by a Start only once stack::down succeeded.
@dustywusty
dustywusty merged commit ad11cd5 into dustywusty/local-eval-on-upstream Oct 29, 2026
25 checks passed
@dustywusty
dustywusty deleted the dustywusty/linux-podman-host-loopback branch October 29, 2026 08:17
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.

1 participant