Tento setup jsem si chystal pro běh Claude Code v lehkém Alpine Linux kontejneru. Cíl byl jednoduchý: mít persistentní domovský adresář, přístup přes SSH a nemuset po každém rebuildu znovu řešit host klíče nebo přihlašování.
Služba v docker-compose.yml vypadá takto:
alpine-dev: container_name: alpine-dev build: context: . dockerfile: Dockerfile.alpine-dev restart: "no" networks: - traefik ports: - "4444:22" environment: - TZ=${DOCKER_TZ} volumes: # Domovský adresář - přežije rebuild kontejneru - ${VOLUME_PATH}/alpine-dev:/home/dev stdin_open: true tty: true
Důležité body:
/home/dev je připojený jako volume, takže obsah domovského adresáře přežije rebuild kontejneru.4444.FROM alpine:3.23
# Nastavení timezone a locale proměnných
ENV TZ=Europe/Prague
ENV LANG=cs_CZ.UTF-8
ENV LANGUAGE=cs_CZ:cs
ENV LC_ALL=cs_CZ.UTF-8
ENV MUSL_LOCPATH=/usr/share/i18n/locales/musl
# Instalace základních balíčků včetně timezone a locale podpory
RUN apk add --no-cache \
# Timezone
tzdata \
# Locale podpora pro musl
musl-locales \
musl-locales-lang \
# Python
python3 \
py3-pip \
pipx \
# Node.js (potřeba pro Claude Code)
nodejs \
npm \
# Základní nástroje
git \
curl \
wget \
jq \
bash \
sudo \
shadow \
openssh-client \
openssh-server \
ca-certificates \
openrc \
# Build nástroje (některé npm balíčky je potřebují)
build-base \
&& cp /usr/share/zoneinfo/${TZ} /etc/localtime \
&& echo "${TZ}" > /etc/timezone
# Vytvoření uživatele 'dev' s UID 1000 (pro mapování volumes)
RUN addgroup -g 1000 dev && \
adduser -D -u 1000 -G dev -h /home/dev -s /bin/bash dev && \
echo "dev ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/dev && \
chmod 0440 /etc/sudoers.d/dev
# Nastavení locale pro bash
RUN echo 'export LANG=cs_CZ.UTF-8' >> /etc/profile.d/locale.sh && \
echo 'export LANGUAGE=cs_CZ:cs' >> /etc/profile.d/locale.sh && \
echo 'export LC_ALL=cs_CZ.UTF-8' >> /etc/profile.d/locale.sh && \
chmod +x /etc/profile.d/locale.sh && \
# Pro interactive non-login shells
echo 'export LANG=cs_CZ.UTF-8' >> /etc/bash/bashrc && \
echo 'export LANGUAGE=cs_CZ:cs' >> /etc/bash/bashrc && \
echo 'export LC_ALL=cs_CZ.UTF-8' >> /etc/bash/bashrc
RUN echo "dev:changeme" | chpasswd
# Nastavení pracovního adresáře
WORKDIR /home/dev
EXPOSE 22
# Přepnutí na uživatele dev
#USER dev
# Kontejner zůstane běžet
#CMD ["tail", "-f", "/dev/null"]
#CMD ["/bin/sh", "-c", "ssh-keygen -A && /usr/sbin/sshd -D -e"]
CMD ["/bin/sh", "-c", "mkdir -p /home/dev/.ssh/keys && if [ -f /home/dev/.ssh/keys/ssh_host_ed25519_key ]; then cp /home/dev/.ssh/keys/ssh_host_* /etc/ssh/; else ssh-keygen -A && cp /etc/ssh/ssh_host_* /home/dev/.ssh/keys/; fi && /usr/sbin/sshd -D -e"]
Chtěl jsem přístup přes SSH a zároveň jsem nechtěl po každém rebuildu znovu odebírat a přidávat host klíče. Proto start kontejneru dělá toto:
/home/dev/.ssh/keys/etc/ssh/ssh-keygen -A a uloží je i do persistentního volumesshdVýsledek: host klíče přežijí rebuild kontejneru a klient SSH nehlásí po každé změně nový fingerprint.
Do /home/dev/.ssh/authorized_keys jsem ručně vložil obsah svého veřejného klíče, například ~/.ssh/id_rsa.pub, abych se mohl přihlašovat bez hesla.
V mém případě se ukázalo, že uživatel dev musí mít v kontejneru nastavené heslo, jinak SSH přihlášení klíčem nefungovalo spolehlivě. Proto je v Dockerfile tento řádek:
echo "dev:changeme" | chpasswd
Heslo changeme je dobré po prvním spuštění změnit, ale běžně se nepřihlašuji heslem. Prakticky používám přístup pouze přes SSH klíč.
Přihlášení pak může vypadat například takto:
ssh dev@localhost -p 4444
Pokud jsou práva moc volná, sshd může soubor authorized_keys ignorovat. Osvědčené nastavení je:
mkdir -p /home/dev/.ssh chmod 700 /home/dev/.ssh chmod 600 /home/dev/.ssh/authorized_keys chown -R dev:dev /home/dev/.ssh
Tohle je potřeba zkontrolovat hlavně tehdy, když je /home/dev připojený jako volume a soubory vznikly mimo kontejner nebo pod jiným UID.
Musel jsem si upravit i shell init soubory.
.profile:
[ -f ~/.bashrc ] && . ~/.bashrc
.bashrc:
export PATH="$HOME/.local/bin:$PATH"
První řádek zajistí načtení ~/.bashrc. Druhý přidá do PATH uživatelské binárky, typicky kvůli nástrojům instalovaným přes pipx.
Tento Alpine kontejner řeší pro Claude Code hlavně tři věci:
/home/dev napojený přes volume