Files
Charon/docs/plans/debian_migration_spec.md
GitHub Actions e0a39518ba chore: migrate Docker base images from Alpine to Debian Trixie
Migrated all Docker stages from Alpine 3.23 to Debian Trixie (13) to
address critical CVE in Alpine's gosu package and improve security
update frequency.

Key changes:

Updated CADDY_IMAGE to debian:trixie-slim
Added gosu-builder stage to compile gosu 1.17 from source with Go 1.25.6
Migrated all builder stages to golang:1.25-trixie
Updated package manager from apk to apt-get
Updated user/group creation to use groupadd/useradd
Changed nologin path from /sbin/nologin to /usr/sbin/nologin
Security impact:

Resolved gosu Critical CVE (built from source eliminates vulnerable Go stdlib)
Reduced overall CVE count from 6 (bookworm) to 2 (trixie)
Remaining 2 CVEs are glibc-related with no upstream fix available
All Go binaries verified vulnerability-free by Trivy and govulncheck
Verification:

E2E tests: 243 passed (5 pre-existing failures unrelated to migration)
Backend coverage: 87.2%
Frontend coverage: 85.89%
Pre-commit hooks: 13/13 passed
TypeScript: 0 errors
Refs: CVE-2026-0861 (glibc, no upstream fix - accepted risk)
2026-01-20 06:11:59 +00:00

796 lines
23 KiB
Markdown

