Skip to content

Commit 30b1c08

Browse files
authored
🤖 feat: add Docker image for mux server (#849)
Adds Dockerfile and docker-compose.yml for running mux server in containers. ## Usage ```bash # Build docker build -t mux-server . # Run docker run -p 3000:3000 -v ~/.mux:/root/.mux mux-server # Or with docker-compose docker compose up -d ``` ## Details - Multi-stage build with slim runtime image (~2GB) - Health check at `/health` - Volume mount for `~/.mux` persistence - Excludes test files during build to avoid rootDir issues - CI smoke test runs in merge queue (validates health + version endpoints) _Generated with `mux`_
1 parent 5e80c97 commit 30b1c08

File tree

4 files changed

+244
-0
lines changed

4 files changed

+244
-0
lines changed

.dockerignore

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Dependencies (will be installed fresh)
2+
node_modules/
3+
4+
# Build outputs
5+
dist/
6+
build/
7+
*.tsbuildinfo
8+
9+
# Git
10+
.git/
11+
.gitignore
12+
13+
# IDE
14+
.idea/
15+
.vscode/
16+
*.swp
17+
*.swo
18+
19+
# Test artifacts
20+
coverage/
21+
.nyc_output/
22+
23+
# Development files
24+
*.log
25+
*.local
26+
.env
27+
.env.*
28+
!.env.example
29+
30+
# Documentation build
31+
docs/book/
32+
33+
# Mobile app (not needed for server)
34+
mobile/
35+
36+
# Electron-specific (not needed for server)
37+
*.dmg
38+
*.exe
39+
*.AppImage
40+
*.snap
41+
*.deb
42+
*.rpm
43+
44+
# Storybook
45+
storybook-static/
46+
47+
# Misc
48+
.DS_Store
49+
Thumbs.db
50+
*.md
51+
!README.md
52+
LICENSE

.github/workflows/ci.yml

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,73 @@ jobs:
171171
env:
172172
ELECTRON_DISABLE_SANDBOX: 1
173173

174+
docker-smoke-test:
175+
name: Docker Smoke Test
176+
runs-on: ${{ github.repository_owner == 'coder' && 'depot-ubuntu-22.04-16' || 'ubuntu-latest' }}
177+
# Only run in merge queue (Docker builds are slow)
178+
if: github.event_name == 'merge_group'
179+
steps:
180+
- name: Checkout code
181+
uses: actions/checkout@v4
182+
with:
183+
fetch-depth: 0 # Required for git describe to find tags
184+
185+
- name: Set up Docker Buildx
186+
uses: docker/setup-buildx-action@v3
187+
188+
- name: Build Docker image
189+
uses: docker/build-push-action@v6
190+
with:
191+
context: .
192+
load: true
193+
tags: mux-server:test
194+
cache-from: type=gha
195+
cache-to: type=gha,mode=max
196+
197+
- name: Start container
198+
run: |
199+
docker run -d --name mux-test -p 3000:3000 mux-server:test
200+
# Wait for server to be ready
201+
for i in {1..30}; do
202+
if curl -sf http://localhost:3000/health; then
203+
echo "Server is ready"
204+
break
205+
fi
206+
echo "Waiting for server... ($i/30)"
207+
sleep 1
208+
done
209+
210+
- name: Health check
211+
run: |
212+
response=$(curl -sf http://localhost:3000/health)
213+
echo "Health response: $response"
214+
if ! echo "$response" | grep -q '"status":"ok"'; then
215+
echo "Health check failed"
216+
exit 1
217+
fi
218+
219+
- name: Version check
220+
run: |
221+
response=$(curl -sf http://localhost:3000/version)
222+
echo "Version response: $response"
223+
# Verify response contains expected fields
224+
if ! echo "$response" | grep -q '"mode":"server"'; then
225+
echo "Version check failed: missing mode=server"
226+
exit 1
227+
fi
228+
if ! echo "$response" | grep -q '"version"'; then
229+
echo "Version check failed: missing version field"
230+
exit 1
231+
fi
232+
233+
- name: Show container logs on failure
234+
if: failure()
235+
run: docker logs mux-test
236+
237+
- name: Cleanup
238+
if: always()
239+
run: docker rm -f mux-test || true
240+
174241
check-codex-comments:
175242
name: Check Codex Comments
176243
runs-on: ${{ github.repository_owner == 'coder' && 'depot-ubuntu-22.04-16' || 'ubuntu-latest' }}

Dockerfile

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
# mux server Docker image
2+
# Multi-stage build for minimal runtime image size
3+
#
4+
# Build: docker build -t mux-server .
5+
# Run: docker run -p 3000:3000 -v ~/.mux:/root/.mux mux-server
6+
#
7+
# See docker-compose.yml for easier orchestration
8+
9+
# ==============================================================================
10+
# Stage 1: Build
11+
# ==============================================================================
12+
FROM node:22-slim AS builder
13+
14+
WORKDIR /app
15+
16+
# Install bun (used for package management and build tooling)
17+
RUN npm install -g bun@1.2
18+
19+
# Install git (needed for version generation)
20+
RUN apt-get update && apt-get install -y git && rm -rf /var/lib/apt/lists/*
21+
22+
# Copy package files first for better layer caching
23+
COPY package.json bun.lock bunfig.toml ./
24+
25+
# Copy postinstall script (needed by bun install)
26+
COPY scripts/postinstall.sh scripts/
27+
28+
# Install build tools needed for native modules
29+
RUN apt-get update && apt-get install -y python3 make g++ && rm -rf /var/lib/apt/lists/*
30+
31+
# Install dependencies (postinstall detects server mode and skips Electron rebuild)
32+
# Note: node-pty is in optionalDependencies and will be built for Node.js
33+
RUN bun install --frozen-lockfile
34+
35+
# Copy source files needed for build
36+
COPY src/ src/
37+
COPY tsconfig.json tsconfig.main.json ./
38+
COPY scripts/generate-version.sh scripts/
39+
COPY index.html terminal.html vite.config.ts ./
40+
COPY public/ public/
41+
COPY static/ static/
42+
43+
# Remove test files (they import from tests/ which is outside rootDir)
44+
RUN find src -name '*.test.ts' -delete
45+
46+
# Initialize git for version script (uses placeholder if not a real repo)
47+
RUN git init && \
48+
git config user.email "docker@build" && \
49+
git config user.name "Docker Build" && \
50+
git add -A && \
51+
git commit -m "docker build" --allow-empty || true
52+
53+
# Generate version info
54+
RUN ./scripts/generate-version.sh
55+
56+
# Build main process (server + backend)
57+
RUN NODE_ENV=production bun x tsc -p tsconfig.main.json && \
58+
NODE_ENV=production bun x tsc-alias -p tsconfig.main.json
59+
60+
# Build renderer (frontend)
61+
RUN bun x vite build
62+
63+
# Copy static assets
64+
RUN mkdir -p dist/static && cp -r static/* dist/static/ 2>/dev/null || true
65+
66+
# ==============================================================================
67+
# Stage 2: Runtime
68+
# ==============================================================================
69+
FROM node:22-slim
70+
71+
WORKDIR /app
72+
73+
# Install runtime dependencies
74+
# - git: required for workspace operations (clone, worktree, etc.)
75+
# - openssh-client: required for SSH runtime support
76+
RUN apt-get update && \
77+
apt-get install -y git openssh-client && \
78+
rm -rf /var/lib/apt/lists/*
79+
80+
# Copy built artifacts from builder
81+
COPY --from=builder /app/dist ./dist
82+
COPY --from=builder /app/node_modules ./node_modules
83+
COPY --from=builder /app/package.json ./
84+
85+
# Create mux data directory
86+
RUN mkdir -p /root/.mux
87+
88+
# Default environment variables
89+
ENV NODE_ENV=production
90+
ENV MUX_HOME=/root/.mux
91+
92+
# Expose server port
93+
EXPOSE 3000
94+
95+
# Health check
96+
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
97+
CMD node -e "fetch('http://localhost:3000/health').then(r => r.ok ? process.exit(0) : process.exit(1)).catch(() => process.exit(1))"
98+
99+
# Run mux server
100+
# --host 0.0.0.0: bind to all interfaces (required for Docker networking)
101+
# --port 3000: default port (can be remapped via docker run -p)
102+
ENTRYPOINT ["node", "dist/cli/index.js", "server"]
103+
CMD ["--host", "0.0.0.0", "--port", "3000"]

docker-compose.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# mux server docker-compose configuration
2+
#
3+
# Quick start:
4+
# docker compose up -d
5+
#
6+
# Add a project:
7+
# docker compose run --rm mux-server --add-project /projects/my-repo
8+
9+
services:
10+
mux-server:
11+
build: .
12+
container_name: mux-server
13+
ports:
14+
- "3000:3000"
15+
volumes:
16+
- mux-data:/root/.mux
17+
# Mount project directories as needed:
18+
# - ~/projects:/projects:rw
19+
restart: unless-stopped
20+
21+
volumes:
22+
mux-data:

0 commit comments

Comments
 (0)