Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

[Feature]: Official multi-arch Docker image and automated build workflow (GHCR / Docker Hub)

Open
#4,198 2 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
55/100
Issue type
Feature
Clarity
Clearly specified
Activity status
Active
Tech stack
bun, docker, github-actions, typescript, vite

Research direction

Start with package.json, bun.lock, gui/, and src/cli/index.ts; verify the documented hub command and the /healthz and /readyz endpoints. Then review the proposed Dockerfile and .github/workflows/docker-publish.yml requirements, including non-root runtime, amd64/arm64 builds, caching, and GHCR tags. Done means the image builds, passes smoke checks, and publishes on releases.

Written by the indexing model from the issue text.

Description

enhancement install priority: P3
Area

Installation or packaging

What are you trying to accomplish?

OpenCodex is widely used not only as a local CLI proxy, but also as a centralized remote hub (on Linux VPS, homelab servers, Docker Compose, and Kubernetes/k3s clusters), following the official Remote Hub Deployment Guide.

Currently, operators who run OpenCodex in containers have to maintain their own external packaging repositories (such as nordz0r/opencodex-docker) with custom scheduled cron workflows to detect new npm/GitHub releases, build the Vite GUI, compile multi-arch images, and push them to container registries.

We would like OpenCodex to provide an official multi-arch container image (linux/amd64 and linux/arm64) published directly to GitHub Container Registry (ghcr.io/lidge-jun/opencodex:<tag> and :latest) upon every release promotion.

What prevents this today?
  1. No official Dockerfile: The repository currently has no container definition. Users wishing to run OpenCodex under Docker or Kubernetes must write their own Dockerfiles, determining how to correctly build the Vite dashboard (gui/), pin Bun versions, set environment variables (OPENCODEX_HOME), and configure file permissions.
  2. Duplicated community effort & release lag: Community packaging repositories must poll for npm/GitHub releases with periodic watchdog workflows. This introduces latency between when an upstream release is published and when the container image becomes available, as well as redundant compute across different operators.
  3. Trust and security: Self-hosters prefer pulling signed or official images from the upstream repository namespace (ghcr.io/lidge-jun/opencodex) rather than relying on third-party community builds.
What should OpenCodex do?
  1. Add a production-ready, security-hardened Dockerfile at the root of the repository:

    • Multi-stage build:
      • Stage 1 (builder): Installs dependencies with bun install --frozen-lockfile, builds the Vite dashboard (cd gui && bun install --frozen-lockfile && bun run build), and prunes dev dependencies.
      • Stage 2 (runtime): Minimal runtime using oven/bun (pinned by digest), copies only the necessary production artifacts (package.json, bun.lock, node_modules, src/, gui/dist/, bin/), creates a dedicated non-root user (USER bun), and defines VOLUME ["/home/bun/.opencodex"].
    • Container Healthcheck: Built-in HEALTHCHECK testing http://127.0.0.1:10100/healthz.
    • Default Entrypoint / CMD: Starts the hub on default port 10100 (bun run src/cli/index.ts start --port 10100).
  2. Add a GitHub Actions workflow (.github/workflows/docker-publish.yml) that:

    • Triggers automatically when a release is published (types: [published]) or via workflow_dispatch.
    • Sets up QEMU and Docker Buildx for multi-architecture builds (linux/amd64,linux/arm64).
    • Leverages GitHub Actions cache (type=gha) for fast builds.
    • Runs a quick container smoke test on the built image (/healthz and /readyz return 200) prior to publishing.
    • Publishes tagged images to GHCR (e.g. ghcr.io/lidge-jun/opencodex:v2.50.0, ghcr.io/lidge-jun/opencodex:2.50.0, and ghcr.io/lidge-jun/opencodex:latest).
Example usage or interface

Here is a complete, production-tested implementation that has been used in production across multiple minor and major OpenCodex versions (from v2.40.0 to v2.50.0):

1. Proposed Dockerfile
# syntax=docker/dockerfile:1
ARG BUN_IMAGE=oven/bun:1.4.0@sha256:5ff609364c049b54eb0ff560ec96319729a972078ef2c755d758f0c6ef89c2d6

