Container Base Image Plan 1
Scope: Prepare the dual-image migration infrastructure and build the Debian-slim Docker image locally, confirming all system tools and Python packages work on the new base before any Railway deployment. Prior plan: None
Task 1 — Duplicate the Config folder for the new Debian-slim image
The current deployment at
ghcr.io/erikdakoda/librechat-git:latest(Alpine-based) must remain completely untouched and fully functional throughout the migration. To achieve this, create a parallel config folder for the Debian-slim build. Separation is enforced entirely by the folder name — individual files keep the same names.
- Create
Forge/Configs-debian/as a full duplicate ofForge/Configs/(includingMCP_Servers/subfolder). All files keep their original names — no.debiansuffixes. - Verify that the original
Forge/Configs/folder is UNCHANGED — the current Alpine deployment must continue to work identically. - The new Dockerfile will push to a SEPARATE GHCR image tag:
ghcr.io/erikdakoda/librechat-git:debian-slim(NOTlatest). This ensures pushing the new image does not overwrite the current Alpine image.
Task 2 — Update the Debian Dockerfile for Debian-slim
No Debian-based LibreChat image exists on GHCR — all variants are Alpine. Use a 3-stage build: copy the pre-built app from the official Alpine image, rebuild node_modules for glibc in a builder stage, then create a clean runtime image.
The final Dockerfile uses this structure:
- source stage —
FROM ghcr.io/danny-avila/librechat:v0.8.5-rc1— extract the pre-built LibreChat app - builder stage —
FROM node:20-slim— install build tools (python3, make, g++), copy/appfrom source,rm -rf node_modules && npm install --omit=devfor a clean glibc production install, clean npm cache - runtime stage —
FROM node:20-slim— install runtime system packages (git, curl, wget, nano, python3), copy uv fromghcr.io/astral-sh/uv:latest, copy/appfrom builder, install Python packages viauv pip install --system(no python3-pip — saves ~40MB), remove PEP 668 EXTERNALLY-MANAGED marker
Key differences from the original plan’s 2-stage approach:
- A 3-stage build is necessary because
npm rebuildon the copied musl node_modules leaves musl prebuilds alongside glibc ones (~1.4GB bloat). A freshnpm install --omit=devin a builder stage produces clean glibc-only node_modules (~400-600MB). - Build tools (python3, make, g++) exist only in the builder stage, not the runtime image.
python3-pipis NOT installed in runtime —uv pip install --systemis used instead (~40MB savings).python3IS installed in the runtime stage (needed by MCP servers and uv).
Update Forge/Configs-debian/Dockerfile.librechat with the 3-stage content. Do NOT push the image yet — that happens in Task 4.
Task 3 — Update startup.sh for Debian-slim compatibility
The new startup script at
Forge/Configs-debian/startup.shcurrently uses#!/bin/shand Alpine conventions. On Debian-slim,bashis available, and the script should use it.
- Change the shebang from
#!/bin/shto#!/bin/bash(bash is now available) - Update the config source path from
Forge/Configs/LibreChat_Service/librechat.yamltoForge/Configs-debian/librechat.yaml— the Debian startup script should reference its own config folder - Review every command in the script for Alpine-specific behavior:
gitcommands: work identically on Debianchmod -R 777: works identicallymkdir -p: works identicallycp: works identicallyecho: works identically
- The script should not need any
apkorapt-getcalls — system packages are installed at build time in the Dockerfile - Verify the
exec npm run backendline works on the new base (it should — same LibreChat entry point) - Update the comment at the top to reference the
:debian-slimimage tag - Update
Forge/Configs-debian/startup.shwith any changes
Task 4 — Build and test the Docker image locally
Build the custom image from the Debian Dockerfile and verify it starts correctly. This is the critical validation step before any Railway deployment. You need Docker installed locally and a GitHub PAT with
write:packagesscope.
⚠ CRITICAL: Push to ghcr.io/erikdakoda/librechat-git:debian-slim — NOT latest. The latest tag points to the current Alpine image used by the production deployment. Overwriting it would break the existing deployment (violates R6).
- Log in to GHCR:
echo "$TOKEN" | docker login ghcr.io -u ErikDakoda --password-stdin - Build:
cd ~/Dev/uvilo-os/Forge/Configs-debian && docker build --pull --platform linux/amd64 -f Dockerfile.librechat -t ghcr.io/erikdakoda/librechat-git:debian-slim . - Run the container locally and verify:
bashis available:which bash→/usr/bin/bashor/bin/bashcurlis available:which curlwgetis available:which wgetnanois available:which nanogitis available:which gitpython3is available:which python3pippackages installed:python3 -c "import mcp; import pymongo; import dns"- Default shell is bash:
ls -la /bin/sh(on Debian this points to dash, which is fine — bash is also available)
- Check image size:
docker images ghcr.io/erikdakoda/librechat-git:debian-slim- Compare with the current Alpine-based image size
- Verify size increase is under 200MB uncompressed (Requirement R2)
- Expected: debian-slim ~1.62GB vs alpine ~2.18GB (560MB decrease)
- If all checks pass, push the image:
docker push ghcr.io/erikdakoda/librechat-git:debian-slim - Record the image size comparison in the State document
Task 5 — Update Forge_Infrastructure.md to document the dual-image setup
The infrastructure docs must reflect that there are now two images: the current Alpine (
latesttag) and the new Debian-slim (debian-slimtag). The “Alpine Container Constraints” section stays for now (it still applies to the running Alpine deployment) but a new section documents the Debian-slim image.
- In
Forge/Forge_Infrastructure.md, add a “Dual Image Migration” section that documents:- Current production image:
ghcr.io/erikdakoda/librechat-git:latest(Alpine-based, untouched) - New migration image:
ghcr.io/erikdakoda/librechat-git:debian-slim(Debian-slim-based, for parallel deployment) - Config folders:
Forge/Configs/(Alpine) vsForge/Configs-debian/(Debian-slim) — same filenames, separated by folder - Build approach: 3-stage (source → builder → runtime) — copies app from Alpine image, rebuilds native modules for glibc
- Once migration is complete, the Debian-slim image will be promoted to
latestandForge/Configs-debian/will be renamed back toForge/Configs/
- Current production image:
- Add a “Debian-slim Container Notes” section that documents:
- Available tools: bash, curl, wget, nano, git, python3 (all pre-installed)
- Default shell:
/bin/sh→ dash,/bin/bash→ bash - Package manager:
apt-get(but container filesystem is read-only at runtime fornodeuser — install packages in Dockerfile instead) - Python package installation:
uv pip install --system(no python3-pip in runtime) uvanduvx: available via COPY fromghcr.io/astral-sh/uv:latestnpx -ystill re-downloads packages on each spawn — this hasn’t changed- Always include
-yin npx args for LibreChat MCP servers
- Do NOT remove the “Alpine Container Constraints” section yet — it still applies to the running deployment