Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
.aider*
__pycache__/
bedlam.code-workspace
158 changes: 158 additions & 0 deletions docker-openclaw/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
# syntax=docker/dockerfile:1.7
FROM igorhvr/bedlam-ubuntu
LABEL maintainer="Felipe Micaroni Lalli <bedlam@nok.uy>"

ENV DEBIAN_FRONTEND=noninteractive
SHELL ["/bin/bash", "-o", "pipefail", "-c"]

# -------------------------------
# System deps (headless + build tools)
# Bedlam already includes: zsh, curl, git, file, procps, sudo, locales, dialog,
# gnupg, lsb-release, unzip, xz-utils, ca-certificates, nodejs/npm, etc.
# -------------------------------
RUN --mount=type=cache,target=/var/cache/apt \
--mount=type=cache,target=/var/lib/apt \
set -eux; \
apt-get update; \
apt-get install -y --no-install-recommends \
build-essential \
python3 python3-dev python3-pip \
chromium xvfb \
libnss3 libatk-bridge2.0-0 libgtk-3-0 libgbm1 libasound2t64 \
; \
rm -rf /var/lib/apt/lists/*
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

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

The command 'rm -rf /var/lib/apt/lists/*' on line 23 will not have the intended effect because /var/lib/apt is mounted as a cache. The cache mount persists across builds, so this cleanup doesn't actually clear the apt lists within the layer. Either remove this line since the cache mount handles cleanup, or move the rm command to execute outside of the cached mount context.

Copilot uses AI. Check for mistakes.

# -------------------------------
# Install GitHub CLI (gh)
# -------------------------------
RUN --mount=type=cache,target=/var/cache/apt \
--mount=type=cache,target=/var/lib/apt \
set -eux; \
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg \
| dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg; \
chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg; \
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" \
> /etc/apt/sources.list.d/github-cli.list; \
apt-get update; \
apt-get install -y --no-install-recommends gh; \
rm -rf /var/lib/apt/lists/*; \
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

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

The command 'rm -rf /var/lib/apt/lists/*' on line 38 will not have the intended effect because /var/lib/apt is mounted as a cache. The cache mount persists across builds, so this cleanup doesn't actually clear the apt lists within the layer. Either remove this line since the cache mount handles cleanup, or move the rm command to execute outside of the cached mount context.

Copilot uses AI. Check for mistakes.
gh --version

# -------------------------------
# Homebrew (Linuxbrew) – manual, Docker-safe
# -------------------------------
RUN set -eux; \
useradd -m -d /home/linuxbrew -s /bin/bash linuxbrew; \
mkdir -p /home/linuxbrew/.linuxbrew; \
chown -R linuxbrew:linuxbrew /home/linuxbrew

USER linuxbrew
ENV HOME=/home/linuxbrew

RUN set -eux; \
git clone --depth=1 https://github.com/Homebrew/brew /home/linuxbrew/.linuxbrew/Homebrew; \
mkdir -p /home/linuxbrew/.linuxbrew/bin; \
ln -sf ../Homebrew/bin/brew /home/linuxbrew/.linuxbrew/bin/brew; \
eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"; \
brew --version

USER root
ENV HOME=/root

# Make brew usable in shells that *do* load /etc/profile.d
RUN set -eux; \
echo 'eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"' > /etc/profile.d/brew.sh

# Keep env for non-shell callers too (but note Bedlam may reset PATH inside zshrc)
ENV PATH="/home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin:${PATH}"
ENV HOMEBREW_PREFIX="/home/linuxbrew/.linuxbrew"
ENV HOMEBREW_CELLAR="/home/linuxbrew/.linuxbrew/Cellar"
ENV HOMEBREW_REPOSITORY="/home/linuxbrew/.linuxbrew/Homebrew"

# -------------------------------
# Fix Bedlam PATH reset for root zsh
# Bedlam sets: export PATH=/usr/local/sbin:...:/bin (drops brew)
# We re-add Linuxbrew safely (no duplication).
# -------------------------------
RUN set -eux; \
cat <<'EOF' >> /root/.zshrc
# Ensure Linuxbrew is available (Bedlam resets PATH above)
case ":$PATH:" in
*":/home/linuxbrew/.linuxbrew/bin:"*) ;;
*) export PATH="/home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin:$PATH" ;;
esac
EOF

# -------------------------------
# npm reliability settings
# Bedlam already installs nodejs/npm, so only configure.
# -------------------------------
RUN set -eux; \
npm config set fund false; \
npm config set audit false; \
npm config set update-notifier false; \
npm config set progress false; \
npm config set fetch-retries 5; \
npm config set fetch-retry-mintimeout 20000; \
npm config set fetch-retry-maxtimeout 120000

# -------------------------------
# Tooling installs (cached)
# -------------------------------
ENV OPENCLAW_STATE_DIR=/root/.openclaw

RUN --mount=type=cache,target=/root/.npm \
set -eux; \
npm install -g openclaw@latest --no-audit --no-fund; \
npm install -g @google/gemini-cli --no-audit --no-fund; \
npm install -g @openai/codex --no-audit --no-fund; \
npm install -g @anthropic-ai/claude-code --no-audit --no-fund

# -------------------------------
# Headless defaults
# -------------------------------
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

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

The Dockerfile installs Xvfb and the openclaw-start script expects to use a virtual display, but no DISPLAY environment variable is set in the Dockerfile. This means applications relying on DISPLAY won't work unless openclaw-start is explicitly run first. Consider adding 'ENV DISPLAY=:99' to the Dockerfile to set a default display that matches what openclaw-start creates, ensuring consistency across the container environment.

Suggested change
# -------------------------------
# -------------------------------
ENV DISPLAY=:99

Copilot uses AI. Check for mistakes.
ENV CHROME_FLAGS="--window-size=1920,1080 --disable-gpu --no-sandbox"

# -------------------------------
# Copy OpenClaw start script
# -------------------------------
COPY openclaw-start /bin/openclaw-start
RUN chmod 0755 /bin/openclaw-start

# -------------------------------
# OpenClaw banner (do NOT overwrite Bedlam zshrc; append)
# -------------------------------
RUN set -eux; \
cat <<'EOF' >> /etc/zsh/zshrc

# ---- OpenClaw banner (interactive only) ----
if [[ -o interactive ]]; then
echo
echo "OpenClaw quickstart:"
echo " Onboard (first run): openclaw onboard"
echo " Start gateway: openclaw-start"
echo " Gateway UI: http://127.0.0.1:18789/"
echo
echo "Diagnostics & config:"
echo " Environment check: openclaw doctor"
echo " Edit configuration: openclaw configure"
echo " Show current config: openclaw config show"
echo
echo "Agents & context:"
echo " List agents: openclaw agent list"
echo " Use agent: openclaw agent use <name>"
echo " Current agent: openclaw agent current"
echo " List loaded context: openclaw context list"
echo
echo " Help: openclaw help"
echo
fi
EOF

# -------------------------------
# Build-time sanity check: brew must be visible in interactive zsh
# -------------------------------
RUN set -eux; \
zsh -ic 'command -v brew >/dev/null && brew --version >/dev/null'

CMD ["/bin/zsh"]
1 change: 1 addition & 0 deletions docker-openclaw/build
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
sudo DOCKER_BUILDKIT=1 docker build --progress=plain -t igorhvr/openclaw .
12 changes: 12 additions & 0 deletions docker-openclaw/openclaw-start
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/usr/bin/env bash
set -euo pipefail

# Start a virtual display for browser-based flows
echo "[+] Starting virtual display on ${DISPLAY:-:99} (1920x1080x24)"
Xvfb "${DISPLAY:-:99}" -screen 0 1920x1080x24 >/tmp/xvfb.log 2>&1 &
sleep 1

Comment on lines +6 to +8
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

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

The Xvfb process is started in the background without verifying it started successfully. If Xvfb fails to start, the script will continue and the 'openclaw gateway' command may fail with cryptic errors. Consider checking if the Xvfb process is actually running before proceeding, or capturing its PID and verifying it's still alive after the sleep.

Suggested change
Xvfb "${DISPLAY:-:99}" -screen 0 1920x1080x24 >/tmp/xvfb.log 2>&1 &
sleep 1
Xvfb "${DISPLAY:-:99}" -screen 0 1920x1080x24 >/tmp/xvfb.log 2>&1 &
XVFB_PID=$!
sleep 1
if ! kill -0 "${XVFB_PID}" 2>/dev/null; then
echo "[!] Failed to start Xvfb on ${DISPLAY:-:99}. See /tmp/xvfb.log for details." >&2
if [ -s /tmp/xvfb.log ]; then
echo "[!] Xvfb log output:" >&2
cat /tmp/xvfb.log >&2
fi
exit 1
fi

Copilot uses AI. Check for mistakes.
PORT="${OPENCLAW_GATEWAY_PORT:-18789}"

echo "[+] Starting OpenClaw gateway on port ${PORT}"
exec openclaw gateway --port "${PORT}" --verbose
20 changes: 20 additions & 0 deletions docker-openclaw/run
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/bin/sh

# Run OpenClaw in an interactive Bedlam-style container
# - privileged + NET_ADMIN + /dev/net/tun: required for network/tunnel features
# - mount ~/.openclaw to persist config, credentials, and WhatsApp session
# - expose gateway/dashboard ports explicitly (avoid random -P)

sudo docker run \
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

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

The container is created with a fixed name 'openclaw', which will cause failures on subsequent runs if the container already exists. Consider adding the '--rm' flag to automatically remove the container when it exits, or use a more dynamic naming scheme, or document that users should manually remove the container between runs.

Suggested change
sudo docker run \
sudo docker run \
--rm \

Copilot uses AI. Check for mistakes.
--name openclaw \
--hostname openclaw \
--privileged \
-it \
--device /dev/net/tun:/dev/net/tun \
--cap-add=NET_ADMIN \
--cap-add=MKNOD \
Comment on lines +8 to +15
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

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

The docker run invocation uses --privileged in combination with explicit --cap-add=NET_ADMIN and --device /dev/net/tun, which grants the container essentially full host capabilities and goes beyond what appears to be required for tunnel/network features. If an attacker gains code execution inside the container (e.g., via the OpenClaw gateway or the headless browser), --privileged makes host compromise much easier compared to using only the minimal capabilities needed. To reduce the impact of a compromise, drop --privileged if possible and instead grant only the specific capabilities/devices strictly required for your networking use case.

Copilot uses AI. Check for mistakes.
-v "$HOME/.openclaw:/root/.openclaw" \
-p 18789:18789 \
-p 18793:18793 \
igorhvr/openclaw /bin/zsh -i

Loading