Skip to content

Fedora podman support#2421

Open
skalawag wants to merge 4 commits into
nanocoai:mainfrom
skalawag:fedora-podman-support
Open

Fedora podman support#2421
skalawag wants to merge 4 commits into
nanocoai:mainfrom
skalawag:fedora-podman-support

Conversation

@skalawag
Copy link
Copy Markdown

@skalawag skalawag commented May 11, 2026

Type of Change

  • Feature skill - adds a channel or integration (source code changes + SKILL.md)
  • Utility skill - adds a standalone tool (code files in .claude/skills/<name>/, no source changes)
  • Operational/container skill - adds a workflow or agent skill (SKILL.md only, no source changes)
  • Fix - bug fix or security fix to source code
  • Simplification - reduces or simplifies source code
  • Documentation - docs, README, or CONTRIBUTING changes only

Description

Adds end-to-end support for installing and running nanoclaw on Fedora (tested
on Fedora 43 and 44) with Podman rootless as the container runtime. No
behavioural change on Debian/Ubuntu + Docker; the existing path is preserved
unchanged when apt-get and get.docker.com are available.

Four logical groups of fixes, one commit each:

1. Installer: detect RPM-based Linux (setup/install-node.sh, setup/install-docker.sh)

  • install-node.sh: branch on apt-get / dnf / yum. Fedora 43+ and RHEL 9+
    ship Node 22 natively (dnf install -y nodejs), so no third-party repo is
    needed; the Debian/NodeSource path is unchanged.
  • install-docker.sh: on dnf/yum systems, install podman,
    podman-docker (provides the /usr/bin/docker shim and sets DOCKER_HOST),
    and the Fedora docker-compose package — which is the real Docker Compose v2
    Go binary, not the Python podman-compose reimplementation. We explicitly
    dnf remove podman-compose because it lacks --wait support and breaks the
    OneCLI installer when present as a weak dep. We also install
    util-linux-script (needed by the Claude auth step: script(1) for PTY
    capture) and slirp4netns (see runtime changes below). podman.socket is
    enabled via systemctl --user enable --now.

2. OneCLI bind host + auto-start (setup/onecli.ts)

  • On Podman the OneCLI installer can't auto-detect a Docker bridge interface,
    so it rejects a missing bind address. Default ONECLI_BIND_HOST=127.0.0.1
    when running on Linux with Podman. Containers reach the host on
    10.0.2.2 via the slirp4netns change below.
  • Podman is daemonless, so restart: unless-stopped in compose has no effect
    after reboot. Generate and systemctl --user enable onecli-compose.service so the OneCLI containers come back up after login.

3. Dockerfile WORKDIR (container/Dockerfile)

09c0e81 introduced WORKDIR /workspace/group. A later refactor (8a12fa6)
renamed the bind-mount target in container-runner.ts from
/workspace/group to /workspace/agent but didn't update the Dockerfile.
Docker silently creates a missing WORKDIR; Podman rootless is stricter and
fails at startup with CouldntReadCurrentDirectory. Aligns Dockerfile to
/workspace/agent.

4. Container runtime: Podman + SELinux + slirp4netns (src/container-runtime.ts, src/container-runner.ts)

Adds host-introspection helpers and applies their results when constructing
docker run args. Docker code path is unchanged.

  • isPodman() — caches the result of docker version regex match.
  • isSelinuxEnforcing() — caches getenforce == "Enforcing".
  • selinuxMountSuffix() — returns :z (read-write) or ,z (added to :ro)
    to relabel bind-mounted host directories with the shared container_file_t
    type so SELinux enforcement can stay on. Applied to both writable and
    readonly mounts.
  • hostGatewayArgs() — on Podman, returns
    --network=slirp4netns:allow_host_loopback=true --add-host=host.docker.internal:10.0.2.2. The default pasta network cannot
    reach the host's loopback from inside the container; slirp4netns can, and
    the literal 10.0.2.2 is required (host-gateway does not resolve under
    slirp4netns). On Docker, returns the existing host-gateway arg.
  • --userns=keep-id is added on Podman so the host UID is preserved inside
    the container; without it --user $HOST_UID:$HOST_GID maps to a sub-UID
    that doesn't own the session files.
  • --workdir /workspace/agent is now passed explicitly (defensive after
    the Dockerfile fix above).
  • relabelOnecliCerts() runs chcon -t container_file_t against the two
    OneCLI CA cert files in /tmp before each spawn. OneCLI writes those files
    with user_tmp_t, which container_t cannot read, and they are mounted
    by OneCLI itself so we can't add :z to the mount spec — relabeling at
    the source is the available lever. No-op on non-SELinux systems.

Testing

  • Clean Fedora 43 Server VM (Docker CE path): full setup completed end-to-end
    with only the install-node.sh change; service survives reboot.
  • Clean Fedora 43 Server VM (Podman path, this PR's stack): full setup
    completed end-to-end; OneCLI containers come up healthy; nanoclaw-v2-*
    service active; both survive reboot.
  • Clean Fedora 44 Server VM (Podman path, this PR's stack): all six setup
    steps (bootstrap, environment, container, onecli, mounts, service)
    completed in 3m51s; Telegram pairing succeeded; first message triggered
    container spawn and agent reply; no SELinux AVC denials in
    ausearch -m avc; services survive reboot.

No regression testing on Debian/Ubuntu was performed in this PR — the changes
are gated on command -v dnf / isPodman() / isSelinuxEnforcing(), so the
existing Debian + Docker path is byte-identical when those return false.

For Skills

  • SKILL.md contains instructions, not inline code (code goes in separate files)
  • SKILL.md is under 500 lines
  • I tested this skill on a fresh clone

skalawag and others added 4 commits May 11, 2026 14:04
  - install-node.sh: add dnf/yum branch; Fedora 43+ and RHEL 9+ ship Node 22
    natively via dnf
  - install-docker.sh: add dnf/yum branch using podman + podman-docker shim
    + docker-compose v2; enable podman.socket; remove podman-compose (lacks
    --wait support)
  - onecli.ts: auto-create onecli-compose.service on podman/systemd systems
    so OneCLI containers survive reboot (podman is daemonless)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The Dockerfile set WORKDIR /workspace/group (introduced in 09c0e81), but
container-runner.ts mounts the group directory at /workspace/agent (renamed
in 8a12fa6). On Docker/Debian the missing WORKDIR is silently created;
Podman rootless fails with CouldntReadCurrentDirectory.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- install-docker.sh: add util-linux-script (script(1) needed for Claude
  auth) and slirp4netns (required for containers to reach host loopback)
- onecli.ts: bind to 127.0.0.1 on Podman; containers reach it via
  slirp4netns allow_host_loopback
- container-runtime.ts: add isPodman(), isSelinuxEnforcing(),
  selinuxMountSuffix(); update hostGatewayArgs() to use slirp4netns +
  10.0.2.2 on Podman; update readonlyMountArgs() to append ,z on SELinux
  enforcing systems
- container-runner.ts: add --userns=keep-id on Podman (rootless UID
  mapping); apply :z suffix on SELinux enforcing bind mounts; relabel
  OneCLI CA cert files with chcon before each spawn (OneCLI writes them
  with user_tmp_t which container_t cannot read under SELinux enforcing)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions github-actions Bot added follows-guidelines PR was created using the current contributing template PR: Fix Bug fix labels May 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

follows-guidelines PR was created using the current contributing template PR: Fix Bug fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant