HolyClaude

CoderLuiiMIT活跃维护

把 Claude Code、网页界面、8 种 AI 命令行工具和无头浏览器打包进 Docker 容器,开箱即用,省去自己搭 AI 编码环境的麻烦。

AI coding workstation: Claude Code + web UI + 8 AI CLIs + headless browser + 50+ tools

v1.6.9发布于 2026-11-06 08:49 UTC2,648star +15 / 7 天275fork同步于 2026-11-10 11:43 UTC

怎么上手

由 README 提炼,执行前请确认
docker compose up
硬件要求按 README 说明

README 未说明显存或 GPU 要求;提供 AMD64 与 ARM64(Apple Silicon、树莓派、AWS Graviton)镜像,Full 与 Slim 两种变体。

支持 Apple Silicon有 Docker 镜像
下载:源码 zip·GitHub Releases(安装包)本站不镜像安装包

项目说明

由 README 自动翻译提炼

一条命令拉起容器化的 AI 开发工作站,省去手动配置 Claude Code 与各类工具的时间

把 Claude Code、网页界面、8 种 AI 命令行工具和无头浏览器打包进 Docker 容器,开箱即用,省去自己搭 AI 编码环境的麻烦。

核心能力

  • 用 docker compose up 一键启动完整 AI 开发环境
  • 内置 CloudCLI 网页界面,可在浏览器里使用 Claude Code
  • 预装 8 个 AI CLI 与 50+ 开发工具
  • 集成 Chromium、Xvfb 与 Playwright 无头浏览器
  • 支持 Claude Max/Pro 订阅 OAuth 或 Anthropic API Key 认证

容易踩的坑

Docker 默认共享内存仅 64MB,Chromium 可能无法启动,需调整 shm 配置;容器内 UID 与宿主机不一致会导致权限拒绝;需通过网页界面完成 OAuth 或填写 API Key 后才能使用 Claude Code。

内容由模型根据 README 生成,可能不完整或不准确,以官方文档为准。看原文 README

最近发版

5 个版本v1.6.9
  1. v1.6.9最新正式版2026-11-06 · 2026-11-06 08:49 UTC

    11/06/2026

    Changed

    • Updated Node to 26.13.0, Claude Code to 2.1.318, Gemini CLI to 0.67.0, Codex to 0.166.0, OpenCode to 1.19.5 and Junie to 4011.1 from official upstream releases.
    • Updated Python to 3.14.10 and Debian Chromium to 156.0.8078.79 on AMD64 and ARM64.
    • Aligned Node and Python Playwright at 1.64.1 and refreshed compatible developer, notification and document tools. Existing CloudCLI features and retained third-party patches remain unchanged.

    Security

    • Added origin checks for the Node binary bundled in Python Playwright, binding its version, architecture, file hash and image layer to the reviewed official wheel.
    • Renewed immutable-input evidence and updated Syft to 1.56.0 and Grype to 0.121.1. Upstream vulnerability findings remain visible as accepted findings, not fixes.
  2. v1.6.82026-10-26 · 2026-10-26 10:17 UTC
    查看更新说明

    10/26/2026

    Changed

    • Updated the runtime to Node 26.12.1 and Python 3.14.9, with Debian Chromium 156.0.8078.47.
    • Updated Claude Code to 2.1.307, Gemini CLI to 0.65.0, OpenAI Codex to 0.163.0, Junie to nightly 3888.1 and OpenCode to 1.19.3.
    • Updated GitHub CLI to 2.103.0 and refreshed compatible npm and Python packages.
    • Removed the Prisma mysql2 and PM2 js-yaml replacement steps. Prisma 7.10.1 supplies mysql2 3.24.4, and PM2 7.1.0 supplies js-yaml 4.3.2 through their official package trees.
    • Updated the optional Full-derived Docker client recipe to Docker CLI 29.9.2 and Compose 5.6.1.
    • Kept Node and Python Playwright aligned at 1.64.0. CloudCLI features and the existing FFmpeg security patches remain unchanged.
    • Kept Go 1.27.1 for the existing custom esbuild binaries. A toolchain update remains deferred.

    Security

    • Refreshed immutable input bindings for v1.6.8 and retained checks of the official Prisma and PM2 dependency trees.
    • Updated Syft to 1.55.0 and Grype to 0.121.0. Dependency reports still list accepted upstream vulnerabilities with their installed versions. These remain unresolved.
  3. v1.6.72026-10-15 · 2026-10-15 06:09 UTC
    查看更新说明

    10/14/2026

    Changed

    • Updated Node to 26.12.0, Claude Code to 2.1.300, Gemini CLI to 0.64.0, Junie to stable 3659.4 and OpenCode to 1.19.0.
    • Updated Chromium to 155.0.8059.39 and aligned Node and Python Playwright at 1.64.0.
    • Updated compatible developer, deployment, Python and optional Docker client tools from official upstream packages.
    • Added disk and swap capacity preparation to published Full-image monitoring before scanner installation, with disk and memory diagnostics retained in the job log.
    • Updated Azure CLI to 2.91.0 while retaining its strict embedded-runtime probes.
    • Kept Go, CloudCLI, Vercel CLI and Pi Coding Agent at their qualified compatibility baselines. See deferred replacements.

    Security

    • Refreshed immutable-input bindings for v1.6.7 and kept dependency scans active.
    • Scans still report accepted upstream vulnerabilities in Vercel's smol-toml 1.5.2, EAS's tar 7.5.19, Azure's cryptography 48.0.1 and other bundled dependencies. These remain unresolved.
    • Kept historical Chromium review decisions bound to their original package version instead of carrying them into Chromium 155.

    Fixed

    • Made immutable-input validation reject stale or untracked Docker and workflow references, including mismatched GitHub Action versions and commit pins.
  4. v1.6.62026-10-10 · 2026-10-10 17:57 UTC
    查看更新说明

    10/10/2026

    Changed

    • Updated Node to 26.11.1, Claude Code to 2.1.296, Gemini CLI to 0.63.0, Codex to 0.162.1, Junie to stable 3579.5 and OpenCode to 1.18.35.
    • Updated compatible developer and deployment tools using official upstream packages.
    • EAS, Netlify and Vercel keep their official dependency trees.
    • Updated Syft to 1.54.1, Grype to 0.120.1 and the artifact upload and download actions to 7.0.2 and 8.0.2.
    • Kept CloudCLI account controls, notifications, proxy paths and existing plugins. See deferred updates for compatibility details.

    Fixed

    • Updated release validation to use v1.6.5 as the source parent while keeping retained artifact checks tied to their original reviewed baseline.
    • Corrected the contributor guide's description of the Docker build stages.

    Security

    • Dependency scans continue. Accepted upstream vulnerabilities remain unresolved; source, artifact integrity and runtime checks still block delivery.
  5. v1.6.52026-10-06 · 2026-10-06 08:39 UTC
    查看更新说明

    10/06/2026

    Changed

    • Updated Node to 26.10.0 and compatible AI CLI, developer-tool and Python packages from official upstream releases.
    • Updated Vercel to official 62.4.0 and Apprise to 2.0.1. Kept legacy email encryption settings working in the notification integration.
    • Added source checks for pull requests and master, plus scheduled released-image dependency scans.
    • Added weekly Docker and GitHub Actions dependency update checks.
    • Kept the existing CloudCLI and plugin artifacts while official replacements lack the required account, reverse-proxy and notification features. See deferred replacements.

    Fixed

    • Corrected the ARM-native build roadmap status and the optional Docker-client image examples.
    • Excluded local execution state from Git and Docker build contexts.
    • Kept the historical Junie applicability guard separate from current-release runtime checks.
    • Fixed Linux advisory checks that could fail when a library lookup closed its output pipe early.

    Security

    • Official Vercel 62.4.0 includes smol-toml 1.5.2, affected by CVE-2026-85730 and GHSA-r4xh-jqrq-34v2. These are accepted upstream vulnerabilities, not fixed.
    • Dependency scans now retain accepted upstream vulnerabilities with raw severity, installed versions and available fixes. Acceptance does not mean fixed. Retained modified third-party components are identified separately from official releases.
    • Kept HolyClaude source checks, artifact integrity, native runtime tests and promotion checks blocking. Historical v1.6.4 approvals remain unchanged.