# Stage 1: Build dashboard and prepare production dependencies
FROM ${BUN_IMAGE} AS build
RUN apt-get update && apt-get install -y --no-install-recommends git ca-certificates && rm -rf /var/lib/apt/lists/*
WORKDIR /home/bun/app

COPY package.json bun.lock ./
RUN --mount=type=cache,target=/home/bun/.bun/install/cache \
    bun install --frozen-lockfile

# Build the GUI dashboard (vite)
COPY gui/package.json gui/bun.lock* ./gui/
RUN cd gui && bun install --frozen-lockfile

COPY . .
RUN cd gui && bun run build

# Remove development-only toolchains before runtime stage
RUN rm -rf node_modules/@typescript node_modules/typescript

# Stage 2: Minimal runtime
FROM ${BUN_IMAGE} AS runtime
RUN apt-get update && apt-get upgrade -y && rm -rf /var/lib/apt/lists/*
WORKDIR /home/bun/app

ENV OPENCODEX_HOME=/home/bun/.opencodex \
    NODE_ENV=production

COPY --from=build --chown=bun:bun /home/bun/app/package.json ./package.json
COPY --from=build --chown=bun:bun /home/bun/app/bun.lock ./bun.lock
COPY --from=build --chown=bun:bun /home/bun/app/node_modules ./node_modules
COPY --from=build --chown=bun:bun /home/bun/app/src ./src
COPY --from=build --chown=bun:bun /home/bun/app/gui/dist ./gui/dist
COPY --from=build --chown=bun:bun /home/bun/app/bin ./bin

RUN mkdir -p /home/bun/.opencodex && chown -R bun:bun /home/bun

USER bun
VOLUME ["/home/bun/.opencodex"]
EXPOSE 10100

HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --retries=3 \
  CMD bun -e "const r=await fetch('http://127.0.0.1:10100/healthz');if(!r.ok)process.exit(1)"

CMD ["bun", "run", "src/cli/index.ts", "start", "--port", "10100"]
2. Proposed GitHub Actions Workflow (.github/workflows/docker-publish.yml)
name: Publish Container Image

on:
  release:
    types: [published]
  workflow_dispatch:
    inputs:
      tag:
        description: 'Tag to build (e.g. v2.50.0)'
        required: false
        type: string

permissions:
  contents: read
  packages: write

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  docker:
    name: Build & Publish Multi-Arch Image
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Set up QEMU
        uses: docker/setup-qemu-action@v3

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Log in to GitHub Container Registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract metadata (tags, labels)
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          tags: |
            type=semver,pattern={{version}}
            type=semver,pattern={{major}}.{{minor}}
            type=raw,value=latest,enable=${{ github.event_name == 'release' }}

      - name: Build and push image
        uses: docker/build-push-action@v5
        with:
          context: .
          file: ./Dockerfile
          platforms: linux/amd64,linux/arm64
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          cache-from: type=gha
          cache-to: type=gha,mode=max
3. User Experience (Docker Compose)

End users and hub administrators can simply run:

services:
  opencodex:
    image: ghcr.io/lidge-jun/opencodex:latest
    container_name: opencodex-hub
    restart: unless-stopped
    ports:
      - "10100:10100"
    volumes:
      - ./data:/home/bun/.opencodex
Alternatives or workarounds
  1. Third-party community packaging: Users currently rely on community images like nordz0r/opencodex from nordz0r/opencodex-docker. While functional, it requires maintenance outside the core repository and creates an unnecessary third-party trust dependency for end users.
  2. Manual local build / systemd service: Running directly on the host using Node/Bun. This is harder to manage in orchestrated container environments (Kubernetes, Nomad, TrueNAS, unRAID, etc.).
Additional context
  • Upstream documentation already emphasizes headless remote hub setups (Remote Hub Deployment). An official container image is the natural companion to this guide.
  • The built-in /healthz and /readyz endpoints make Kubernetes Liveness and Readiness probes straightforward.
  • Happy to submit this as a Pull Request to dev if maintainers agree with the proposed layout.
Checks
  • I searched existing issues and documentation.
  • This request describes a concrete OpenCodex workflow rather than merely naming a desired technology.
  • I removed secrets and personal data.
Dominant language
TypeScript
Stars
16.9k
Forks
1.3k
Avg merge
7h 38m
Merged PRs (30d)
659

Getting set up

This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from lidge-jun/opencodex

All issues in lidge-jun/opencodex

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.