Skip to main content

DOCKERFILE

Constant DOCKERFILE 

Source
pub const DOCKERFILE: &str = "# =============================================================================\n# opencode-cloud Container Image\n# =============================================================================\n# A comprehensive development environment for AI-assisted coding with opencode.\n#\n# Features:\n# - Ubuntu 24.04 LTS (noble) base\n# - Non-root user with passwordless sudo\n# - Multiple languages via mise (Node.js, Python, Rust, Go)\n# - Modern CLI tools (ripgrep, eza, fzf, lazygit, etc.)\n# - GSD opencode plugin for task management\n#\n# Usage:\n#   docker build -t opencode-cloud .\n#   docker run -it opencode-cloud\n#\n# =============================================================================\n\n# -----------------------------------------------------------------------------\n# Version Pinning Policy\n# -----------------------------------------------------------------------------\n# - APT packages: Use major.minor.* wildcards for patch updates\n# - GitHub tools: Pin to release tags (vX.Y.Z)\n# - Cargo/Go: Pin to exact versions (@X.Y.Z)\n# - Security exceptions marked with: # UNPINNED: package - reason\n# - Self-managing installers (mise, rustup, etc.) trusted to handle versions\n#\n# To check for updates: just check-updates\n# Last version audit: 2026-01-22\n# -----------------------------------------------------------------------------\n\n# -----------------------------------------------------------------------------\n# Stage 1: Runtime\n# -----------------------------------------------------------------------------\nFROM ubuntu:24.04 AS runtime\n\n# OCI Labels for image metadata\nLABEL org.opencontainers.image.title=\"opencode-cloud\"\nLABEL org.opencontainers.image.description=\"AI-assisted development environment with opencode\"\nLABEL org.opencontainers.image.url=\"https://github.com/pRizz/opencode-cloud\"\nLABEL org.opencontainers.image.source=\"https://github.com/pRizz/opencode-cloud\"\nLABEL org.opencontainers.image.vendor=\"pRizz\"\nLABEL org.opencontainers.image.licenses=\"MIT\"\nLABEL org.opencontainers.image.base.name=\"ubuntu:24.04\"\n\n# Environment configuration\nENV DEBIAN_FRONTEND=noninteractive\nENV TZ=UTC\nENV LANG=C.UTF-8\nENV LC_ALL=C.UTF-8\n\n# -----------------------------------------------------------------------------\n# System Dependencies\n# -----------------------------------------------------------------------------\n# Install core system packages in logical groups for better caching\n\n# Group 1: Core utilities and build tools (2026-01-22)\n# Use BuildKit cache mount for APT package lists and cache\nRUN --mount=type=cache,target=/var/lib/apt/lists \\\n    --mount=type=cache,target=/var/cache/apt \\\n    apt-get update && apt-get install -y --no-install-recommends \\\n    # Init systems\n    tini=0.19.* \\\n    dumb-init=1.2.* \\\n    # systemd for Cockpit support\n    systemd=255.* \\\n    systemd-sysv=255.* \\\n    dbus=1.14.* \\\n    # Shell and terminal\n    zsh=5.9-* \\\n    tmux=3.4-* \\\n    # Editors\n    vim=2:9.1.* \\\n    neovim=0.9.* \\\n    nano=7.2-* \\\n    # Build essentials\n    build-essential=12.* \\\n    pkg-config=1.8.* \\\n    cmake=3.28.* \\\n    # Version control\n    git=1:2.43.* \\\n    git-lfs=3.4.* \\\n    # Core utilities\n    curl=8.5.* \\\n    wget=1.21.* \\\n    # UNPINNED: ca-certificates - security-critical root certs, needs auto-updates\n    ca-certificates \\\n    # UNPINNED: gnupg - key management security, needs auto-updates\n    gnupg \\\n    lsb-release=12.* \\\n    software-properties-common=0.99.* \\\n    sudo=1.9.* \\\n    # UNPINNED: openssh-client - security-critical, needs auto-updates\n    openssh-client \\\n    # Process/system tools\n    htop=3.3.* \\\n    procps=2:4.0.* \\\n    less=590-* \\\n    file=1:5.45-* \\\n    tree=2.1.* \\\n    # JSON/YAML processing\n    jq=1.7.* \\\n    # Network tools\n    netcat-openbsd=1.226-* \\\n    iputils-ping=3:20240117-* \\\n    dnsutils=1:9.18.* \\\n    # Reverse proxy for opencode UI + API\n    nginx=1.24.* \\\n    # Compression\n    zip=3.0-* \\\n    unzip=6.0-* \\\n    xz-utils=5.6.* \\\n    p7zip-full=16.02* \\\n    && rm -rf /var/lib/apt/lists/*\n\n# Mask unnecessary systemd services for container environment\nRUN systemctl mask \\\n    dev-hugepages.mount \\\n    sys-fs-fuse-connections.mount \\\n    systemd-update-utmp.service \\\n    systemd-tmpfiles-setup.service \\\n    systemd-remount-fs.service\n\n# Group 2: Database clients (2026-01-22)\n# Use BuildKit cache mount for APT package lists and cache\nRUN --mount=type=cache,target=/var/lib/apt/lists \\\n    --mount=type=cache,target=/var/cache/apt \\\n    apt-get update && apt-get install -y --no-install-recommends \\\n    sqlite3=3.45.* \\\n    postgresql-client=16+* \\\n    default-mysql-client=1.1.* \\\n    && rm -rf /var/lib/apt/lists/*\n\n# Group 3: Development libraries for compiling tools (2026-01-22)\n# Use BuildKit cache mount for APT package lists and cache\nRUN --mount=type=cache,target=/var/lib/apt/lists \\\n    --mount=type=cache,target=/var/cache/apt \\\n    apt-get update && apt-get install -y --no-install-recommends \\\n    # libssl-dev depends on libssl3t64 with exact version match\n    libssl3t64=3.0.* \\\n    libssl-dev=3.0.* \\\n    libffi-dev=3.4.* \\\n    zlib1g-dev=1:1.3.* \\\n    libbz2-dev=1.0.* \\\n    libreadline-dev=8.2-* \\\n    libsqlite3-dev=3.45.* \\\n    libncurses-dev=6.4+* \\\n    libpam0g-dev=1.5.* \\\n    liblzma-dev=5.6.* \\\n    && rm -rf /var/lib/apt/lists/*\n\n# -----------------------------------------------------------------------------\n# Create Non-Root User\n# -----------------------------------------------------------------------------\n# Create \'opencode\' user with passwordless sudo\nRUN useradd -m -s /bin/zsh -G sudo opencode \\\n    && echo \"opencode ALL=(ALL) NOPASSWD:ALL\" > /etc/sudoers.d/opencode \\\n    && chmod 0440 /etc/sudoers.d/opencode\n\n# Switch to opencode user for remaining setup\nUSER opencode\nWORKDIR /home/opencode\n\n# Set up directories\nRUN mkdir -p \\\n    /home/opencode/.config \\\n    /home/opencode/.local/bin \\\n    /home/opencode/.local/share \\\n    /home/opencode/.cache \\\n    /home/opencode/workspace\n\n# Add local bin to PATH\nENV PATH=\"/home/opencode/.local/bin:${PATH}\"\n\n# -----------------------------------------------------------------------------\n# Shell Setup: Zsh + Oh My Zsh + Starship\n# -----------------------------------------------------------------------------\n# Oh My Zsh - self-managing installer, trusted to handle versions\n# Disabled temporarily to reduce Docker build time.\n# RUN sh -c \"$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)\" \"\" --unattended\n\n# Starship prompt - self-managing installer, trusted to handle versions\n# Disabled temporarily to reduce Docker build time.\n# RUN curl -sS https://starship.rs/install.sh | sh -s -- --yes --bin-dir /home/opencode/.local/bin\n\n# Configure zsh with starship\n# Disabled temporarily to reduce Docker build time.\n# RUN echo \'eval \"$(starship init zsh)\"\' >> /home/opencode/.zshrc \\\n#     && echo \'export PATH=\"/home/opencode/.local/bin:$PATH\"\' >> /home/opencode/.zshrc\n\n# -----------------------------------------------------------------------------\n# mise: Universal Version Manager\n# -----------------------------------------------------------------------------\n# mise - self-managing installer, trusted to handle versions\nRUN curl https://mise.run | sh \\\n    && echo \'eval \"$(/home/opencode/.local/bin/mise activate zsh)\"\' >> /home/opencode/.zshrc\n\n# Install language runtimes via mise (2026-01-22)\n# - node@lts: mise handles LTS resolution (currently 22.x)\n# - python@3.12: pinned to minor version\n# - go@1.24: pinned to minor version (was @latest)\nRUN /home/opencode/.local/bin/mise install node@lts \\\n    && /home/opencode/.local/bin/mise install python@3.12 \\\n    && /home/opencode/.local/bin/mise install go@1.24 \\\n    && /home/opencode/.local/bin/mise use --global node@lts \\\n    && /home/opencode/.local/bin/mise use --global python@3.12 \\\n    && /home/opencode/.local/bin/mise use --global go@1.24\n\n# Set up mise shims in PATH for non-interactive shells\nENV PATH=\"/home/opencode/.local/share/mise/shims:${PATH}\"\n\n# -----------------------------------------------------------------------------\n# Rust Installation\n# -----------------------------------------------------------------------------\n# rustup - self-managing installer, trusted to handle versions\n# Uses stable toolchain (rustup manages toolchain versioning)\nRUN curl --proto \'=https\' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable \\\n    && . /home/opencode/.cargo/env \\\n    && rustup default stable \\\n    && rustup component add rust-analyzer rustfmt clippy\n\nENV PATH=\"/home/opencode/.cargo/bin:${PATH}\"\n\n# -----------------------------------------------------------------------------\n# Package Managers\n# -----------------------------------------------------------------------------\n# Switch to bash for mise activation (mise outputs bash-specific syntax)\nSHELL [\"/bin/bash\", \"-c\"]\n\n# Install pnpm 10.x via corepack (2026-01-22)\nRUN eval \"$(/home/opencode/.local/bin/mise activate bash)\" \\\n    && corepack enable \\\n    && corepack prepare pnpm@10.28.1 --activate\n\n# Set up pnpm global bin directory\nENV PNPM_HOME=\"/home/opencode/.local/share/pnpm\"\nENV PATH=\"${PNPM_HOME}:${PATH}\"\nRUN mkdir -p \"${PNPM_HOME}\"\n\n\n# uv - self-managing installer, trusted to handle versions (fast Python package manager)\nRUN curl -LsSf https://astral.sh/uv/install.sh | sh\n\n# Install pipx for isolated Python application installs\n# Use BuildKit cache mount for pip cache\nRUN --mount=type=cache,target=/home/opencode/.cache/pip,uid=1000,gid=1000,mode=0755 \\\n    mkdir -p /home/opencode/.cache/pip \\\n    && eval \"$(/home/opencode/.local/bin/mise activate bash)\" \\\n    && pip install --user pipx \\\n    && pipx ensurepath\n\n# Install global TypeScript compiler\n# NOTE: Avoid cache mount here to prevent pnpm store permission issues\nRUN eval \"$(/home/opencode/.local/bin/mise activate bash)\" \\\n    && pnpm add -g typescript\n\n# -----------------------------------------------------------------------------\n# Modern CLI Tools (Rust-based) - pinned versions (2026-01-22)\n# -----------------------------------------------------------------------------\n# ripgrep 15.1.0 - fast regex search\n# eza 0.23.4 - modern ls replacement\n# NOTE: Avoid cache mounts here due to permission issues with non-root Cargo cache\nRUN mkdir -p /home/opencode/.cargo/registry /home/opencode/.cargo/git \\\n    && . /home/opencode/.cargo/env \\\n    && cargo install --locked ripgrep@15.1.0 eza@0.23.4 \\\n    && rm -rf /home/opencode/.cargo/registry /home/opencode/.cargo/git\n\n# lazygit v0.58.1 (2026-01-12) - terminal UI for git\n# Disabled temporarily to reduce Docker build time.\n# RUN eval \"$(/home/opencode/.local/bin/mise activate bash)\" \\\n#     && go install github.com/jesseduffield/lazygit@v0.58.1\n\n# -----------------------------------------------------------------------------\n# Additional Development Tools\n# -----------------------------------------------------------------------------\n# fzf v0.67.0 (2025-11-16) - fuzzy finder\n# Disabled temporarily to reduce Docker build time.\n# RUN git clone --branch v0.67.0 --depth 1 https://github.com/junegunn/fzf.git /home/opencode/.fzf \\\n#     && /home/opencode/.fzf/install --all --no-bash --no-fish\n\n# yq v4.50.1 (2025-12-14) - YAML processor\n# Disabled temporarily to reduce Docker build time.\n# RUN curl -sL https://github.com/mikefarah/yq/releases/download/v4.50.1/yq_linux_$(dpkg --print-architecture) -o /home/opencode/.local/bin/yq \\\n#     && chmod +x /home/opencode/.local/bin/yq\n\n# Install direnv (2026-01-22)\n# Disabled temporarily to reduce Docker build time.\n# USER root\n# RUN apt-get update && apt-get install -y --no-install-recommends direnv=2.32.* \\\n#     && rm -rf /var/lib/apt/lists/*\n# USER opencode\n# RUN echo \'eval \"$(direnv hook zsh)\"\' >> /home/opencode/.zshrc\n\n# Install HTTPie\n# Disabled temporarily to reduce Docker build time.\n# RUN eval \"$(/home/opencode/.local/bin/mise activate bash)\" \\\n#     && pipx install httpie\n\n# Install shellcheck (2026-01-22)\n# Disabled temporarily to reduce Docker build time.\n# USER root\n# RUN apt-get update && apt-get install -y --no-install-recommends shellcheck=0.9.* \\\n#     && rm -rf /var/lib/apt/lists/*\n# USER opencode\n# shfmt v3.12.0 (2025-07-06) - shell formatter\n# Disabled temporarily to reduce Docker build time.\n# RUN eval \"$(/home/opencode/.local/bin/mise activate bash)\" \\\n#     && go install mvdan.cc/sh/v3/cmd/shfmt@v3.12.0\n\n# Install btop system monitor (2026-01-22)\n# Use BuildKit cache mount for APT package lists and cache\nUSER root\nRUN --mount=type=cache,target=/var/lib/apt/lists \\\n    --mount=type=cache,target=/var/cache/apt \\\n    apt-get update && apt-get install -y --no-install-recommends btop=1.3.* \\\n    && rm -rf /var/lib/apt/lists/*\nUSER opencode\n\n# -----------------------------------------------------------------------------\n# GitHub CLI\n# -----------------------------------------------------------------------------\nUSER root\n# Use BuildKit cache mount for APT package lists and cache\nRUN --mount=type=cache,target=/var/lib/apt/lists \\\n    --mount=type=cache,target=/var/cache/apt \\\n    curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg \\\n    && chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg \\\n    && 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 \\\n    && apt-get update && apt-get install -y --no-install-recommends gh \\\n    && rm -rf /var/lib/apt/lists/*\nUSER opencode\n\n# -----------------------------------------------------------------------------\n# Cockpit Web Console (2026-01-22) - temporarily disabled\n# -----------------------------------------------------------------------------\n# Cockpit provides web-based administration for the container\n# Ubuntu noble has cockpit 316 in main repos\n# Use BuildKit cache mount for APT package lists and cache\n# USER root\n# RUN --mount=type=cache,target=/var/lib/apt/lists \\\n#     --mount=type=cache,target=/var/cache/apt \\\n#     apt-get update && \\\n#     apt-get install -y --no-install-recommends \\\n#     cockpit-ws \\\n#     cockpit-system \\\n#     cockpit-bridge \\\n#     && rm -rf /var/lib/apt/lists/*\n#\n# Enable Cockpit socket activation (manual symlink since systemctl doesn\'t work during build)\n# RUN mkdir -p /etc/systemd/system/sockets.target.wants \\\n#     && ln -sf /lib/systemd/system/cockpit.socket /etc/systemd/system/sockets.target.wants/cockpit.socket\n#\n# Configure Cockpit for HTTP (TLS terminated externally) and proxy headers\n# RUN mkdir -p /etc/cockpit && \\\n#     printf \'%s\\n\' \\\n#     \'[WebService]\' \\\n#     \'# Allow HTTP connections (TLS terminated externally like opencode)\' \\\n#     \'AllowUnencrypted = true\' \\\n#     \'\' \\\n#     \'# Trust proxy headers for X-Forwarded-For, X-Forwarded-Proto\' \\\n#     \'ProtocolHeader = X-Forwarded-Proto\' \\\n#     \'ForwardedForHeader = X-Forwarded-For\' \\\n#     \'\' \\\n#     \'# Limit concurrent login attempts\' \\\n#     \'MaxStartups = 10\' \\\n#     > /etc/cockpit/cockpit.conf\n#\n# USER opencode\n\n# -----------------------------------------------------------------------------\n# CI/CD + tooling (disabled)\n# -----------------------------------------------------------------------------\n# NOTE: Commented out because this section adds significant time in GitHub Actions\n# builds. We will reconsider re-adding these tools later, potentially in a more\n# templated/configured Docker image optimized for build tooling.\n# -----------------------------------------------------------------------------\n# # CI/CD Tools\n# # -----------------------------------------------------------------------------\n# # act v0.2.84 (2026-01-01) - run GitHub Actions locally\n# RUN curl -sL https://raw.githubusercontent.com/nektos/act/master/install.sh | sudo bash -s -- -b /home/opencode/.local/bin v0.2.84\n#\n# # -----------------------------------------------------------------------------\n# # Rust Tooling - pinned versions (2026-01-22)\n# # -----------------------------------------------------------------------------\n# # cargo-nextest 0.9.122 - fast test runner\n# # cargo-audit 0.22.0 - security audit\n# # cargo-deny 0.19.0 - dependency linter\n# RUN . /home/opencode/.cargo/env \\\n#     && cargo install --locked cargo-nextest@0.9.122 cargo-audit@0.22.0 cargo-deny@0.19.0\n#\n# # Install mold fast linker (2026-01-22)\n# USER root\n# RUN apt-get update && apt-get install -y --no-install-recommends mold=2.30.* \\\n#     && rm -rf /var/lib/apt/lists/*\n# USER opencode\n#\n# # -----------------------------------------------------------------------------\n# # Code Quality Tools\n# # -----------------------------------------------------------------------------\n# # JavaScript/TypeScript tools\n# RUN eval \"$(/home/opencode/.local/bin/mise activate bash)\" \\\n#     && pnpm add -g \\\n#     prettier \\\n#     eslint \\\n#     @biomejs/biome\n#\n# # Python tools\n# RUN eval \"$(/home/opencode/.local/bin/mise activate bash)\" \\\n#     && pipx install black \\\n#     && pipx install ruff\n#\n# # Test runners (commonly needed)\n# RUN eval \"$(/home/opencode/.local/bin/mise activate bash)\" \\\n#     && pnpm add -g jest vitest\n#\n# # Python pytest via pipx\n# RUN eval \"$(/home/opencode/.local/bin/mise activate bash)\" \\\n#     && pipx install pytest\n#\n# # -----------------------------------------------------------------------------\n# # Protocol Buffers / gRPC (2026-01-22)\n# # -----------------------------------------------------------------------------\n# USER root\n# RUN apt-get update && apt-get install -y --no-install-recommends protobuf-compiler=3.21.* \\\n#     && rm -rf /var/lib/apt/lists/*\n# USER opencode\n#\n# # grpcurl v1.9.3 (2025-03-11) - gRPC debugging tool\n# RUN eval \"$(/home/opencode/.local/bin/mise activate bash)\" \\\n#     && go install github.com/fullstorydev/grpcurl/cmd/grpcurl@v1.9.3\n\n# -----------------------------------------------------------------------------\n# Sensible Defaults Configuration\n# -----------------------------------------------------------------------------\n# Git configuration\nRUN git config --global init.defaultBranch main \\\n    && git config --global core.editor \"nvim\" \\\n    && git config --global pull.rebase false \\\n    && git config --global merge.conflictstyle diff3 \\\n    && git config --global diff.colorMoved default\n\n# Starship configuration (minimal, fast prompt)\nRUN mkdir -p /home/opencode/.config \\\n    && printf \'%s\\n\' \\\n    \'# Minimal starship config for fast prompt\' \\\n    \'format = \"\"\"\' \\\n    \'$directory\\\' \\\n    \'$git_branch\\\' \\\n    \'$git_status\\\' \\\n    \'$character\"\"\"\' \\\n    \'\' \\\n    \'[directory]\' \\\n    \'truncation_length = 3\' \\\n    \'truncate_to_repo = true\' \\\n    \'\' \\\n    \'[git_branch]\' \\\n    \'format = \"[$branch]($style) \"\' \\\n    \'style = \"bold purple\"\' \\\n    \'\' \\\n    \'[git_status]\' \\\n    \'format = \'\"\'\"\'([$all_status$ahead_behind]($style) )\'\"\'\"\'\' \\\n    \'\' \\\n    \'[character]\' \\\n    \'success_symbol = \"[>](bold green)\"\' \\\n    \'error_symbol = \"[>](bold red)\"\' \\\n    > /home/opencode/.config/starship.toml\n\n# Shell aliases\nRUN printf \'%s\\n\' \\\n    \'\' \\\n    \'# Modern CLI aliases\' \\\n    \'alias ls=\"eza --icons\"\' \\\n    \'alias ll=\"eza -l --icons\"\' \\\n    \'alias la=\"eza -la --icons\"\' \\\n    \'alias lt=\"eza --tree --icons\"\' \\\n    \'alias grep=\"rg\"\' \\\n    \'alias top=\"btop\"\' \\\n    \'\' \\\n    \'# Git aliases\' \\\n    \'alias g=\"git\"\' \\\n    \'alias gs=\"git status\"\' \\\n    \'alias gd=\"git diff\"\' \\\n    \'alias gc=\"git commit\"\' \\\n    \'alias gp=\"git push\"\' \\\n    \'alias gl=\"git pull\"\' \\\n    \'alias gco=\"git checkout\"\' \\\n    \'alias gb=\"git branch\"\' \\\n    \'alias lg=\"lazygit\"\' \\\n    \'\' \\\n    \'# Docker aliases (for Docker-in-Docker)\' \\\n    \'alias d=\"docker\"\' \\\n    \'alias dc=\"docker compose\"\' \\\n    \'\' \\\n    >> /home/opencode/.zshrc\n\n# Set up pipx path\nRUN echo \'export PATH=\"/home/opencode/.local/bin:$PATH\"\' >> /home/opencode/.zshrc\n\n# -----------------------------------------------------------------------------\n# opencode Setup (Fork + Broker + Proxy)\n# -----------------------------------------------------------------------------\n# Keep this block near the end to preserve cache for earlier layers. We expect\n# opencode fork changes to happen more often than base tooling changes.\n#\n# This block includes:\n# - opencode build (backend binary) + app build (frontend dist)\n# - opencode-broker build\n# - nginx config for single-endpoint UI + API proxy\n# - PAM configuration + systemd services\n# - opencode config file\n#\n# NOTE: This section switches between opencode and root users as needed.\n\n# -----------------------------------------------------------------------------\n# opencode Installation (Fork from pRizz/opencode)\n# -----------------------------------------------------------------------------\n# Clone the fork and build opencode from source (as non-root user)\n# Pin to specific commit for reproducibility\n# Build opencode from source (BuildKit cache mounts disabled for now)\nRUN rm -rf /tmp/opencode-repo \\\n    && git clone --depth 1 https://github.com/pRizz/opencode.git /tmp/opencode-repo \\\n    && cd /tmp/opencode-repo \\\n    && git checkout 798ccdba1265b7e5499ba49db2f99ca1dd4a15d7 \\\n    && curl -fsSL https://bun.sh/install | bash -s \"bun-v1.3.5\" \\\n    && export PATH=\"/home/opencode/.bun/bin:${PATH}\" \\\n    && bun install --frozen-lockfile \\\n    && bun run packages/opencode/script/build.ts --single \\\n    && cd packages/app \\\n    && bun run build \\\n    && rm -rf /home/opencode/.bun/install/cache /home/opencode/.bun/cache /home/opencode/.cache/bun \\\n    && cd /tmp/opencode-repo \\\n    && mkdir -p /home/opencode/.local/share/opencode/bin \\\n    && cp /tmp/opencode-repo/packages/opencode/dist/opencode-*/bin/opencode /home/opencode/.local/share/opencode/bin/opencode \\\n    && chown -R opencode:opencode /home/opencode/.local/share/opencode \\\n    && chmod +x /home/opencode/.local/share/opencode/bin/opencode \\\n    && /home/opencode/.local/share/opencode/bin/opencode --version\n\n# Add opencode to PATH\nENV PATH=\"/home/opencode/.local/share/opencode/bin:${PATH}\"\n\n# Copy UI assets to standard web root (requires root)\nUSER root\nRUN mkdir -p /var/www/opencode \\\n    && cp -R /tmp/opencode-repo/packages/app/dist/. /var/www/opencode/ \\\n    && chown -R root:root /var/www/opencode \\\n    && chmod 755 /var/www /var/www/opencode \\\n    && chmod -R a+rX /var/www/opencode\n\n# -----------------------------------------------------------------------------\n# opencode-broker Installation\n# -----------------------------------------------------------------------------\n# Build opencode-broker from source (Rust service for PAM authentication)\n# The broker handles PAM authentication and user process spawning\n# NOTE: Requires root privileges for setuid bit (chmod 4755) to allow broker\n# to run with elevated privileges for PAM authentication\nUSER root\nRUN cd /tmp/opencode-repo/packages/opencode-broker \\\n    && runuser -u opencode -- bash -c \'. /home/opencode/.cargo/env && cargo build --release\' \\\n    && mkdir -p /usr/local/bin \\\n    && cp target/release/opencode-broker /usr/local/bin/opencode-broker \\\n    && chmod 4755 /usr/local/bin/opencode-broker \\\n    && rm -rf /tmp/opencode-repo\n\n# Verify broker binary exists and is executable\nRUN ls -la /usr/local/bin/opencode-broker \\\n    && test -x /usr/local/bin/opencode-broker \\\n    && echo \"Broker installed\"\n\n# -----------------------------------------------------------------------------\n# Nginx Reverse Proxy for UI + API\n# -----------------------------------------------------------------------------\n# Serve the built UI from /var/www/opencode and proxy API/WebSocket\n# TODO: Explore a sustainable routing strategy (e.g., backend-driven base URL or\n# TODO: content-type aware proxying without hardcoded path lists).\nRUN rm -f /etc/nginx/sites-enabled/default /etc/nginx/conf.d/default.conf 2>/dev/null || true \\\n    && printf \'%s\\n\' \\\n    \'server {\' \\\n    \'  listen 3000;\' \\\n    \'  server_name _;\' \\\n    \'\' \\\n    \'  root /var/www/opencode;\' \\\n    \'  index index.html;\' \\\n    \'\' \\\n    \'  location = /health {\' \\\n    \'    proxy_pass http://127.0.0.1:3001;\' \\\n    \'  }\' \\\n    \'\' \\\n    \'  location /assets/ {\' \\\n    \'    try_files $uri =404;\' \\\n    \'  }\' \\\n    \'\' \\\n    \'  location ~* \\.(?:js|css|png|jpg|jpeg|gif|svg|ico|webp|woff2?|ttf|map)$ {\' \\\n    \'    try_files $uri =404;\' \\\n    \'  }\' \\\n    \'\' \\\n    \'  location ~ ^/(agent|auth|command|config|event|events|global|lsp|mcp|path|permission|project|provider|pty|question|rpc|session|sessions|status|v1|vcs|ws|api) {\' \\\n    \'    proxy_pass http://127.0.0.1:3001;\' \\\n    \'    proxy_http_version 1.1;\' \\\n    \'    proxy_set_header Upgrade $http_upgrade;\' \\\n    \'    proxy_set_header Connection \"upgrade\";\' \\\n    \'    proxy_set_header Host $host;\' \\\n    \'    proxy_set_header X-Real-IP $remote_addr;\' \\\n    \'    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\' \\\n    \'    proxy_set_header X-Forwarded-Proto $scheme;\' \\\n    \'  }\' \\\n    \'\' \\\n    \'  location / {\' \\\n    \'    try_files $uri $uri/ /index.html;\' \\\n    \'  }\' \\\n    \'}\' \\\n    > /etc/nginx/conf.d/opencode.conf\n\n# -----------------------------------------------------------------------------\n# PAM Configuration\n# -----------------------------------------------------------------------------\n# Install PAM configuration for opencode authentication\n# This allows opencode to authenticate users via PAM (same users as Cockpit)\n# NOTE: Requires root privileges to write to /etc/pam.d/\nRUN printf \'%s\\n\' \\\n    \'# PAM configuration for OpenCode authentication\' \\\n    \'# Install to /etc/pam.d/opencode\' \\\n    \'\' \\\n    \'# Standard UNIX authentication\' \\\n    \'auth required pam_unix.so\' \\\n    \'account required pam_unix.so\' \\\n    \'\' \\\n    \'# Optional: Enable TOTP 2FA (uncomment when pam_google_authenticator is installed)\' \\\n    \'# auth required pam_google_authenticator.so\' \\\n    > /etc/pam.d/opencode \\\n    && chmod 644 /etc/pam.d/opencode\n\n# Verify PAM config file exists\nRUN ls -la /etc/pam.d/opencode && cat /etc/pam.d/opencode\n\n# -----------------------------------------------------------------------------\n# opencode-broker systemd Service\n# -----------------------------------------------------------------------------\n# Create opencode-broker service for PAM authentication\n# NOTE: Requires root privileges to write to /etc/systemd/system/\nRUN printf \'%s\\n\' \\\n    \'[Unit]\' \\\n    \'Description=OpenCode Authentication Broker\' \\\n    \'Documentation=https://github.com/pRizz/opencode\' \\\n    \'After=network.target\' \\\n    \'\' \\\n    \'[Service]\' \\\n    \'Type=notify\' \\\n    \'ExecStart=/usr/local/bin/opencode-broker\' \\\n    \'ExecReload=/bin/kill -HUP $MAINPID\' \\\n    \'Restart=always\' \\\n    \'RestartSec=5\' \\\n    \'\' \\\n    \'# Security hardening\' \\\n    \'NoNewPrivileges=false\' \\\n    \'ProtectSystem=strict\' \\\n    \'ProtectHome=read-only\' \\\n    \'PrivateTmp=true\' \\\n    \'ReadWritePaths=/run/opencode\' \\\n    \'\' \\\n    \'# Socket directory\' \\\n    \'RuntimeDirectory=opencode\' \\\n    \'RuntimeDirectoryMode=0755\' \\\n    \'\' \\\n    \'# Logging\' \\\n    \'StandardOutput=journal\' \\\n    \'StandardError=journal\' \\\n    \'SyslogIdentifier=opencode-broker\' \\\n    \'\' \\\n    \'[Install]\' \\\n    \'WantedBy=multi-user.target\' \\\n    > /etc/systemd/system/opencode-broker.service\n\n# Enable opencode-broker service\nRUN mkdir -p /etc/systemd/system/multi-user.target.wants \\\n    && ln -sf /etc/systemd/system/opencode-broker.service /etc/systemd/system/multi-user.target.wants/opencode-broker.service\n\nUSER opencode\n\n# -----------------------------------------------------------------------------\n# GSD Plugin Installation\n# -----------------------------------------------------------------------------\n# Install the GSD (Get Shit Done) plugin for opencode\n# Note: If this fails in container builds due to \"~\" path resolution, retry with\n# OPENCODE_CONFIG_DIR=/home/opencode/.config/opencode set explicitly.\nRUN mkdir -p /home/opencode/.npm \\\n    && npx --yes get-shit-done-cc --opencode --global \\\n    && rm -rf /home/opencode/.npm/_cacache /home/opencode/.npm/_npx\n\n# -----------------------------------------------------------------------------\n# opencode systemd Service (2026-01-22)\n# -----------------------------------------------------------------------------\n# Create opencode as a systemd service for Cockpit integration (backend only)\n# NOTE: Requires root privileges to write to /etc/systemd/system/\nUSER root\nRUN printf \'%s\\n\' \\\n    \'[Unit]\' \\\n    \'Description=opencode Web Interface\' \\\n    \'After=network.target opencode-broker.service\' \\\n    \'\' \\\n    \'[Service]\' \\\n    \'Type=simple\' \\\n    \'User=opencode\' \\\n    \'WorkingDirectory=/home/opencode/workspace\' \\\n    \'ExecStart=/home/opencode/.local/share/opencode/bin/opencode --port 3001 --hostname 0.0.0.0\' \\\n    \'Restart=always\' \\\n    \'RestartSec=5\' \\\n    \'Environment=PATH=/home/opencode/.local/share/opencode/bin:/home/opencode/.local/bin:/home/opencode/.cargo/bin:/home/opencode/.local/share/mise/shims:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\' \\\n    \'\' \\\n    \'[Install]\' \\\n    \'WantedBy=multi-user.target\' \\\n    > /etc/systemd/system/opencode.service\n\n# Enable opencode service to start at boot (manual symlink since systemctl doesn\'t work during build)\nRUN mkdir -p /etc/systemd/system/multi-user.target.wants \\\n    && ln -sf /etc/systemd/system/opencode.service /etc/systemd/system/multi-user.target.wants/opencode.service\n\n# Nginx service for serving UI + proxying API\nRUN printf \'%s\\n\' \\\n    \'[Unit]\' \\\n    \'Description=Nginx reverse proxy for opencode UI\' \\\n    \'After=network.target opencode.service\' \\\n    \'\' \\\n    \'[Service]\' \\\n    \'Type=simple\' \\\n    \'ExecStart=/usr/sbin/nginx -g \"daemon off;\"\' \\\n    \'ExecReload=/usr/sbin/nginx -s reload\' \\\n    \'Restart=always\' \\\n    \'RestartSec=5\' \\\n    \'\' \\\n    \'[Install]\' \\\n    \'WantedBy=multi-user.target\' \\\n    > /etc/systemd/system/opencode-nginx.service\n\n# Enable nginx service\nRUN mkdir -p /etc/systemd/system/multi-user.target.wants \\\n    && ln -sf /etc/systemd/system/opencode-nginx.service /etc/systemd/system/multi-user.target.wants/opencode-nginx.service\n\n# Prevent the distro nginx service from also starting (port 3000 conflict)\nRUN rm -f /etc/systemd/system/multi-user.target.wants/nginx.service \\\n    && ln -sf /dev/null /etc/systemd/system/nginx.service\n\n# -----------------------------------------------------------------------------\n# opencode Configuration\n# -----------------------------------------------------------------------------\n# Create opencode.json config file with PAM authentication enabled\nRUN mkdir -p /home/opencode/.config/opencode \\\n    && printf \'%s\\n\' \\\n    \'{\' \\\n    \'  \"auth\": {\' \\\n    \'    \"enabled\": true\' \\\n    \'  }\' \\\n    \'}\' \\\n    > /home/opencode/.config/opencode/opencode.json \\\n    && chown -R opencode:opencode /home/opencode/.config/opencode \\\n    && chmod 644 /home/opencode/.config/opencode/opencode.json\n\n# Verify config file exists\nRUN ls -la /home/opencode/.config/opencode/opencode.json && cat /home/opencode/.config/opencode/opencode.json\n\nUSER opencode\n\n# -----------------------------------------------------------------------------\n# Entrypoint Script (Hybrid Init Support)\n# -----------------------------------------------------------------------------\n# Supports both tini (default, works everywhere) and systemd (for Cockpit on Linux)\n# Set USE_SYSTEMD=1 environment variable to use systemd init\n# Note: Entrypoint runs as root to support both modes; tini mode drops to opencode user\nUSER root\nRUN printf \'%s\\n\' \\\n    \'#!/bin/bash\' \\\n    \'if [ \"${USE_SYSTEMD}\" = \"1\" ]; then\' \\\n    \'    exec /sbin/init\' \\\n    \'else\' \\\n    \'    # Use runuser to switch to opencode user without password prompt\' \\\n    \'    runuser -u opencode -- /home/opencode/.local/share/opencode/bin/opencode --port 3001 --hostname 0.0.0.0 &\' \\\n    \'    exec /usr/sbin/nginx -g \"daemon off;\"\' \\\n    \'fi\' \\\n    > /usr/local/bin/entrypoint.sh && chmod +x /usr/local/bin/entrypoint.sh\n\n# Note: Don\'t set USER here - entrypoint needs root to use runuser\n# The tini mode drops privileges to opencode user via runuser\n\n# -----------------------------------------------------------------------------\n# Health Check\n# -----------------------------------------------------------------------------\n# Check that opencode health endpoint responds\n# Works for both tini and systemd modes\nHEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \\\n    CMD curl -f http://localhost:3000/health || exit 1\n\n# -----------------------------------------------------------------------------\n# Version File\n# -----------------------------------------------------------------------------\n# Store version in file for runtime access (debugging, scripts)\n# Keep this near the end: changing the version invalidates the cache\n# and significantly slows down docker builds if placed earlier.\nUSER root\nARG OPENCODE_CLOUD_VERSION=dev\nLABEL org.opencode-cloud.version=\"${OPENCODE_CLOUD_VERSION}\"\nRUN echo \"${OPENCODE_CLOUD_VERSION}\" > /etc/opencode-cloud-version\n# Note: Stay as root - entrypoint.sh needs root to run either:\n# - /sbin/init (systemd mode)\n# - runuser (tini mode, which then drops privileges to opencode user)\n\n# -----------------------------------------------------------------------------\n# Final Configuration\n# -----------------------------------------------------------------------------\nWORKDIR /home/opencode/workspace\n\n# Expose opencode web port (3000) and Cockpit port (9090)\nEXPOSE 3000 9090\n\n# Hybrid init: entrypoint script chooses tini or systemd based on USE_SYSTEMD env\nENTRYPOINT [\"/usr/local/bin/entrypoint.sh\"]\n";
Expand description

The Dockerfile for building the opencode-cloud-sandbox container image