From 48c6273082ecbf3c17cace30860772859c9f0393 Mon Sep 17 00:00:00 2001 From: Michael Suchacz <203725896+ibetitsmike@users.noreply.github.com> Date: Tue, 2 Dec 2025 17:14:30 +0000 Subject: [PATCH 1/3] =?UTF-8?q?=F0=9F=A4=96=20feat:=20add=20Docker=20image?= =?UTF-8?q?=20for=20mux=20server?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds Dockerfile and docker-compose.yml for running mux server in containers. - Multi-stage build: slim runtime image (~2GB) - Health check endpoint at /health - Volume mount for ~/.mux persistence - Excludes test files during build to avoid rootDir issues --- .dockerignore | 52 +++++++++++++++++++++++ Dockerfile | 103 +++++++++++++++++++++++++++++++++++++++++++++ docker-compose.yml | 22 ++++++++++ 3 files changed, 177 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 docker-compose.yml diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000000..032ae770fa --- /dev/null +++ b/.dockerignore @@ -0,0 +1,52 @@ +# Dependencies (will be installed fresh) +node_modules/ + +# Build outputs +dist/ +build/ +*.tsbuildinfo + +# Git +.git/ +.gitignore + +# IDE +.idea/ +.vscode/ +*.swp +*.swo + +# Test artifacts +coverage/ +.nyc_output/ + +# Development files +*.log +*.local +.env +.env.* +!.env.example + +# Documentation build +docs/book/ + +# Mobile app (not needed for server) +mobile/ + +# Electron-specific (not needed for server) +*.dmg +*.exe +*.AppImage +*.snap +*.deb +*.rpm + +# Storybook +storybook-static/ + +# Misc +.DS_Store +Thumbs.db +*.md +!README.md +LICENSE diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000..eeb113bda9 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,103 @@ +# mux server Docker image +# Multi-stage build for minimal runtime image size +# +# Build: docker build -t mux-server . +# Run: docker run -p 3000:3000 -v ~/.mux:/root/.mux mux-server +# +# See docker-compose.yml for easier orchestration + +# ============================================================================== +# Stage 1: Build +# ============================================================================== +FROM node:22-slim AS builder + +WORKDIR /app + +# Install bun (used for package management and build tooling) +RUN npm install -g bun@1.2 + +# Install git (needed for version generation) +RUN apt-get update && apt-get install -y git && rm -rf /var/lib/apt/lists/* + +# Copy package files first for better layer caching +COPY package.json bun.lock bunfig.toml ./ + +# Copy postinstall script (needed by bun install) +COPY scripts/postinstall.sh scripts/ + +# Install build tools needed for native modules +RUN apt-get update && apt-get install -y python3 make g++ && rm -rf /var/lib/apt/lists/* + +# Install dependencies (postinstall detects server mode and skips Electron rebuild) +# Note: node-pty is in optionalDependencies and will be built for Node.js +RUN bun install --frozen-lockfile + +# Copy source files needed for build +COPY src/ src/ +COPY tsconfig.json tsconfig.main.json ./ +COPY scripts/generate-version.sh scripts/ +COPY index.html terminal.html vite.config.ts ./ +COPY public/ public/ +COPY static/ static/ + +# Remove test files (they import from tests/ which is outside rootDir) +RUN find src -name '*.test.ts' -delete + +# Initialize git for version script (uses placeholder if not a real repo) +RUN git init && \ + git config user.email "docker@build" && \ + git config user.name "Docker Build" && \ + git add -A && \ + git commit -m "docker build" --allow-empty || true + +# Generate version info +RUN ./scripts/generate-version.sh + +# Build main process (server + backend) +RUN NODE_ENV=production bun x tsc -p tsconfig.main.json && \ + NODE_ENV=production bun x tsc-alias -p tsconfig.main.json + +# Build renderer (frontend) +RUN bun x vite build + +# Copy static assets +RUN mkdir -p dist/static && cp -r static/* dist/static/ 2>/dev/null || true + +# ============================================================================== +# Stage 2: Runtime +# ============================================================================== +FROM node:22-slim + +WORKDIR /app + +# Install runtime dependencies +# - git: required for workspace operations (clone, worktree, etc.) +# - openssh-client: required for SSH runtime support +RUN apt-get update && \ + apt-get install -y git openssh-client && \ + rm -rf /var/lib/apt/lists/* + +# Copy built artifacts from builder +COPY --from=builder /app/dist ./dist +COPY --from=builder /app/node_modules ./node_modules +COPY --from=builder /app/package.json ./ + +# Create mux data directory +RUN mkdir -p /root/.mux + +# Default environment variables +ENV NODE_ENV=production +ENV MUX_HOME=/root/.mux + +# Expose server port +EXPOSE 3000 + +# Health check +HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ + CMD node -e "fetch('http://localhost:3000/health').then(r => r.ok ? process.exit(0) : process.exit(1)).catch(() => process.exit(1))" + +# Run mux server +# --host 0.0.0.0: bind to all interfaces (required for Docker networking) +# --port 3000: default port (can be remapped via docker run -p) +ENTRYPOINT ["node", "dist/cli/index.js", "server"] +CMD ["--host", "0.0.0.0", "--port", "3000"] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000000..1ecfa39534 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,22 @@ +# mux server docker-compose configuration +# +# Quick start: +# docker compose up -d +# +# Add a project: +# docker compose run --rm mux-server --add-project /projects/my-repo + +services: + mux-server: + build: . + container_name: mux-server + ports: + - "3000:3000" + volumes: + - mux-data:/root/.mux + # Mount project directories as needed: + # - ~/projects:/projects:rw + restart: unless-stopped + +volumes: + mux-data: From d6acab8d42fac8247c135deb50b2e4596c280c02 Mon Sep 17 00:00:00 2001 From: Michael Suchacz <203725896+ibetitsmike@users.noreply.github.com> Date: Wed, 3 Dec 2025 07:21:53 +0000 Subject: [PATCH 2/3] ci: add Docker smoke test for health and version endpoints --- .github/workflows/ci.yml | 66 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 86bcea98b0..83fdfda6d7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -171,6 +171,72 @@ jobs: env: ELECTRON_DISABLE_SANDBOX: 1 + docker-smoke-test: + name: Docker Smoke Test + runs-on: ${{ github.repository_owner == 'coder' && 'depot-ubuntu-22.04-16' || 'ubuntu-latest' }} + if: github.event.inputs.test_filter == '' + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 # Required for git describe to find tags + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build Docker image + uses: docker/build-push-action@v6 + with: + context: . + load: true + tags: mux-server:test + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Start container + run: | + docker run -d --name mux-test -p 3000:3000 mux-server:test + # Wait for server to be ready + for i in {1..30}; do + if curl -sf http://localhost:3000/health; then + echo "Server is ready" + break + fi + echo "Waiting for server... ($i/30)" + sleep 1 + done + + - name: Health check + run: | + response=$(curl -sf http://localhost:3000/health) + echo "Health response: $response" + if ! echo "$response" | grep -q '"status":"ok"'; then + echo "Health check failed" + exit 1 + fi + + - name: Version check + run: | + response=$(curl -sf http://localhost:3000/version) + echo "Version response: $response" + # Verify response contains expected fields + if ! echo "$response" | grep -q '"mode":"server"'; then + echo "Version check failed: missing mode=server" + exit 1 + fi + if ! echo "$response" | grep -q '"version"'; then + echo "Version check failed: missing version field" + exit 1 + fi + + - name: Show container logs on failure + if: failure() + run: docker logs mux-test + + - name: Cleanup + if: always() + run: docker rm -f mux-test || true + check-codex-comments: name: Check Codex Comments runs-on: ${{ github.repository_owner == 'coder' && 'depot-ubuntu-22.04-16' || 'ubuntu-latest' }} From ba79a05546f4901e2fcc1fdd2215f34cbad8a91d Mon Sep 17 00:00:00 2001 From: Michael Suchacz <203725896+ibetitsmike@users.noreply.github.com> Date: Wed, 3 Dec 2025 07:22:12 +0000 Subject: [PATCH 3/3] ci: only run Docker smoke test in merge queue --- .github/workflows/ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 83fdfda6d7..85b02738ff 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -174,7 +174,8 @@ jobs: docker-smoke-test: name: Docker Smoke Test runs-on: ${{ github.repository_owner == 'coder' && 'depot-ubuntu-22.04-16' || 'ubuntu-latest' }} - if: github.event.inputs.test_filter == '' + # Only run in merge queue (Docker builds are slow) + if: github.event_name == 'merge_group' steps: - name: Checkout code uses: actions/checkout@v4