# Alpine to Debian Slim Migration Specification
> **Version**: 1.0.0
> **Created**: 2026-01-18
> **Status**: PLANNING
> **Author**: Planning Agent
---
## Executive Summary
### Security Rationale
The user has identified a critical CVE in Alpine Linux that necessitates migrating the Docker base images from Alpine to Debian slim. This migration addresses:
1. **Critical CVE Mitigation**: Immediate resolution of the identified Alpine Linux vulnerability
2. **Broader Security Posture**: Debian's larger security team and faster CVE response times
3. **glibc vs musl Compatibility**: Eliminates potential musl libc edge cases that can cause subtle bugs in Go binaries with CGO
4. **Long-term Maintainability**: Debian slim provides a battle-tested, stable base with predictable security update cycles
### Key Benefits of Debian Slim
| Aspect | Alpine | Debian Slim | Advantage |
|--------|--------|-------------|-----------|
| Security Updates | Community-driven | Dedicated security team (Debian Security Team) | Faster CVE patches |
| C Library | musl libc | glibc | Better compatibility with CGO |
| Package Availability | ~10k packages | ~60k packages | More comprehensive |
| DNS Resolution | musl DNS bugs known | glibc mature DNS | More reliable |
| Image Size | ~5MB base | ~25MB base | Alpine smaller, but acceptable trade-off |
---
## Current State Analysis
### Dockerfile Structure Overview
The current `Dockerfile` is a multi-stage build with the following Alpine-based stages:
#### Builder Stages (Alpine-based)
| Stage | Base Image | Purpose |
|-------|------------|---------|
| `xx` | `tonistiigi/xx:1.9.0` | Cross-compilation helpers (unchanged) |
| `frontend-builder` | `node:24.13.0-alpine` | Build React frontend |
| `backend-builder` | `golang:1.25-alpine` | Build Go backend with CGO |
| `caddy-builder` | `golang:1.25-alpine` | Build Caddy with plugins |
| `crowdsec-builder` | `golang:1.25.6-alpine` | Build CrowdSec from source |
| `crowdsec-fallback` | `alpine:3.23` | Fallback binary download |
#### Runtime Stage (Alpine-based)
| Stage | Base Image | Purpose |
|-------|------------|---------|
| Final runtime | `alpine:3.23` (via `CADDY_IMAGE` ARG) | Production runtime |
### Alpine Packages Currently Installed
#### Builder Stage Packages (apk)
```dockerfile
# backend-builder
apk add --no-cache clang lld
xx-apk add --no-cache gcc musl-dev sqlite-dev
# caddy-builder
apk add --no-cache git
# crowdsec-builder
apk add --no-cache git clang lld
xx-apk add --no-cache gcc musl-dev
# crowdsec-fallback
apk add --no-cache curl tar
```
#### Runtime Stage Packages (apk)
```dockerfile
# Final runtime image
apk --no-cache add bash ca-certificates sqlite-libs sqlite tzdata curl gettext su-exec libcap-utils
apk --no-cache upgrade
apk --no-cache upgrade c-ares
```
### Alpine-Specific Commands in Dockerfile
1. **User/Group Creation**:
```dockerfile
RUN addgroup -g 1000 charon && \
adduser -D -u 1000 -G charon -h /app -s /sbin/nologin charon
```
2. **Package Management**:
- `apk add --no-cache`
- `apk --no-cache upgrade`
- `xx-apk add --no-cache` (cross-compilation)
3. **Privilege Dropping**:
- Uses `su-exec` (Alpine-specific lightweight sudo replacement)
### Alpine-Specific Commands in docker-entrypoint.sh
1. **User Group Management**:
```bash
addgroup -g "$DOCKER_SOCK_GID" docker 2>/dev/null || true
addgroup charon docker 2>/dev/null || true
addgroup charon "$GROUP_NAME" 2>/dev/null || true
```
2. **File Statistics**:
```bash
stat -c '%a' "$PLUGINS_DIR" # Alpine stat syntax
stat -c '%g' /var/run/docker.sock
```
### CI/CD Workflow References
Files referencing Alpine that need updates:
| File | Line | Reference |
|------|------|-----------|
| `.github/workflows/docker-build.yml` | 103-104 | `caddy:2-alpine` image pull |
| `.github/workflows/security-weekly-rebuild.yml` | 53-54 | `caddy:2-alpine` image pull |
| `.github/workflows/security-weekly-rebuild.yml` | 127 | `apk info` command for package check |
---
## Target State: Debian Slim Configuration
### Recommended Base Images
| Current Alpine Image | Debian Slim Replacement | Notes |
|---------------------|-------------------------|-------|
| `node:24.13.0-alpine` | `node:24.13.0-slim` | Node.js official slim variant |
| `golang:1.25-alpine` | `golang:1.25-bookworm` | Go official Debian variant |
| `golang:1.25.6-alpine` | `golang:1.25.6-bookworm` | CrowdSec builder |
| `alpine:3.23` | `debian:bookworm-slim` | Runtime image |
| `caddy:2-alpine` | Build Caddy ourselves | Already building from source |
### Package Mapping: Alpine → Debian
| Alpine Package | Debian Equivalent | Notes |
|----------------|-------------------|-------|
| `bash` | `bash` | Same |
| `ca-certificates` | `ca-certificates` | Same |
| `sqlite-libs` | `libsqlite3-0` | Runtime library |
| `sqlite` | `sqlite3` | CLI tool |
| `sqlite-dev` | `libsqlite3-dev` | Build dependency |
| `tzdata` | `tzdata` | Same |
| `curl` | `curl` | Same |
| `gettext` | `gettext-base` | Smaller variant with envsubst |
| `su-exec` | `gosu` | Debian equivalent |
| `libcap-utils` | `libcap2-bin` | Contains setcap |
| `clang` | `clang` | Same |
| `lld` | `lld` | Same |
| `gcc` | `gcc` | Same (may need build-essential) |
| `musl-dev` | `libc6-dev` | glibc development files |
| `git` | `git` | Same |
| `tar` | `tar` | Usually pre-installed |
| `c-ares` | `libc-ares2` | Async DNS library |
### User/Group Creation Syntax Changes
| Operation | Alpine | Debian |
|-----------|--------|--------|
| Create group | `addgroup -g 1000 charon` | `groupadd -g 1000 charon` |
| Create user | `adduser -D -u 1000 -G charon -h /app -s /sbin/nologin charon` | `useradd -u 1000 -g charon -d /app -s /usr/sbin/nologin -M charon` |
| Add to group | `addgroup charon docker` | `usermod -aG docker charon` |
> **Note**: Debian uses `/usr/sbin/nologin` instead of Alpine's `/sbin/nologin`
### Entrypoint Script Changes
The `docker-entrypoint.sh` requires these changes:
1. **Replace `addgroup`/`adduser` with `groupadd`/`useradd`**
2. **Replace `su-exec` with `gosu`**
3. **Update stat command syntax** (BSD vs GNU - Debian uses GNU which is same)
---
## Detailed Migration Steps
### Phase 1: Builder Stage Migrations
#### Step 1.1: Frontend Builder
**File**: `Dockerfile`
**Lines**: 27-47
```dockerfile
# BEFORE (Alpine)
FROM --platform=$BUILDPLATFORM node:24.13.0-alpine AS frontend-builder
# AFTER (Debian slim)
FROM --platform=$BUILDPLATFORM node:24.13.0-slim AS frontend-builder
```
**Notes**:
- No package installation changes needed (npm handles dependencies)
- Environment variables remain the same
#### Step 1.2: Backend Builder
**File**: `Dockerfile`
**Lines**: 49-143
```dockerfile
# BEFORE (Alpine)
FROM --platform=$BUILDPLATFORM golang:1.25-alpine AS backend-builder
# ...
RUN apk add --no-cache clang lld
RUN xx-apk add --no-cache gcc musl-dev sqlite-dev
# AFTER (Debian)
FROM --platform=$BUILDPLATFORM golang:1.25-bookworm AS backend-builder
# ...
RUN apt-get update && apt-get install -y --no-install-recommends \
clang lld \
&& rm -rf /var/lib/apt/lists/*
```
**Critical Change - CGO with glibc**:
- Remove the clang wrapper workaround for ARM64 gold linker (lines 67-91)
- glibc environments handle this natively
- Change `xx-apk` to cross-compilation apt packages or use `TARGETPLATFORM` specific installs
**xx-go Cross Compilation Notes**:
- The `xx` helper supports Debian-based images
- Replace `xx-apk` with appropriate Debian cross-compilation setup
#### Step 1.3: Caddy Builder
**File**: `Dockerfile`
**Lines**: 145-202
```dockerfile
# BEFORE (Alpine)
FROM --platform=$BUILDPLATFORM golang:1.25-alpine AS caddy-builder
# ...
RUN apk add --no-cache git
# AFTER (Debian)
FROM --platform=$BUILDPLATFORM golang:1.25-bookworm AS caddy-builder
# ...
RUN apt-get update && apt-get install -y --no-install-recommends git \
&& rm -rf /var/lib/apt/lists/*
```
#### Step 1.4: CrowdSec Builder
**File**: `Dockerfile`
**Lines**: 204-256
```dockerfile
# BEFORE (Alpine)
FROM --platform=$BUILDPLATFORM golang:1.25.6-alpine AS crowdsec-builder
# ...
RUN apk add --no-cache git clang lld
RUN xx-apk add --no-cache gcc musl-dev
# AFTER (Debian)
FROM --platform=$BUILDPLATFORM golang:1.25.6-bookworm AS crowdsec-builder
# ...
RUN apt-get update && apt-get install -y --no-install-recommends \
git clang lld gcc libc6-dev \
&& rm -rf /var/lib/apt/lists/*
```
#### Step 1.5: CrowdSec Fallback
**File**: `Dockerfile`
**Lines**: 258-293
```dockerfile
# BEFORE (Alpine)
FROM alpine:3.23 AS crowdsec-fallback
# ...
RUN apk add --no-cache curl tar
# AFTER (Debian)
FROM debian:bookworm-slim AS crowdsec-fallback
# ...
RUN apt-get update && apt-get install -y --no-install-recommends \
curl ca-certificates tar \
&& rm -rf /var/lib/apt/lists/*
```
> **⚠️ IMPORTANT**: Debian slim does NOT include `tar` by default. It must be explicitly installed for CrowdSec binary extraction.
### Phase 2: Runtime Stage Migration
#### Step 2.1: Base Image Change
**File**: `Dockerfile`
**Lines**: 23, 295-303
```dockerfile
# BEFORE (Alpine)
ARG CADDY_IMAGE=alpine:3.23
# ...
FROM ${CADDY_IMAGE}
# ...
RUN apk --no-cache add bash ca-certificates sqlite-libs sqlite tzdata curl gettext su-exec libcap-utils \
&& apk --no-cache upgrade \
&& apk --no-cache upgrade c-ares
# AFTER (Debian)
ARG CADDY_IMAGE=debian:bookworm-slim
# ...
FROM ${CADDY_IMAGE}
# ...
RUN apt-get update && apt-get install -y --no-install-recommends \
bash ca-certificates libsqlite3-0 sqlite3 tzdata curl gettext-base gosu libcap2-bin libc-ares2 \
&& apt-get upgrade -y \
&& rm -rf /var/lib/apt/lists/*
```
#### Step 2.2: User Creation
**File**: `Dockerfile`
**Lines**: 307-308
```dockerfile
# BEFORE (Alpine)
RUN addgroup -g 1000 charon && \
adduser -D -u 1000 -G charon -h /app -s /sbin/nologin charon
# AFTER (Debian)
RUN groupadd -g 1000 charon && \
useradd -u 1000 -g charon -d /app -s /usr/sbin/nologin -M charon
```
> **⚠️ PATH CHANGE**: Debian uses `/usr/sbin/nologin` instead of Alpine's `/sbin/nologin`.
#### Step 2.3: setcap Command
**File**: `Dockerfile`
**Line**: 318
```dockerfile
# BEFORE (Alpine - same)
RUN setcap 'cap_net_bind_service=+ep' /usr/bin/caddy
# AFTER (Debian - same, but requires libcap2-bin)
RUN setcap 'cap_net_bind_service=+ep' /usr/bin/caddy
```
### Phase 3: Entrypoint Script Migration
**File**: `.docker/docker-entrypoint.sh`
> **⚠️ CRITICAL**: Debian slim does NOT include `wget`. The entrypoint uses wget for the Caddy readiness check. All `wget` calls must be replaced with `curl` equivalents.
#### Step 3.0: Replace wget with curl for Caddy Readiness Check
```bash
# BEFORE (Alpine - uses wget)
wget -q --spider http://localhost:2019/config/ || exit 1
# AFTER (Debian - uses curl)
curl -sf http://localhost:2019/config/ > /dev/null || exit 1
```
#### Step 3.1: Replace su-exec with gosu
```bash
# BEFORE (Alpine)
run_as_charon() {
if is_root; then
su-exec charon "$@"
else
"$@"
fi
}
# AFTER (Debian)
run_as_charon() {
if is_root; then
gosu charon "$@"
else
"$@"
fi
}
```
#### Step 3.2: Replace addgroup/adduser with groupadd/usermod
```bash
# BEFORE (Alpine)
addgroup -g "$DOCKER_SOCK_GID" docker 2>/dev/null || true
addgroup charon docker 2>/dev/null || true
# AFTER (Debian)
groupadd -g "$DOCKER_SOCK_GID" docker 2>/dev/null || true
usermod -aG docker charon 2>/dev/null || true
```
```bash
# BEFORE (Alpine)
addgroup charon "$GROUP_NAME" 2>/dev/null || true
# AFTER (Debian)
usermod -aG "$GROUP_NAME" charon 2>/dev/null || true
```
#### Step 3.3: stat Command (No Change Required)
Both Alpine and Debian use GNU coreutils `stat`, so the syntax remains:
```bash
stat -c '%a' "$PLUGINS_DIR"
stat -c '%g' /var/run/docker.sock
```
### Phase 4: CI/CD Workflow Updates
#### Step 4.1: docker-build.yml
**File**: `.github/workflows/docker-build.yml`
**Lines**: 103-104
```yaml
# BEFORE
run: |
docker pull caddy:2-alpine
DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' caddy:2-alpine)
# AFTER
# Remove this step entirely - we build Caddy from source
# Or update to pull debian:bookworm-slim for digest verification
run: |
docker pull debian:bookworm-slim
DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' debian:bookworm-slim)
```
#### Step 4.2: security-weekly-rebuild.yml
**File**: `.github/workflows/security-weekly-rebuild.yml`
**Lines 53-54** (Caddy digest):
```yaml
# Remove or update similar to docker-build.yml
```
**Lines 127-133** (Package version check):
```yaml
# BEFORE
- name: Check Alpine package versions
run: |
echo "Checking key security packages:" >> $GITHUB_STEP_SUMMARY
docker run --rm --entrypoint "" ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build.outputs.digest }} \
sh -c "apk update >/dev/null 2>&1 && apk info c-ares curl libcurl openssl" >> $GITHUB_STEP_SUMMARY
# AFTER
- name: Check Debian package versions
run: |
echo "Checking key security packages:" >> $GITHUB_STEP_SUMMARY
docker run --rm --entrypoint "" ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build.outputs.digest }} \
sh -c "dpkg -l | grep -E 'libc-ares|curl|libcurl|openssl|libssl'" >> $GITHUB_STEP_SUMMARY
```
### Phase 5: Cross-Compilation Considerations
#### xx Helper Compatibility
The `tonistiigi/xx` project supports both Alpine and Debian. Key changes:
1. **Remove xx-apk usage**: Replace with native apt-get for the target architecture
2. **CGO Cross-Compilation**: Debian has better cross-compilation toolchain support
3. **Remove Gold Linker Workaround**: The clang wrapper hack (lines 67-91) for Go 1.25 ARM64 can be removed
```dockerfile
# Debian cross-compilation setup (replaces xx-apk)
ARG TARGETARCH
RUN dpkg --add-architecture ${TARGETARCH} && \
apt-get update && \
apt-get install -y --no-install-recommends \
gcc-$(dpkg-architecture -A ${TARGETARCH} -qDEB_TARGET_GNU_TYPE) \
libc6-dev:${TARGETARCH} \
libsqlite3-dev:${TARGETARCH} \
&& rm -rf /var/lib/apt/lists/*
```
**Alternative**: Continue using `xx` helper which has Debian support:
```dockerfile
COPY --from=xx / /
RUN xx-apt install -y libc6-dev libsqlite3-dev
```
---
## Testing Strategy
### Phase 1: Local Build Verification
1. **Build All Architectures**:
```bash
docker buildx build --platform linux/amd64,linux/arm64 -t charon:debian-test .
```
2. **Verify Binary Execution**:
```bash
docker run --rm charon:debian-test /app/charon --version
docker run --rm charon:debian-test caddy version
docker run --rm charon:debian-test cscli version
```
3. **Verify Package Installation**:
```bash
docker run --rm --entrypoint bash charon:debian-test -c "which gosu setcap curl sqlite3"
```
### Phase 2: Functional Testing
1. **Run E2E Playwright Tests**:
```bash
npx playwright test --project=chromium
```
2. **Run Backend Unit Tests**:
```bash
make test-backend
```
3. **Run Docker Compose Stack**:
```bash
docker compose -f .docker/compose/docker-compose.yml up -d
# Verify all services start correctly
curl http://localhost:8080/api/v1/health
```
### Phase 3: Security Verification
1. **Trivy Vulnerability Scan**:
```bash
trivy image charon:debian-test --severity CRITICAL,HIGH
```
2. **Verify No Alpine CVE Present**:
```bash
trivy image charon:debian-test | grep -i alpine
# Should return nothing
```
3. **Verify User Permissions**:
```bash
docker run --rm charon:debian-test id
# Should show: uid=1000(charon) gid=1000(charon)
```
### Phase 4: Performance Validation
1. **Compare Image Sizes**:
```bash
docker images | grep charon
# Alpine: ~150MB, Debian: ~200MB (acceptable)
```
2. **Startup Time Comparison**:
```bash
time docker run --rm charon:debian-test /app/charon --version
```
3. **Memory Usage Comparison**:
```bash
docker stats --no-stream charon-container
```
---
## Rollback Plan
### Immediate Rollback
1. **Revert Dockerfile Changes**:
```bash
git checkout main -- Dockerfile
git checkout main -- .docker/docker-entrypoint.sh
```
2. **Rebuild with Alpine**:
```bash
docker buildx build --no-cache -t charon:alpine-rollback .
```
### Staged Rollback
If issues are discovered post-deployment:
1. **Tag Current (Debian) Image**:
```bash
docker tag ghcr.io/wikid82/charon:latest ghcr.io/wikid82/charon:debian-v1
```
2. **Push Previous Alpine Image**:
```bash
docker tag ghcr.io/wikid82/charon:v{previous} ghcr.io/wikid82/charon:latest
docker push ghcr.io/wikid82/charon:latest
```
3. **Document Rollback**:
- Create GitHub issue documenting the reason
- Update CHANGELOG.md with rollback notice
### Rollback Criteria
Trigger rollback if any of these occur:
- [ ] Critical security vulnerability in Debian base
- [ ] Application crashes on startup
- [ ] E2E tests fail > 10%
- [ ] Memory usage increases > 50%
- [ ] Build times increase > 3x
---
## Security Considerations
### Security Features to Maintain
| Feature | Alpine Implementation | Debian Implementation | Status |
|---------|----------------------|----------------------|--------|
| Non-root user | `adduser -D` | `useradd -M` | ✅ Maintain |
| Privilege dropping | `su-exec` | `gosu` | ✅ Maintain |
| Capability binding | `setcap` via `libcap-utils` | `setcap` via `libcap2-bin` | ✅ Maintain |
| Read-only filesystem | N/A | N/A | N/A |
| Minimal packages | `--no-cache` | `--no-install-recommends` | ✅ Maintain |
| Security upgrades | `apk upgrade` | `apt-get upgrade` | ✅ Maintain |
| HEALTHCHECK | Present | Present | ✅ Maintain |
### Security Enhancements with Debian
1. **glibc Security**: Better Address Space Layout Randomization (ASLR)
2. **Faster CVE Patches**: Debian Security Team is larger and faster
3. **No musl Edge Cases**: Eliminates subtle bugs in Go binaries with CGO
4. **SELinux Compatibility**: Debian has better SELinux support if needed
### Security Scanning Updates
Update Trivy configuration to scan for Debian-specific vulnerabilities:
```yaml
# .github/workflows/security-weekly-rebuild.yml
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@...
with:
image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build.outputs.digest }}
vuln-type: 'os,library'
severity: 'CRITICAL,HIGH'
```
---
## Implementation Checklist
### Pre-Migration
- [ ] Create feature branch: `feature/debian-migration`
- [ ] Document current Alpine image hashes for comparison
- [ ] Run full E2E test suite as baseline
- [ ] Create backup of working Dockerfile
- [ ] **Backup current production image for rollback**:
```bash
docker tag ghcr.io/wikid82/charon:latest ghcr.io/wikid82/charon:pre-debian-migration
docker push ghcr.io/wikid82/charon:pre-debian-migration
```
### Dockerfile Changes
- [ ] Update `frontend-builder` stage to Debian slim
- [ ] Update `backend-builder` stage to Debian bookworm
- [ ] Update `caddy-builder` stage to Debian bookworm
- [ ] Update `crowdsec-builder` stage to Debian bookworm
- [ ] Update `crowdsec-fallback` stage to Debian slim
- [ ] Update final runtime stage to Debian slim
- [ ] Update `CADDY_IMAGE` ARG default
- [ ] Replace all `apk` commands with `apt-get`
- [ ] Update user/group creation commands
- [ ] Replace `su-exec` with `gosu`
- [ ] Remove ARM64 clang wrapper workaround
- [ ] Update cross-compilation setup for xx helper
### Entrypoint Changes
- [ ] Replace `su-exec` with `gosu`
- [ ] Replace `addgroup` with `groupadd`
- [ ] Replace `adduser` with `usermod -aG`
### CI/CD Changes
- [ ] Update `docker-build.yml` Caddy digest step
- [ ] Update `security-weekly-rebuild.yml` package check
- [ ] Update any other workflows referencing Alpine
- [ ] **Update Renovate configuration** (`renovate.json`) to track Debian base image updates (see Appendix B)
### Testing
- [ ] Build multi-architecture image (amd64, arm64)
- [ ] Run all E2E Playwright tests
- [ ] Run all backend unit tests
- [ ] Run Trivy vulnerability scan
- [ ] Verify non-root user execution
- [ ] Verify CrowdSec initialization
- [ ] Verify Caddy startup
- [ ] **gosu functionality test**: Verify privilege dropping works correctly
```bash
docker run --rm charon:debian-test gosu charon id
# Expected: uid=1000(charon) gid=1000(charon) groups=1000(charon)
docker run --rm charon:debian-test gosu charon whoami
# Expected: charon
```
- [ ] **Docker socket integration test**: Verify socket group mapping works
```bash
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock charon:debian-test \
bash -c "stat -c '%g' /var/run/docker.sock && groups charon"
# Verify charon user is added to the docker socket's group
```
### Documentation
- [ ] Update README.md if any user-facing changes
- [ ] Update CHANGELOG.md with migration details
- [ ] Update `docs/DOCKER.md` with Debian-specific instructions
- [ ] Update `docs/features.md` to reflect base image change
- [ ] Archive this plan to `docs/implementation/`
### Post-Migration
- [ ] Monitor production for 48 hours
- [ ] Verify no regression in vulnerability reports
- [ ] Close related security issues/CVEs
- [ ] Remove any Alpine-specific workarounds from codebase
---
## Appendix A: Complete Debian Package List
```dockerfile
# Runtime packages
RUN apt-get update && apt-get install -y --no-install-recommends \
bash \
ca-certificates \
curl \
gettext-base \
gosu \
libc-ares2 \
libcap2-bin \
libsqlite3-0 \
sqlite3 \
tzdata \
&& apt-get upgrade -y \
&& rm -rf /var/lib/apt/lists/*
```
## Appendix B: Renovate Configuration Updates
If using Renovate for dependency management, update `renovate.json`:
```json
{
"regexManagers": [
{
"fileMatch": ["^Dockerfile$"],
"matchStrings": ["ARG CADDY_IMAGE=debian:(?<currentValue>[\\w.-]+)"],
"depNameTemplate": "debian",
"datasourceTemplate": "docker"
}
]
}
```
## Appendix C: Image Size Comparison (Expected)
| Component | Alpine Size | Debian Size | Delta |
|-----------|-------------|-------------|-------|
| Base image | 5 MB | 25 MB | +20 MB |
| Runtime packages | 45 MB | 55 MB | +10 MB |
| Go binary (Charon) | 30 MB | 30 MB | 0 |
| Caddy binary | 45 MB | 45 MB | 0 |
| CrowdSec binaries | 25 MB | 25 MB | 0 |
| Frontend assets | 10 MB | 10 MB | 0 |
| **Total** | **~160 MB** | **~190 MB** | **+30 MB** |
*Note: Actual sizes may vary. The ~30MB increase is an acceptable trade-off for improved security.*
---
## References
- [Debian Docker Official Images](https://hub.docker.com/_/debian)
- [Node.js Docker Official Images](https://hub.docker.com/_/node)
- [Go Docker Official Images](https://hub.docker.com/_/golang)
- [gosu GitHub Repository](https://github.com/tianon/gosu)
- [tonistiigi/xx Cross-Compilation](https://github.com/tonistiigi/xx)
- [Alpine vs Debian for Docker](https://docs.docker.com/build/building/best-practices/)
- [musl vs glibc Considerations](https://wiki.musl-libc.org/functional-differences-from-glibc.html)