用户点评

登录用户的真实使用记录,可按版本和硬件筛选
共 0 条

    还没有人点评。第一个说出真实体验的人最有价值。

    README 原文

    未翻译

    🌍 English | Español | Français | Italiano | Português | Deutsch | Русский | हिन्दी | 中文 | 日本語 | 한국어

    HolyClaude

    License: MIT Docker Pulls Full Image Slim Image GitHub Stars Twitter Follow PayPal Buy Me A Coffee Website GitHub Release Issues Contributors

    Stop configuring. Start building.

    One command. Full AI development workstation. Claude Code, web UI, headless browser, 8 AI CLIs, 50+ dev tools — containerized and ready.

    You were going to spend 2 hours setting this up manually. Or you could just docker compose up.

    Works with your existing Claude Code subscription. Max/Pro plan, API key — whatever you have, it just works.

    [!TIP] Stop maintaining. Start building.

    A hosted AI workstation. Always-on Linux box.

    holycode.cloud


    What is this?

    You know the drill. You want Claude Code. But you also want it in a browser. With a headless browser for screenshots and testing. With Playwright configured. With every AI CLI. With TypeScript, Python, deployment tools, database clients, GitHub CLI.

    v1.6.9 updates the bundled AI CLIs and developer tools using official upstream releases. Node and Python Playwright are aligned at 1.64.1, with Debian Chromium 156.0.8078.79 for AMD64 and ARM64. The Docker client remains an opt-in Full-derived recipe; stock images still ship without it. See the deferred replacements for integrations that still need an equivalent official release.

    [!WARNING] Dependency scans still run. Accepted upstream vulnerabilities remain listed with their installed versions, raw severity and available fixes; acceptance does not mean fixed. Retained modified third-party artifacts are identified separately from official releases. HolyClaude source checks, artifact integrity and runtime tests still block delivery. See the dependency policy and the release's scan evidence before deploying.

    Release-sensitive facts are also published in contracts/product-facts.json. The release workflow checks that contract against the Dockerfile and Compose files before building images.

    So you start installing things. One by one. Then Chromium won't launch because Docker's shared memory is 64MB. Then Xvfb isn't configured. Then the UID inside the container doesn't match your host and everything is permission denied. Then you realize Claude Code's installer hangs when WORKDIR is root-owned. Then SQLite locks on your NAS mount. Then—

    HolyClaude is the container I built after solving every single one of those problems.

    You pull it. You run it. You open your browser. You build.

    :credit_card: Use Your Existing Subscription

    This runs the real Claude Code CLI. Not a wrapper. Not a proxy. Not a knock-off.

    Your existing Anthropic account works directly:

    • Claude Max/Pro plan — authenticate through the web UI (OAuth), same as desktop Claude Code
    • Anthropic API key — set it through the web UI, same billing as always
    • No extra cost — HolyClaude is free and open source. You only pay Anthropic for what you use, like you already do.

    HolyClaude operates no credential relay. Bundled tools read credentials from container files, bind mounts, or environment variables, then contact the providers you configure directly.


    Table of Contents

    Section
    :zap:Quick Start
    :computer:Platform Support
    :star2:Why HolyClaude
    :credit_card:Subscription & Authentication
    :package:Image Variants
    :whale:Docker Compose — Quick
    :whale2:Docker Compose — Full
    :wrench:Environment Variables
    :rocket:What's Inside
    :robot:AI CLI Providers
    :mag:Desloppify
    :llama:Using Ollama
    :building_construction:Architecture
    :file_folder:Project Structure
    :floppy_disk:Data & Persistence
    :lock:Permissions
    :shield:Remote Access & Exposure
    :bell:Notifications
    :arrows_counterclockwise:Upgrading
    :construction:Troubleshooting
    :warning:Known Issues
    :hammer_and_wrench:Building Locally
    :bar_chart:Alternatives
    :rocket:Roadmap
    :trophy:Built with HolyClaude
    :handshake:Contributing
    :heart:Support
    :scroll:Third-Party Software
    :page_facing_up:License

    :zap: Quick Start

    1. Create a folder for HolyClaude:

    mkdir holyclaude && cd holyclaude
    

    2. Create a docker-compose.yaml file. Copy one of the templates below:

    3. Pull and start:

    docker compose up -d
    

    4. Open the web UI:

    http://localhost:3001
    

    5. Create a CloudCLI account (takes 10 seconds), sign in with your Anthropic account, and you're live.

    No .env files. No pre-configuration. No reading 40 pages of docs before you can start. It just runs.

    Want to reach it from outside your network? Don't port-forward it. See Remote Access & Exposure — use Tailscale or Cloudflare Tunnel instead.


    :computer: Platform Support

    PlatformStatusNotes
    Linux (amd64)✅ Fully supportedNative performance, recommended
    Linux (arm64)✅ Fully supportedRaspberry Pi 4+, Oracle Cloud, AWS Graviton
    macOS (Docker Desktop)✅ Fully supportedApple Silicon & Intel via Docker Desktop
    Windows (WSL2 + Docker Desktop)✅ Fully supportedRequires WSL2 backend
    Synology / QNAP NAS✅ Fully supportedUse CHOKIDAR_USEPOLLING=true for SMB mounts
    Kubernetes🔜 Coming soonHelm chart planned

    :star2: Why HolyClaude

    I built this because I was tired of re-doing the same setup every time. Installing Claude Code, wiring up a web UI, configuring Chromium in Docker, fixing permission issues, debugging process supervision. Every time.

    HolyClaude bundles those tools in one Docker image.

    HolyClaudeDoing it yourself
    Setup30 seconds1-2 hours (if it goes well)
    Claude CodePre-installed, pre-configured, readyInstall, configure, debug installer hanging, fix WORKDIR
    Web UICloudCLI included with pluginsFind a web UI, install it, configure it, wire it to Claude
    Headless browserChromium + Xvfb + Playwright, configuredInstall Chromium, install Xvfb, configure display :99, fix shm, fix sandbox, fix seccomp...
    AI CLIs8 providers, one containerInstall each one separately across 3 package managers
    Dev tools50+ tools, readyapt-get install / npm i -g / pip install for the next hour
    Process managements6-overlay (auto-restart, graceful shutdown)Write your own supervisord config or hope Docker restart works
    PersistenceBind-mounted tool config and workspace survive rebuildsFigure out Docker volumes, debug "why is this a directory not a file"
    Updatesdocker compose pull && docker compose up -dUpdate 50 tools manually, pray nothing breaks
    Multi-archAMD64 + ARM64Pray your Dockerfile builds on ARM

    Images are available for Linux AMD64 and ARM64.


    :credit_card: Subscription & Authentication

    HolyClaude runs the official Claude Code CLI from Anthropic. Your existing account works out of the box.

    What works:

    Authentication methodHowCost
    Claude Max/Pro plan (subscription)Sign in through CloudCLI web UI — same OAuth flow as desktopYour existing subscription, no extra charge
    Anthropic API keyPaste your API key in the web UIPay-per-use, same Anthropic billing

    What doesn't work:

    Why
    OpenAI API key for ClaudeDifferent company, different API. OpenAI keys work with the Codex CLI (also pre-installed)

    ChatGPT Plus/Pro subscribers: Your subscription works with the Codex CLI. Run codex login --device-auth inside the container to authenticate with your ChatGPT account. If you need Codex's browser callback flow from your host, expose port 1455 in the full compose template below.

    Other AI CLIs included:

    CLIWhat you need
    Gemini CLIGoogle AI API key (GEMINI_API_KEY)
    OpenAI CodexOpenAI API key (OPENAI_API_KEY) or ChatGPT Plus/Pro subscription (codex login --device-auth)
    CursorCursor API key (CURSOR_API_KEY)
    TaskMaster AIUses your AI provider keys (Anthropic, OpenAI, etc.)
    JunieJetBrains account (JetBrains AI subscription)
    OpenCodeConfigure via opencode TUI (OpenRouter and other providers)
    Pi Coding AgentConfigure through pi (supports multiple providers)

    HolyClaude is free and open source. You only pay your AI providers for usage, same as you already do. HolyClaude does not relay provider credentials. Bundled tools read them from container files, bind mounts, or environment variables and contact providers directly.


    :package: Image Variants

    Two flavors. Same quality. Pick your weight class.

    TagWhat you getBest forDocker Hub compressed size
    latestFull toolset listed belowExtra agents and specialist toolsCheck by architecture
    slimCore tools only — Claude installs extras on-demandSmaller VPS, limited disk, metered bandwidthCheck by architecture
    X.Y.ZFull image, pinned versionProduction stability — you control when to updateSame as latest for that release
    X.Y.Z-slimSlim image, pinned versionProduction + small footprintSame as slim for that release
    # Full — batteries included (recommended)
    docker pull coderluii/holyclaude
    
    # Slim — lean and mean
    docker pull coderluii/holyclaude:slim
    

    latest is always the full image. Slim users: don't worry — when you ask Claude to do something that needs a missing tool, it installs it in seconds. You get the same capabilities, just with a smaller initial download.

    Download size varies by release and architecture; check the matching tag on Docker Hub. It reports compressed transfer size. Docker, Synology Container Manager, and NAS filesystems can show a larger unpacked size after layers are extracted. Use slim when disk space or bandwidth matters more than having every tool ready on first boot.


    :whale: Docker Compose — Quick

    The "I just want it running" template. Copy this entire block into a docker-compose.yaml file:

    # ==============================================================================
    # HolyClaude — Quick Start
    # Just run: docker compose up -d
    # Then open: http://localhost:3001
    # ==============================================================================
    
    services:
      holyclaude:
        image: coderluii/holyclaude:latest     # Full image (use :slim for smaller download)
        container_name: holyclaude
        hostname: holyclaude
        restart: unless-stopped
        shm_size: 2g                           # Retained browser default for this release
        network_mode: bridge
        cap_add:
          - SYS_ADMIN                          # Current browser profile for this release; hardening is separate
          - SYS_PTRACE                         # Debugging-related capability
        security_opt:
          - seccomp=unconfined                 # Current browser profile for this release; hardening is separate
        ports:
          - "127.0.0.1:3001:3001"              # CloudCLI web UI, localhost only
        volumes:
          #
          # ./data/claude — Your settings, credentials, API keys, and Claude's memory.
          #                  This is what survives container rebuilds.
          #                  NEVER delete this folder — your auth lives here.
          #
          - ./data/claude:/home/claude/.claude
          #
          # ./workspace — Your code. All projects go here.
          #               Bind-mounted so you can access files from your host.
          #
          - ./workspace:/workspace
        environment:
          - TZ=UTC                             # Your timezone (e.g., America/New_York, Europe/London)
    

    Then:

    docker compose up -d
    

    Open http://localhost:3001. Create a CloudCLI account. Sign in with your Anthropic account. Build something.

    That's the whole setup. You're done.

    Why these browser caps? This release keeps HolyClaude's current browser container profile in place. Chromium does not universally require SYS_ADMIN, SYS_PTRACE, or seccomp=unconfined, and SYS_PTRACE is debugging-related. Keep the web UI bound to 127.0.0.1 unless you put a real private tunnel or access layer in front of it. Treat any hardening pass as a separate change.

    Why shm_size: 2g? Docker gives containers 64MB of shared memory by default. HolyClaude keeps 2GB as the retained browser default for this release because Chromium uses /dev/shm heavily for tab rendering. At 64MB, tabs crash randomly. For heavy browser use (many tabs, complex pages), increase to 4GB.


    :whale2: Docker Compose — Full

    Same image, every knob exposed. Copy this entire block into a docker-compose.yaml file:

    # ==============================================================================
    # HolyClaude — Full Configuration
    # All options documented inline.
    # Detailed docs: https://github.com/CoderLuii/HolyClaude/blob/master/docs/configuration.md
    # ==============================================================================
    
    services:
      holyclaude:
        image: coderluii/holyclaude:latest     # Full image (use :slim for smaller download)
        container_name: holyclaude
        hostname: holyclaude
        restart: unless-stopped
        shm_size: 2g                           # Chromium shared memory — increase to 4g for heavy browser use
        network_mode: bridge
        cap_add:
          - SYS_ADMIN                          # Current browser profile for this release; hardening is separate
          - SYS_PTRACE                         # Debugging-related capability (strace, lsof)
        security_opt:
          - seccomp=unconfined                 # Current browser profile for this release; hardening is separate
        ports:
          #
          # CloudCLI web UI — this is the only port you need.
          # Override the host-side port from `.env` if 3001 is already in use.
          #
          - "127.0.0.1:${HOLYCLAUDE_HOST_PORT:-3001}:3001"
          #
          # Dev server ports — uncomment as needed.
          # These let you access dev servers running inside the container from your host browser.
          #
          # - "127.0.0.1:3000:3000"            # Next.js / Express
          # - "127.0.0.1:4321:4321"            # Astro
          # - "127.0.0.1:5173:5173"            # Vite
          # - "127.0.0.1:8787:8787"            # Wrangler (Cloudflare Workers)
          # - "127.0.0.1:9229:9229"            # Node.js debugger
          # - "127.0.0.1:1455:1455"            # Codex auth callback port
          # - "127.0.0.1:2222:22"              # Optional SSH, localhost/VPN only
          # - "127.0.0.1:60000-60010:60000-60010/udp"  # Optional Mosh UDP range
        volumes:
          #
          # PERSISTENT DATA
          #
          # ./data/claude — Settings, credentials, API keys, Claude's memory file.
          #                  Survives container rebuilds. NEVER delete this folder.
          #                  Override the host path from `.env` if you want it elsewhere.
          #
          - ${HOLYCLAUDE_HOST_CLAUDE_DIR:-./data/claude}:/home/claude/.claude
          #
          # ./workspace — Your code and projects. Everything you build goes here.
          #               Accessible from your host machine.
          #               Override the host path from `.env` if you want a different root.
          #
          - ${HOLYCLAUDE_HOST_WORKSPACE_DIR:-./workspace}:/workspace
          #
          # OPTIONAL SSH/MOSH REMOTE SHELL
          # Keep authorized_keys outside .claude and /workspace. Mount it read-only.
          #
          # - ./data/ssh/authorized_keys:/run/holyclaude-ssh/authorized_keys:ro
          # - holyclaude-ssh:/var/lib/holyclaude-ssh
        environment:
          #
          # TIMEZONE
          # Full list: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
          #
          - TZ=UTC
          #
          # PERFORMANCE
          # Node.js heap memory limit in MB. Increase if you work on large monorepos
          # and hit out-of-memory errors. 4096 (4GB) is a solid default.
          #
          - NODE_OPTIONS=--max-old-space-size=4096
          #
          # USER MAPPING
          # Docker-style UID/GID remapping. Run `id -u` and `id -g` on your host.
          # Rootless Podman users should use docker-compose.podman-rootless.yaml instead.
          #
          - PUID=1000
          - PGID=1000
          #
          # SMB/CIFS NETWORK MOUNTS
          # Only enable these if your volumes are on a NAS, Samba share, or CIFS mount.
          # They enable polling-based file watching since network mounts don't support inotify.
          # Leave commented out for local storage — polling uses more CPU.
          #
          # - CHOKIDAR_USEPOLLING=1
          # - WATCHFILES_FORCE_POLLING=true
          #
          # NOTIFICATIONS (optional)
          # Get notified when Claude finishes a task or hits an error.
          # Uses Apprise — supports 100+ services. Also requires creating a flag file
          # inside the container: touch ~/.claude/notify-on
          #
          # - NOTIFY_DISCORD=discord://webhook_id/webhook_token
          # - NOTIFY_TELEGRAM=tgram://bot_token/chat_id
          # - NOTIFY_PUSHOVER=pover://user_key@app_token
          # - NOTIFY_SLACK=slack://token_a/token_b/token_c
          # - NOTIFY_EMAIL=mailto://user:[email protected][email protected]
          # - NOTIFY_GOTIFY=gotify://hostname/token
          # - NOTIFY_URLS=                                   # catch-all: comma-separated Apprise URLs
          #
          # AI PROVIDER KEYS (optional)
          # Claude Code can authenticate via web UI (OAuth) or ANTHROPIC_API_KEY.
          # Set these if you want to use additional AI CLIs or API-based auth.
          #
          # - GEMINI_API_KEY=your_key
          # - OPENAI_API_KEY=your_key
          # - CURSOR_API_KEY=your_key
          #
          # WEB UI BASE PATH (optional)
          # Use only when a reverse proxy mounts HolyClaude below a path.
          # Example: Tailscale Serve --set-path=/holyclaude
          # Do not add a trailing slash.
          #
          # - HOLYCLAUDE_BASE_PATH=/holyclaude
          #
          # CODEX PERMISSION MODES (optional)
          # CloudCLI Codex chat uses this only when a request omits permissionMode.
          # The current browser client sends permissionMode explicitly.
          # Raw codex CLI reads HOLYCLAUDE_CODEX_CLI_PERMISSION_MODE only when first creating ~/.codex/config.toml.
          # Valid values: default, acceptEdits, bypassPermissions. Recommended: acceptEdits.
          # bypassPermissions gives full access with no approval. Use it only for trusted local workspaces.
          #
          # - HOLYCLAUDE_CODEX_CHAT_PERMISSION_MODE=acceptEdits
          # - HOLYCLAUDE_CODEX_CLI_PERMISSION_MODE=acceptEdits
          #
          # SSH/MOSH REMOTE SHELL (optional, disabled by default)
          # Keep this behind localhost, VPN, Tailscale, or a firewall.
          #
          # - HOLYCLAUDE_SSH_ENABLE=false
          # - HOLYCLAUDE_SSH_AUTHORIZED_KEYS=/run/holyclaude-ssh/authorized_keys
          # - HOLYCLAUDE_SSH_HOST_KEYS_DIR=/var/lib/holyclaude-ssh/host_keys
          # - HOLYCLAUDE_MOSH_ENABLE=false
          # - HOLYCLAUDE_MOSH_UDP_START=60000
          # - HOLYCLAUDE_MOSH_UDP_END=60010
    
    # volumes:
    #   holyclaude-ssh:
    

    Then:

    docker compose up -d
    

    If you want to change the host-side port or bind-mount paths without editing compose, copy .env.example to .env and set:

    HOLYCLAUDE_HOST_PORT=3003
    HOLYCLAUDE_HOST_CLAUDE_DIR=./data/claude
    HOLYCLAUDE_HOST_WORKSPACE_DIR=./workspace
    

    These values are read by Docker Compose on the host. They are not container environment variables.

    What each section controls:

    SectionWhat it doesWhen to change it
    TimezoneContainer clockAlways — set to your local TZ
    PerformanceNode.js memory ceilingOnly if you hit OOM errors on large projects
    User mappingFile permissions between container and hostDocker users: match id -u and id -g. Rootless Podman users: use the Podman compose file below.
    SMB/CIFSFile watcher polling modeOnly if your volumes live on a NAS or network share
    NotificationsPush alerts via Apprise (Discord, Telegram, Slack, Email, 100+ services)If you want to walk away and know when your AI agents are done
    AI providersAPI keys for Gemini, Codex, Cursor, Junie, OpenCodeIf you want to use AI CLIs other than Claude

    Every single environment variable is optional. The container runs perfectly with just TZ=UTC. Everything else has sensible defaults or is handled through the web UI.


    :wrench: Environment Variables

    The complete reference. Every variable, what it defaults to, what it does.

    VariableDefaultWhat it does
    TZUTCContainer timezone
    PUID1000Container user ID for Docker-style UID/GID remapping
    PGID1000Container group ID for Docker-style UID/GID remapping
    NODE_OPTIONSFull Compose: --max-old-space-size=4096Optional Node.js heap limit. The quick Compose file and raw image do not set a heap-size default.
    HOLYCLAUDE_BASE_PATH(unset)Optional web UI subpath such as /holyclaude for Tailscale Serve --set-path or reverse proxies
    GIT_USER_NAMEHolyClaude UserGit commit author, seeded only when the persisted global config has no value
    GIT_USER_EMAIL[email protected]Git commit email, seeded only when the persisted global config has no value
    CHOKIDAR_USEPOLLING(unset)Set to 1 for SMB/CIFS — enables polling file watchers
    WATCHFILES_FORCE_POLLING(unset)Set to true for SMB/CIFS — enables Python polling
    NOTIFY_DISCORD(unset)Discord webhook URL for notifications
    NOTIFY_TELEGRAM(unset)Telegram bot URL for notifications
    NOTIFY_PUSHOVER(unset)Pushover URL for notifications
    NOTIFY_SLACK(unset)Slack webhook URL for notifications
    NOTIFY_EMAIL(unset)Email (SMTP) URL for notifications
    NOTIFY_GOTIFY(unset)Gotify URL for notifications
    NOTIFY_URLS(unset)Catch-all — comma-separated Apprise URLs
    ANTHROPIC_API_KEY(unset)Anthropic API key (alternative to web UI OAuth)
    ANTHROPIC_AUTH_TOKEN(unset)Anthropic auth token (alternative to API key, or set to ollama for Ollama)
    ANTHROPIC_BASE_URL(unset)Custom Anthropic API endpoint (proxies, private deployments, or Ollama's Anthropic-compatible API)
    CLAUDE_CODE_USE_BEDROCK(unset)Set to 1 to use Amazon Bedrock backend
    CLAUDE_CODE_USE_VERTEX(unset)Set to 1 to use Google Vertex AI backend
    GEMINI_API_KEY(unset)Google Gemini API key
    OPENAI_API_KEY(unset)OpenAI API key (for Codex CLI, or use codex login --device-auth for ChatGPT subscription)
    CURSOR_API_KEY(unset)Cursor API key
    HOLYCLAUDE_CODEX_CHAT_PERMISSION_MODEacceptEdits fallbackCloudCLI Codex chat fallback when a request omits permissionMode. The current browser client sends an explicit value. Valid: default, acceptEdits, bypassPermissions
    HOLYCLAUDE_CODEX_CLI_PERMISSION_MODEdefaultRaw codex CLI first-boot mode for new ~/.codex/config.toml only. Valid: default, acceptEdits, bypassPermissions
    HOLYCLAUDE_DESLOPPIFY_SETUPoffOptional Desloppify global skill setup. Valid: off, all, claude, codex, gemini, opencode, or comma-separated subsets
    HOLYCLAUDE_SSH_ENABLEfalseEnables the optional sshd service when a safe authorized_keys mount is present
    HOLYCLAUDE_SSH_AUTHORIZED_KEYS/run/holyclaude-ssh/authorized_keysRead-only public-key file for SSH login as claude; must not live under .claude or /workspace
    HOLYCLAUDE_SSH_HOST_KEYS_DIR/var/lib/holyclaude-ssh/host_keysRoot-owned SSH host key directory; mount /var/lib/holyclaude-ssh to keep fingerprints stable after recreate
    HOLYCLAUDE_MOSH_ENABLEfalseAllows mosh-server for SSH sessions when UDP ports are mapped
    HOLYCLAUDE_MOSH_UDP_START60000First UDP port Mosh may use
    HOLYCLAUDE_MOSH_UDP_END60010Last UDP port Mosh may use

    :rocket: What's Inside

    This is not a minimal container. This is an entire development workstation.

    Both variants (full + slim)

    PackageWhat it's for
    typescript, tsxTypeScript compilation and execution
    pnpmFast, disk-efficient package manager
    vite, esbuildLightning-fast build tools
    eslint, prettierCode quality and formatting
    serve, nodemonStatic file server, auto-restart dev server
    concurrentlyRun multiple scripts in parallel
    dotenv-cliLoad env vars from .env files
    PackageWhat it's for
    requests, httpxHTTP clients
    beautifulsoup4, lxmlWeb scraping and HTML parsing
    PillowImage processing (pre-compiled — no waiting)
    pandas, numpyData manipulation (pre-compiled — seriously, you don't want to pip install these at runtime)
    openpyxlRead/write Excel files
    python-docxRead/write Word documents
    jinja2, markdownTemplating and markdown rendering
    pyyaml, python-dotenvConfig file parsing
    rich, click, tqdmBeautiful CLIs and progress bars
    desloppify, bandit, tree-sitterCode-quality scans, Python security checks, parser-backed code analysis
    playwrightBrowser automation (Python and Node 1.64.1 are baked into both images)
    pytest, pytest-asyncio, flake8Python tests, async tests, and linting
    aiomqtt, aiohttpAsync MQTT and HTTP clients
    ToolWhat it's for
    git, ghVersion control + GitHub CLI (PRs, issues, releases from the terminal)
    ripgrep (rg), fd, fzfBlazing-fast search — Claude uses these constantly
    bat, tree, jqBetter cat (syntax highlighting), directory trees, JSON processing
    curl, wgetHTTP downloads
    nano, shellcheckTerminal editing and Bash linting
    yq, digMike Farah's YAML processor and DNS queries
    atuinShell history client; installed without account setup or shell integration
    tmuxTerminal multiplexer — run things in the background
    htop, lsof, straceProcess monitoring and debugging
    imagemagickImage conversion (convert, identify, mogrify)
    chromiumHeadless browser — screenshots and Playwright; /usr/bin/chromium stays the supported wrapper
    psql, redis-cli, sqlite3, mysql, mysqldumpDatabase clients; MySQL-compatible commands use Debian's MariaDB client
    openssh-client, openssh-server, moshSSH out, and optional key-only SSH/Mosh access into the container
    CLICommandVersionWhat it's for
    Claude Codeclaude2.1.318The main event — you're running inside this
    Gemini CLIgemini0.67.0Google's AI coding agent
    OpenAI Codexcodex0.166.0OpenAI's coding agent
    Cursorcursor2026.09.15-d2fe57eCursor's AI agent
    TaskMaster AItask-master0.43.1Task planning and orchestration

    Five AI CLIs ship in both full and slim. The full image adds Junie, OpenCode, and Pi below, for eight AI CLIs total.

    Full image only (additional packages)

    The full image includes everything above, plus:

    CLICommandVersionWhat it's for
    Juniejunie4011.1JetBrains' AI coding agent
    OpenCodeopencode1.19.5Open source AI agent (OpenRouter and other providers)
    Pi Coding Agentpi0.85.1Minimal agent harness (multiple providers)
    PackageWhat it's for
    wrangler, @cloudflare/next-on-pagesCloudflare Workers deployment
    vercelVercel deployment
    netlify-cliNetlify deployment
    azAzure CLI for cloud deployment and management
    prisma, drizzle-kitThe two most popular Node.js ORMs
    pm2Production process manager
    eas-cliExpo / React Native builds
    lighthouse, @lhci/cliPerformance auditing (full image only; Chromium is already there)
    sharp-cliImage processing CLI
    json-server, http-serverMock REST APIs, static file serving
    @marp-team/marp-cliMarkdown to presentation slides
    PackageWhat it's for
    reportlab, weasyprint, cairosvg, fpdf2, PyMuPDF, img2pdfPDF generation, reading, conversion, and merging libraries.
    xlsxwriter, xlrdExcel formats beyond what openpyxl covers
    matplotlib, seabornData visualization and charts
    python-pptxPowerPoint generation
    fastapi, uvicornPython web framework
    PackageWhat it's for
    pandocConvert between any document format (markdown, HTML, PDF, docx, epub...)
    ffmpegVideo and audio processing (extract, convert, transcode)
    libvips-devHigh-performance image processing library

    Slim users: Missing a package? Ask Claude. It installs npm/pip packages in seconds. System packages (pandoc, ffmpeg) take 1-2 minutes. You get the same capabilities — the full image just has zero wait time.


    :robot: AI CLI Providers

    The full image ships eight AI CLIs. The slim image ships the five core CLIs.

    ProviderCommandHow to authenticateSubscription works?
    Claude CodeclaudeCloudCLI web UI (OAuth)Yes — Max/Pro plan or API key
    Gemini CLIgeminiGEMINI_API_KEY env varAPI key (pay-per-use)
    OpenAI CodexcodexOPENAI_API_KEY or codex login --device-authYes — ChatGPT Plus/Pro/Team/Enterprise or API key
    CursorcursorCURSOR_API_KEY env varAPI key
    TaskMaster AItask-masterUses existing AI provider keysWorks with configured keys
    JuniejunieJetBrains AI subscriptionJetBrains account required, full image only
    OpenCodeopencodeConfigure via TUIOpenRouter and other providers, full image only
    Pi Coding AgentpiConfigure through PiSupports multiple providers, full image only

    Claude Code is the primary CLI. The others are there because sometimes you want a second opinion, or a specific model's strengths, or you're comparing outputs. Having all of them one Tab away is the whole point.

    OpenCode is the full-image path for OpenRouter and multi-provider model routing. Configure it inside opencode; free model availability depends on OpenRouter and provider account limits, not HolyClaude.


    :mag: Desloppify

    Desloppify ships in both images as the desloppify command. It is passive by default. HolyClaude does not run scans, create .desloppify/, edit .gitignore, or change your mounted workspace unless you run Desloppify yourself.

    Use it inside a project:

    desloppify scan --path .
    desloppify next
    

    After you use scans in a project, add .desloppify/ to that project's .gitignore.

    Optional global skill setup is controlled by HOLYCLAUDE_DESLOPPIFY_SETUP.

    ValueBehavior
    offDefault. No global skill setup. The CLI is still installed.
    claudeRuns desloppify setup --interface claude at container start.
    codexRuns desloppify setup --interface codex at container start.
    geminiRuns desloppify setup --interface gemini at container start.
    allExpands to claude,codex,gemini.
    claude,codexAny comma-separated subset of claude, codex, and gemini.
    opencodeFull image only. Sets up the OpenCode-native global skill path.

    OpenCode can also discover Claude-compatible skills from ~/.claude/skills, so all does not include opencode. Do not combine claude and opencode in automatic setup; HolyClaude warns and skips opencode to avoid duplicate skill discovery. If OPENCODE_CONFIG_DIR is set, HolyClaude also skips automatic OpenCode setup because Desloppify writes to the standard ~/.config/opencode path.

    Desloppify also supports these manual upstream targets if you want to configure them yourself: cursor, copilot, windsurf, qwen, amp, rovodev, droid, and hermes.


    :llama: Using Ollama

    HolyClaude works with Ollama as an alternative to an Anthropic subscription. The supported setup path is ANTHROPIC_AUTH_TOKEN=ollama plus ANTHROPIC_BASE_URL=<your Ollama endpoint>.

    See the full setup guide: docs/ollama.md


    :building_construction: Architecture

    graph TB
        subgraph Docker Container
            EP["entrypoint.sh"] --> CP["Persist Git and gh config\n(every boot)"]
            CP --> BS["bootstrap.sh\n(first boot only)"]
            EP --> S6["s6-overlay\n(PID 1)"]
            S6 --> CC["CloudCLI\n(:3001)"]
            S6 --> XV["Xvfb\n(:99)"]
            S6 -. optional .-> SSH["sshd\n(:22)"]
            CC --> CLAUDE["Claude Code CLI"]
            CLAUDE --> TOOLS["Dev Tools\n(Node, Python, Git...)"]
            CLAUDE --> CHROME["Chromium\n(headless)"]
            XV -.-> CHROME
        end
    
        subgraph Host
            DATA["./data/claude"] -.->|bind mount| HOME["~/.claude"]
            WS["./workspace"] -.->|bind mount| WORK["/workspace"]
        end
    
        USER["Browser"] -->|":3001"| CC
    
        style S6 fill:#2d3748,color:#fff
        style CC fill:#6366f1,color:#fff
        style CLAUDE fill:#f59e0b,color:#000
    

    How the pieces fit together

    1. Container starts — entrypoint.sh runs as root for Docker and remaps UID/GID there. In rootless Podman keep-id mode, it skips root-only repairs because the container is already running as the target user. In both paths it restores the saved Claude Code session and prepares persistent Git and GitHub CLI configuration before checking if this is a first boot.

    2. Every boot — HolyClaude links global Git config, XDG Git config, and GitHub CLI config into the existing .claude mount. Missing identity values are seeded without replacing manual changes.

    3. First boot only — bootstrap.sh copies default settings and the memory template, then creates .holyclaude-bootstrapped. Your customizations are safe from that point on.

    4. s6-overlay takes over as PID 1 — This isn't supervisord. It's s6-overlay, purpose-built for Docker. Supervises CloudCLI, Xvfb, Claude session sync, and optional sshd when you explicitly enable it. Auto-restarts on crash. Forwards signals. Reaps zombies. Shuts down gracefully.

    5. CloudCLI serves the web UI — Port 3001. Browser-based interface to Claude Code with project management, multiple sessions, and plugins (project stats + web terminal included).

    6. Xvfb provides a compatibility display — Xvfb stays available at :99 for tools that use a headed display. Modern headless Chromium, Playwright, and Lighthouse do not universally require Xvfb.

    See docs/architecture.md for the full technical deep-dive — including why we chose s6 over supervisord, why plugins are baked into the image, and why runuser instead of su.


    :file_folder: Project Structure

    holyclaude/
    ├── .github/                 # CI/CD workflows, issue & PR templates
    │   ├── FUNDING.yml          # Sponsor/donation links
    │   ├── ISSUE_TEMPLATE/      # Bug report, feature request, package request
    │   ├── pull_request_template.md
    │   ├── SECURITY.md          # Security policy
    │   └── workflows/           # Docker build & push automation
    ├── assets/                  # Logo and banner images
    ├── config/                  # Claude Code configuration
    │   ├── claude-memory-full.md
    │   ├── claude-memory-slim.md
    │   └── settings.json
    ├── docs/                    # Extended documentation
    │   ├── architecture.md
    │   ├── CHANGELOG.md
    │   ├── configuration.md
    │   ├── dockerhub-description.md
    │   ├── ollama.md
    │   └── troubleshooting.md
    ├── scripts/                 # Container lifecycle scripts
    │   ├── bootstrap.sh         # First-run setup
    │   ├── entrypoint.sh        # Container entrypoint
    │   └── notify.py            # Notification helper (Apprise)
    ├── s6-overlay/              # Process supervision (s6-rc services)
    ├── Dockerfile               # Multi-stage build
    ├── docker-compose.yaml      # Quick start (minimal config)
    ├── docker-compose.full.yaml # Full config (all options)
    ├── docker-compose.podman-rootless.yaml # Rootless Podman keep-id profile
    ├── LICENSE
    └── README.md
    

    :floppy_disk: Data & Persistence

    WhatWhere (container)Where (host)Survives rebuild?
    Claude settings and persisted tool config/home/claude/.claude./data/claudeYes
    Claude Code session (OAuth, onboarding)/home/claude/.claude.json./data/claude/.claude.json.persistYes
    Git global and XDG configuration/home/claude/.gitconfig, /home/claude/.config/git./data/claude/.gitconfig, ./data/claude/.config/gitYes
    GitHub CLI configuration and authentication/home/claude/.config/gh./data/claude/.config/ghYes
    Bash aliases/home/claude/.bash_aliases./data/claude/.bash_aliasesYes
    Your code and projects/workspace./workspaceYes
    CloudCLI account/home/claude/.cloudcli(container only by default — see below)No (opt-in available)

    HolyClaude restores the saved Claude Code session before startup can create a fresh default file. That keeps container rebuilds and recreates from replacing a real OAuth/API session with onboarding state.

    What survives docker compose down && docker compose up:

    • File-based Anthropic authentication and Claude Code API-key settings
    • Claude Code settings, memory (CLAUDE.md), and OAuth session (no re-login)
    • All your code in ./workspace
    • Git global configuration, aliases, and XDG Git settings
    • GitHub CLI configuration and authentication
    • Bash aliases saved in ~/.bash_aliases
    • Codex and Gemini file-based config and authentication stored below /home/claude/.claude (since v1.1.7). Cursor uses .claude/.cursor only when HolyClaude creates the managed alias; an existing real directory or custom link remains user-managed, so inspect and migrate it before relying on .claude persistence. Environment-provided keys remain in your Compose or host environment.

    What you'll redo (10 seconds):

    • CloudCLI web account — quick signup, that's it (unless you opt into persistence below)

    Re-triggering first-boot setup:

    # Delete the sentinel file — NOT the whole folder
    rm ./data/claude/.holyclaude-bootstrapped
    docker compose restart holyclaude
    

    Protect ./data/claude/. It contains saved Claude Code sessions and may now contain GitHub credentials in .config/gh/hosts.yml. Do not commit it, share it broadly, or place it in an unencrypted backup. Delete only the specific state you intend to reset.

    Persisting the CloudCLI account (optional, local storage only)

    By default, the CloudCLI account database (~/.cloudcli) is container-local and gets wiped on rebuild. Re-creating the account takes 10 seconds, so most people leave it as-is.

    CloudCLI is a single-user service. Remote access shares the same CloudCLI account, /workspace, and mounted credential context; it does not create separate users or tenant isolation.

    If you want it to survive rebuilds, add a named Docker volume to your compose file:

    services:
      holyclaude:
        volumes:
          - ./data/claude:/home/claude/.claude
          - ./workspace:/workspace
          - cloudcli-data:/home/claude/.cloudcli   # add this line
    
    volumes:
      cloudcli-data:                                # and this block
    

    HolyClaude prepares this directory before CloudCLI starts. Fresh Docker volumes inherit the image's claude:claude ownership. Existing volumes are repaired to the configured PUID/PGID during normal root-starting Docker startup. If the mount is read-only or cannot be repaired, startup stops with the exact path and UID/GID instead of letting CloudCLI repeat unable to open database file.

    For rootless Podman, use docker-compose.podman-rootless.yaml. Its keep-id mapping and :Z labels let the existing host user write the mounted state without a privileged ownership repair. :Z handles SELinux labeling; :U rewrites host ownership and is not the default.

    Keep CloudCLI's SQLite database off network shares (NAS, SMB/CIFS, NFS). Network filesystem locking can cause database is locked errors. Use a named volume backed by the default local driver without remote mount options, or a local-disk bind mount. A volume name alone does not guarantee local storage; remote drivers and NFS/CIFS options still place the database on a network share.

    A bind mount to a local SSD path is fine too, just keep it off any network share.


    :lock: Permissions

    Claude Code runs in acceptEdits mode by default. This is the shipped setting:

    ActionAllowed?
    Read filesYes
    Edit / create filesYes
    Run shell commandsDepends on Claude Code's current permission prompt
    Install packagesDepends on Claude Code's current permission prompt

    Want full bypass? (power users)

    This is how I personally run it. Edit ./data/claude/settings.json on your host:

    {
      "permissions": {
        "defaultMode": "bypassPermissions"
      }
    }
    

    Bypass mode means Claude executes commands without confirmation. It is powerful, but it can also run destructive commands quickly. Keep the shipped acceptEdits default unless you trust the workspace and every prompt you run.

    Codex Permission Modes

    HolyClaude also ships configurable near-parity permission modes for Codex, with separate controls for CloudCLI Codex chat and the raw codex CLI.

    SettingApplies toDefaultWhen it is read
    HOLYCLAUDE_CODEX_CHAT_PERMISSION_MODECloudCLI Codex requests that omit permissionModeacceptEdits fallbackRuntime container config, used only when the request has no explicit value
    HOLYCLAUDE_CODEX_CLI_PERMISSION_MODERaw codex CLI config at ~/.codex/config.tomldefaultFirst boot only, when the file does not already exist

    Valid values for both are default, acceptEdits, and bypassPermissions. acceptEdits is the fallback recommended for trusted self-hosted workspaces. The current CloudCLI browser client sends an explicit permissionMode, and that request value wins. HOLYCLAUDE_CODEX_CHAT_PERMISSION_MODE is only the fallback for direct WebSocket/API clients or custom frontends that omit it. For the raw codex CLI, default is the first-boot default; the setting only seeds a new ~/.codex/config.toml, existing configs are not overwritten, and the generated value persists until you edit that file yourself.

    bypassPermissions maps Codex to full access with no approval. Inside Docker, that still runs within the container and mounted volumes, but it can read and change anything reachable through those mounts, especially /workspace and persisted config under /home/claude. Use it only for trusted local workspaces, and don't expose CloudCLI directly to the public internet.


    :shield: Remote Access & Exposure

    HolyClaude binds CloudCLI to 127.0.0.1:3001 by default. That keeps the web UI on the Docker host only, which is right for a laptop or a home server you reach over SSH.

    The moment you want to reach it from outside your network, read this section.

    Don't port-forward it to the public internet

    I'll say it flat out: do not punch a hole in your router and expose 3001 to the open internet. Not even with a password. Here's why:

    • CloudCLI exposes a full shell through the web terminal plugin
    • It can run arbitrary code, install packages, and read/write your mounted /workspace
    • It holds your Anthropic OAuth tokens and API keys
    • Basic auth / app-level passwords get brute-forced, credential-stuffed, and scraped out of logs
    • One leaked password = someone else has a paid Claude Code instance running on your box with your money

    A password is a speed bump, not a door. Treat HolyClaude like you'd treat an SSH session: never on the open internet without a proper tunnel in front of it.

    Use a proper tunnel instead

    These are the two options I actually recommend:

    OptionWho it's forWhy
    TailscalePersonal use, small teamsWireGuard mesh VPN. Install Tailscale on your server + your laptop/phone, and you reach http://holyclaude:3001 from anywhere as if you were on the LAN. No ports opened, no DNS, no certs. Free for personal use.
    Cloudflare TunnelSharing with others, public hostnameCloudflare proxies the connection, so port 3001 stays closed. You get a real domain with HTTPS, and you can put Cloudflare Access (Google/GitHub SSO) in front of it. Free tier covers most personal use.

    Both avoid forwarding HolyClaude's application port through your router. Tailscale provides encrypted mesh transport and identity controls. Cloudflare Tunnel provides encrypted transport to Cloudflare's edge; configure Cloudflare Access separately when you need identity-based access controls and Access audit logs.

    Tailscale subpath mounts

    If you mount HolyClaude below a path, set the same path inside the container:

    environment:
      - HOLYCLAUDE_BASE_PATH=/holyclaude
    

    Then publish that path with Tailscale Serve:

    sudo tailscale serve --bg --https=443 --set-path=/holyclaude http://127.0.0.1:3001
    

    Use no trailing slash in HOLYCLAUDE_BASE_PATH. If you serve HolyClaude at the hostname root, leave this unset.

    Optional SSH and Mosh

    HolyClaude also ships sshd and Mosh for people who want a direct terminal from a phone, laptop, NAS, or VPN connection. It is off by default. Nothing listens on port 22 unless you enable it.

    This is a remote shell into the same container that holds your /workspace and Claude state. Treat it like SSH to your dev box:

    • key-only login as claude
    • no password auth
    • no root login
    • no authorized_keys under .claude or /workspace
    • no public internet port forwarding

    Safe setup shape:

    services:
      holyclaude:
        ports:
          - "127.0.0.1:2222:22"
          - "127.0.0.1:60000-60010:60000-60010/udp"
        volumes:
          - ./data/ssh/authorized_keys:/run/holyclaude-ssh/authorized_keys:ro
          - holyclaude-ssh:/var/lib/holyclaude-ssh
        environment:
          - HOLYCLAUDE_SSH_ENABLE=true
          - HOLYCLAUDE_MOSH_ENABLE=true
    
    volumes:
      holyclaude-ssh:
    

    Prepare the public key file on the host:

    mkdir -p data/ssh
    cp ~/.ssh/id_ed25519.pub data/ssh/authorized_keys
    

    Connect over SSH:

    ssh -p 2222 [email protected]
    

    Connect over Mosh when UDP is reachable:

    mosh --ssh="ssh -p 2222" -p 60000:60010 [email protected]
    

    Bind those ports to localhost, a VPN interface, or a firewall-restricted address. If you change 127.0.0.1 to 0.0.0.0, you are taking responsibility for that exposure.

    If you insist on exposing it directly (please don't)

    If you absolutely have to skip the tunnel (self-hosting tutorial, isolated lab network, whatever), at the very minimum:

    1. Put a reverse proxy in front of it (Caddy, nginx, Traefik) with real TLS
    2. Add IP allowlisting at the firewall or proxy level — only your known IPs
    3. Keep the shipped acceptEdits default unless you have a clear reason to use bypassPermissions
    4. Rotate your Anthropic credentials if anything looks off
    5. Run behind Cloudflare Access or similar SSO, not basic auth

    Even with all that, the risk surface is huge. Use Tailscale or Cloudflare Tunnel. They're free, they take five minutes to set up, and they're what I personally use.


    :bell: Notifications

    Walk away from your computer and know when a task is done. Claude Code hooks, raw CLI hooks for Codex and Gemini CLI, and CloudCLI Codex chat completion/failure events use the same Apprise setup. Apprise supports 100+ services including Discord, Telegram, Slack, Email, Pushover, Gotify, and more.

    To enable:

    1. Add one or more NOTIFY_* variables to your compose environment:
      - NOTIFY_DISCORD=discord://webhook_id/webhook_token
      - NOTIFY_TELEGRAM=tgram://bot_token/chat_id
      
    2. Inside the container: touch ~/.claude/notify-on

    Telegram uses Apprise's tgram:// scheme. Legacy Telegram values are still accepted, but new setups should use tgram://.

    Test the setup without sending a message:

    docker compose exec holyclaude /usr/local/bin/notify.py test --dry-run --debug
    

    See configuration docs for all supported variables and URL formats.

    To disable: rm ~/.claude/notify-on

    Events that trigger notifications:

    EventWhat happened
    stopClaude Code hooks, raw CLI hooks for Codex and Gemini CLI, or a CloudCLI Codex chat run finished
    errorA Claude Code hook, raw CLI hook, or CloudCLI Codex chat run failed

    Completely silent when not configured. No NOTIFY_* vars set? No flag file? Zero network calls. Zero log spam. Zero overhead.


    :arrows_counterclockwise: Upgrading

    Upgrading from a version before v1.5.5? If the current container holds git config --global or gh auth state that is not already in ./data/claude, migrate it before recreating the container. Follow Git and GitHub CLI recovery. Removing the old container first can discard that state.

    # Pull the latest image
    docker compose pull
    
    # Recreate the container with the new image
    docker compose up -d
    

    Your data persists in ./data/claude and ./workspace — upgrading only replaces the container, not your files.

    Do not update CloudCLI inside the container with cloudcli update or npm install -g @cloudcli-ai/cloudcli@latest. HolyClaude ships a patched CloudCLI runtime, so the supported update path is the Docker image:

    docker compose pull && docker compose up -d
    

    To pin a specific version instead of latest:

    image: coderluii/holyclaude:1.5.5   # instead of :latest
    

    :construction: Troubleshooting

    CloudCLI opens to /home/claude instead of /workspace.

    Cause: A custom or modified CloudCLI service script did not set WORKSPACES_ROOT=/workspace before launching CloudCLI.

    Fix: Already handled in HolyClaude. The s6 run script uses with-contenv, exports WORKSPACES_ROOT=/workspace, then starts CloudCLI as the claude user.

    CloudCLI cannot open ~, /workspace, or a broad NAS mount such as /volume2/docker:/workspace.

    Cause: HolyClaude 1.3.3 could remove CloudCLI's expandWorkspacePath helper while disabling CloudCLI's in-container self-update path.

    Fix: Update to HolyClaude 1.3.4 or newer:

    docker compose pull && docker compose up -d
    

    Broad NAS mounts work, but /workspace is the CloudCLI boundary. Anything readable under that mount is visible to authenticated CloudCLI users. Use a narrower project mount when you do not want the whole NAS folder tree exposed inside CloudCLI.

    The Web Terminal output is hard to read. Box drawing, emoji, CJK text, or CLI banners may show as black squares or broken characters.

    Cause: Older images built the CloudCLI Web Terminal plugin with string-based PTY output handling and a narrow xterm.js font stack. If a multibyte character was split between PTY chunks, or if WebGL picked a weak fallback font, terminal output could render as replacement blocks.

    Fix: Update to HolyClaude 1.3.5 or newer:

    docker compose pull && docker compose up -d
    

    HolyClaude now patches the baked Web Terminal plugin before it is built. If your browser still shows black squares after updating, open browser DevTools on the CloudCLI page, run this once, then reopen the Web Terminal:

    localStorage.setItem('web-terminal-disable-webgl', 'true')
    

    Cause: SQLite databases on SMB/CIFS network mounts. CIFS doesn't support the file-level locking SQLite requires.

    Fix: Don't store SQLite databases on network shares. HolyClaude keeps .cloudcli in container-local storage for exactly this reason. If you have your own SQLite databases in /workspace on a NAS, move them to a local path.

    Cause: Usually insufficient shared memory. Docker defaults to 64MB. If the process exits immediately with SIGTRAP or exit 133, treat that as a separate browser/runtime failure instead of a shared-memory symptom.

    Fix: Ensure shm_size: 2g in your compose file. For heavy browser use (many tabs, complex pages), increase to 4g. If you still get an immediate SIGTRAP, re-check the browser build path before only raising shm.

    Cause: SMB/CIFS network mounts don't support inotify.

    Fix: Enable polling in your compose environment:

    - CHOKIDAR_USEPOLLING=1
    - WATCHFILES_FORCE_POLLING=true
    

    Note: Polling uses more CPU than inotify. Only