Claude Code Docker実行ガイド — 認証の永続化とヘッドレス実行
Claude CodeをDockerコンテナで動かす実務手順。認証をコンテナの再起動をまたいで維持する設定と、CI向けのヘッドレス実行、docker-composeの構成例を扱います。
要点
Claude CodeはDockerコンテナ単体でも普通に動きます。VS CodeのDevContainer仕様に乗る必要はなく、Dockerfileでイメージを作って docker run するだけです。躓きどころは実行そのものより認証で、コンテナを作り直すたびにログインし直す状態を避けるには、設定の永続化と非対話実行の両方を最初に設計しておく必要があります。
この記事は既存記事が扱うセキュリティ境界の設計(capability制限やネットワーク遮断)とは別の観点で、動かし続けるための実務、つまり認証の永続化・ヘッドレス実行・docker-composeでの日常運用を扱います。強い権限制限やCI向けの隔離設計が目的なら、後半の節で紹介する記事を先に読んでください。
最小構成のDockerfileを用意する
VS Codeの拡張機能を前提にしないなら、DevContainer機能を使わず素のDockerfileで十分です。公式のネイティブインストーラーはリリースチャネルまたは特定バージョンを指定できるので、CI用イメージでは stable チャネルかバージョン番号を固定するのが安全です。
FROM ubuntu:24.04
RUN apt-get update && apt-get install -y --no-install-recommends \
curl \
ca-certificates \
git \
&& rm -rf /var/lib/apt/lists/*
# stableチャネルを固定してインストール(latestだと再現性が崩れる)
RUN curl -fsSL https://claude.ai/install.sh | bash -s stable
ENV PATH="/root/.local/bin:${PATH}"
WORKDIR /workspace
CMD ["bash"]ネイティブインストーラーはmacOS / Linux / WSLで ~/.local/bin/claude にシンボリックリンクを作り、実体は ~/.local/share/claude/versions/ 配下に置きます。イメージのビルド時点でバージョンを固定したい場合は bash -s stable の代わりに bash -s 2.1.89 のように具体的な版番号を渡します。自動更新を止めたい場合は起動時に DISABLE_AUTOUPDATER=1 を設定してください。
CMD ["bash"] にしているのは意図的です。ENTRYPOINT でいきなり claude を起動する構成もよく見ますが、それだとコンテナに入って別のシェルコマンドを試したいときに毎回上書きが要ります。日常的に使い続けるコンテナなら bash で起動しておき、必要なときに claude や claude -p を手で叩くほうが小回りが利きます。CIのように「1コマンド実行して終了する」用途に絞るなら ENTRYPOINT 固定のほうが呼び出し側は書きやすくなります。用途で使い分けてください。
認証をコンテナの再起動をまたいで維持する
docker run --rm で使い捨てるコンテナなら、起動のたびに ANTHROPIC_API_KEY を環境変数で渡すだけで済みます。
docker run --rm -it \
-e ANTHROPIC_API_KEY \
-v "$(pwd):/workspace" \
my-claude-image一方、同じコンテナやイメージを使い続けたい、あるいはサブスクリプションのOAuthログインを毎回やり直したくない場合は、設定ディレクトリごと永続化します。Claude Codeの認証・設定・セッション履歴は ~/.claude 配下に保存され、CLAUDE_CONFIG_DIR 環境変数でこのディレクトリの場所を変えられます。名前付きボリュームをマウントしてこの変数を合わせておけば、コンテナを作り直しても認証状態が残ります。
docker volume create claude-config
docker run --rm -it \
-v claude-config:/root/.claude \
-e CLAUDE_CONFIG_DIR=/root/.claude \
-v "$(pwd):/workspace" \
my-claude-image \
claudeコンテナ内で claude を起動すると初回だけブラウザ経由のログインを求められます。Dockerコンテナのブラウザコールバックはホストに届かないことが多いため、ブラウザに表示されたコードをターミナルの Paste code here if prompted に貼り付けて完了させます。2回目以降は永続化したボリュームのおかげでログインなしに起動します。
サブスクリプションアカウントを使わずCIパイプラインだけで動かすなら、claude setup-token で1年間有効なOAuthトークンを発行し、CLAUDE_CODE_OAUTH_TOKEN としてCIのシークレットに登録する方法もあります。このコマンドもブラウザでの承認が必要なので、ローカル環境で一度だけ実行してトークンを取り出します。
CIやスクリプトからヘッドレスで実行する
対話プロンプトを避けたい自動化では -p フラグの非対話モード(print mode)を使います。標準入力やコマンド引数でクエリを渡すと、結果を出力して終了します。
docker run --rm \
-e ANTHROPIC_API_KEY \
-v "$(pwd):/workspace" \
-w /workspace \
my-claude-image \
claude -p "READMEのタイポを直して" --output-format json起動を速くしたいだけのスクリプト用途では --bare フラグも検討します。hooks・Skills・Plugins・MCPサーバー・自動メモリ・CLAUDE.mdの自動検出をすべて省略し、BashとファイルRead/Editだけの最小構成で立ち上がります。ただし --bare はOAuthトークンやKeychainの資格情報を読みません。永続化した CLAUDE_CODE_OAUTH_TOKEN を使うつもりの構成では動かないので、--bare を使う場合は ANTHROPIC_API_KEY か apiKeyHelper で認証してください。
docker-composeで日常的な開発用途に使う
一時的なCI実行ではなく、日々のコーディングをコンテナの中で完結させたい場合はdocker-composeでボリュームとワークスペースをまとめて定義すると管理が楽になります。
services:
claude:
build: .
volumes:
- claude-config:/root/.claude
- .:/workspace
environment:
- CLAUDE_CONFIG_DIR=/root/.claude
- ANTHROPIC_API_KEY
working_dir: /workspace
stdin_open: true
tty: true
volumes:
claude-config:docker compose run claude claude のように起動すれば、対話セッションのままコンテナに入れます。ホスト側の .ssh や .aws を安易にマウントしない設計は、通常のDocker利用でも最低限の防御になります。
同じCIジョブを大量に、しかも継続的に捌く必要が出てきたら、コンテナを都度起動する構成ではなくClaude Code self-hosted-runnerとはが扱うself-hosted環境のほうが管理コストを抑えられます。runnerはあなたのインフラ上で常駐し、claude.aiから始めたクラウドセッションを受け取って実行する仕組みなので、この記事のようにDockerfileを自分で書いて都度起動する運用とは前提が異なります。
社内プロキシ配下のDockerホストから使う
CIサーバーや踏み台ホストがプロキシ経由でしか外部に出られない構成では、Claude Codeの起動前に標準的なプロキシ環境変数を設定します。HTTPS_PROXY を優先的に読み、認証が必要なプロキシならURLに資格情報を埋め込みます。SOCKSプロキシには対応していません。
ENV HTTPS_PROXY=https://proxy.example.com:8080
ENV NO_PROXY="localhost,127.0.0.1,.internal.example.com"環境変数はプロセス起動時に一度だけ読み込まれるため、実行中のコンテナでシェルの環境を書き換えても反映されません。値を変えたら再起動します。プロキシ配下でも到達させる必要がある宛先は主に3つで、api.anthropic.com(モデル推論・認証)、claude.ai と platform.claude.com(OAuthログイン)、そして downloads.claude.ai(ネイティブインストーラーと自動更新)です。npmやbunでインストールする場合は registry.npmjs.org も許可リストに加えます。ファイアウォールで最小限に絞りたいイメージほど、これらのドメインを先に確定させてからDockerfileを書き始めるほうが手戻りが少なくなります。
セキュリティを強めたい場合の分岐
ここまでの構成は「動かし続けること」を優先した設計で、--dangerously-skip-permissions を使う自動化やCIの隔離要件までは踏み込んでいません。ホストの認証情報から物理的に隔離したい、Linux capabilityを絞りたい、ネットワークを遮断したいといった要件がある場合は、DevContainer / Docker sandbox完全実装がcapability drop・read-onlyファイルシステム・段階的な認証情報の扱いまで手順化しています。認証情報をコンテナ内でマスキングする設定はClaude Codeの認証情報マスキングも参照してください。
よくあるつまずき
- コンテナを作り直すたびにログインし直す:
CLAUDE_CONFIG_DIRを名前付きボリュームと合わせて設定していないケースです。上の設定例のとおり、ボリュームと環境変数を必ずセットで指定します --bareで起動したら認証エラーになる:--bareはOAuthトークンやKeychainを読みません。ANTHROPIC_API_KEYかapiKeyHelperに切り替えます- ブラウザでログインが完結しない: コンテナのブラウザコールバックはホストに届きません。表示されたコードを
Paste code here if promptedに貼り付けます - サブスクリプションなのにAPIキー扱いになる: シェルのどこかに古い
ANTHROPIC_API_KEYが残っていると、OAuthログインより優先されます。イメージやcomposeファイルの環境変数を洗い直します。認証まわりの切り分けはClaude Codeでよくあるエラー10選も参考になります docker.sockをマウントしてサンドボックスの意味が消える: コンテナ内からdocker daemonに到達できると、実質的にホストへ抜けられます。特別な理由がない限りマウントしません
まとめ
Docker単体でClaude Codeを動かすこと自体はDockerfile 1つで完結します。設計で決めるべきなのは、使い捨てのCI実行なら ANTHROPIC_API_KEY を都度渡すだけで十分、日常的に使い続けるなら CLAUDE_CONFIG_DIR とボリュームで認証を永続化する、という使い分けです。セキュリティ境界を厳格にする必要が出てきたら、上のcapability制限の設計に切り替えます。
よくある質問
DevContainerとDockerだけの構成、どちらを選べばよいですか
VS CodeやCodespacesの統合(拡張の自動インストールやポート転送)が必要ならDevContainer仕様に乗るほうが手間が省けます。エディタ非依存でCIや自前のワークフローに組み込むだけなら、この記事の素のDockerfileで十分です。両者は排他的ではなく、DevContainerの中身も結局はDockerイメージです。
CI用のコンテナでも claude setup-token は使えますか
コマンド自体はコンテナ内でも実行できますが、ブラウザでの承認が必要なため無人のCIジョブの中では完結しません。ローカル環境や踏み台になるマシンで一度だけ実行してトークンを取り出し、CIのシークレットとして登録する運用にします。
--dangerously-skip-permissions をDockerコンテナで使っても安全ですか
コンテナ境界があるという理由だけでは安全と言い切れません。ホストの認証情報をマウントしていないか、ネットワークが不要に開いていないかを確認してから使う前提のフラグです。具体的な設計は上の「セキュリティを強めたい場合の分岐」で紹介した記事を参照してください。