Obsah

Claude Code v Alpine Linux Dockeru

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í.

docker-compose.yml

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:

Dockerfile.alpine-dev

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"]

Jak funguje SSH v tomto setupu

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:

Výsledek: host klíče přežijí rebuild kontejneru a klient SSH nehlásí po každé změně nový fingerprint.

Přihlášení přes SSH klíč

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

Práva pro .ssh a authorized_keys

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.

.profile a .bashrc

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.

Shrnutí

Tento Alpine kontejner řeší pro Claude Code hlavně tři věci: