Contents
背景と問題の全体像
WSL2 上で Docker Desktop を利用すると、仮想ネットワーク、Windows のプロキシ/証明書設定、Docker デーモンの TLS オプションが複雑に絡み合い、x509: certificate signed by unknown authority や SSL handshake failure といったエラーが頻発します。
本稿ではそれぞれの要因を分解し、根本的な対策と再発防止の自動化までを網羅的に解説します。
WSL2 のネットワーク構成がもたらすリスク
1. 仮想 NIC と IP アドレスの変動
- 仕組み:WSL2 は Hyper‑V 上に軽量 VM を起動し、
vEthernet (WSL)という仮想 NIC が自動生成されます。VM 起動ごとに172.x.x.x系や10.x.x.x系のプライベートアドレスが割り当てられ、Docker の内部ネットワーク(デフォルトは172.17.0.0/16)と衝突することがあります。 - 影響:コンテナから外部 HTTPS エンドポイントへアクセスすると DNS 解決が失敗し、TLS ハンドシェイクで unknown authority が返るケースが増えます。
2. VPN 環境との競合例
VPN に接続した状態で WSL を再起動すると、vEthernet (WSL) の IP が 10.0.x.x 系に変わり、Docker の内部 DNS が正しく機能しなくなることがあります。
対策のヒント:
- wsl --shutdown 後に VPN を一度切断してから再起動する。
- Docker Desktop の設定で 「Use the WSL 2 based engine」 を有効にしたまま、Docker → Settings → Resources → Network でカスタムサブネット(例: 172.30.0.0/16)を指定すると衝突リスクが低減します。
Windows 側プロキシ/証明書設定がコンテナに与える影響
1. プロキシによる TLS インスペクション
企業ネットワークでは多くの場合、HTTPS 通信はプロキシサーバで復号・再暗号化(TLS インスペクション)されます。この際、社内 CA が発行した証明書で通信が再署名されます。
- Windows 側:CA 証明書は「信頼されたルート証明機関」にインポート済みでも、WSL2 の Linux 環境や Docker コンテナには自動的に同期されません。
- 結果:コンテナ内から外部リポジトリへ
docker pushすると certificate verification failed が発生します。
2. 設定の可視化手段
| 項目 | 確認方法 |
|---|---|
| Windows のプロキシ設定 | netsh winhttp show proxy |
| WSL 側環境変数 | echo $HTTPS_PROXY $NO_PROXY |
| Docker Desktop のプロキシ設定 | Settings → Resources → Proxies で UI を確認 |
ベストプラクティス:
1. Windows と同一のプロキシ URL/ポートを WSL の環境変数にエクスポートする(例: export HTTPS_PROXY=http://proxy.example.com:8080)。
2. Docker Desktop の「Proxies」画面でも同様に設定し、Docker Engine が自動的に環境変数をコンテナへ注入できるようにします。
Windows ルート CA を WSL にインポートする実践手順
以下の手順は PowerShell と WSL の両方で実行可能です。作業は管理者権限が必要な点に注意してください。
手順概要
| 手順 | コマンド例 |
|---|---|
| 1. Windows の証明書ストアからエクスポート | powershell<br>certutil -store -user Root # シリアル番号を確認<br>$serial = "<シリアル>"<br>Export-Certificate -Cert (Get-Item "Cert:\CurrentUser\Root\$serial") -FilePath C:\tmp\myca.cer |
2. エクスポートした .cer を WSL へコピー |
powershell<br>Copy-Item C:\tmp\myca.cer \\wsl$\Ubuntu\home\<ユーザー>\myca.cer |
3. 拡張子を .crt にリネーム |
bash<br>mv /home/<ユーザー>/myca.cer /home/<ユーザー>/myca.crt |
| 4. 証明書ディレクトリへ配置 | bash<br>sudo cp myca.crt /usr/local/share/ca-certificates/ |
| 5. ストアを更新 | bash<br>sudo update-ca-certificates |
補足ポイント
update-ca-certificatesは/usr/local/share/ca-certificates/*.crtを対象にします。.cerのままだと無視されます。- 手順全体をシェルスクリプト化すれば、社内ネットワークの証明書更新時にも 数秒 で完了します。
スクリプト例(WSL 側)
|
1 2 3 4 5 6 7 8 9 10 11 12 |
#!/usr/bin/env bash set -euo pipefail # Windows からエクスポートした証明書を /tmp に配置している前提 SRC="/mnt/c/tmp/myca.cer" DST="/usr/local/share/ca-certificates/myca.crt" sudo cp "$SRC" "$DST" sudo update-ca-certificates echo "✅ CA 証明書が WSL にインポートされました" |
mkcert でローカル開発用証明書を作成し Docker と共有する方法
mkcert は ローカル開発向け の自己署名 CA を簡単に生成でき、Windows の信頼ストアと Linux コンテナ双方に展開できます。
1. インストール手順
| 環境 | 手順 |
|---|---|
| Windows (PowerShell) | choco install mkcert -y (Chocolatey がインストールされている場合) |
| WSL (Ubuntu) | bash<br>curl -JLO "https://dl.filippo.io/mkcert/latest?for=linux/amd64"<br>chmod +x mkcert-*-linux-amd64<br>sudo mv mkcert-*-linux-amd64 /usr/local/bin/mkcert |
2. ローカル CA の生成と共有
|
1 2 3 4 5 6 |
# Windows 側で一度だけ実行 → Windows の証明書ストアに自動登録 mkcert -install # WSL 側でも同じ CA を利用したい場合はシンボリックリンクを作成 ln -s "$(wslpath 'C:\Users\<ユーザー>\AppData\Local\mkcert')/rootCA.pem" ~/.local/share/mkcert/rootCA.pem |
3. 開発用サーバ証明書の作成例(Nginx 用)
|
1 2 3 4 5 |
mkdir -p ~/certs mkcert -key-file ~/certs/dev.local-key.pem \ -cert-file ~/certs/dev.local.pem \ dev.local "*.dev.local" localhost 127.0.0.1 ::1 |
4. Docker Compose で証明書をマウント
|
1 2 3 4 5 6 7 8 9 10 |
# docker-compose.yml の抜粋 services: nginx: image: nginx:latest ports: - "443:443" volumes: - ./certs:/etc/nginx/certs:ro # 読み取り専用で共有 - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro |
Nginx 設定例
|
1 2 3 4 5 6 7 8 9 10 |
server { listen 443 ssl; server_name dev.local; ssl_certificate /etc/nginx/certs/dev.local.pem; ssl_certificate_key /etc/nginx/certs/dev.local-key.pem; location / { proxy_pass http://app:8000; } } |
検証ポイント
- Windows のブラウザで https://dev.local にアクセスし、警告が出ないことを確認。
- コンテナ内から curl https://dev.local -v を実行し、証明書チェーンが正しく認識されているかチェック。
代表的なエラーメッセージ別トラブルシューティングフロー
以下は CA 未登録 / ネットワーク競合 / Docker 設定ミス の三層に分けたチェックリストです。各項目を順に確認することで、原因特定の時間を数分に短縮できます。
| 確認ポイント | 手段 |
|---|---|
| Windows の社内 CA が WSL に反映されているか | openssl s_client -connect example.com:443 -servername example.com → Issuer が自組織の CA か確認 |
| mkcert のローカル CA がコンテナにマウントされているか | コンテナ内部で grep "<CA名>" /etc/ssl/certs/ca-certificates.crt |
| Docker Desktop の TLS 設定が過剰になっていないか | Settings → General → Expose daemon on tcp://localhost:2375 が不要なら OFF にする |
対策
- 1,2 が NG であれば CA インポート手順(上記セクション)を再実行。
- 3 が原因の場合は、開発時だけ一時的に有効化し、本番環境では --tlsverify を外すか適切な証明書を用意。
2. SSL handshake failure
| ステップ | 内容 |
|---|---|
| ネットワーク | ip a で vEthernet (WSL) と Docker のサブネットが重複していないか確認。 |
| プロキシ | 環境変数 HTTPS_PROXY, NO_PROXY が正しく設定されているか。Docker Desktop の Resources → Proxies でも同様にチェック。 |
| 証明書チェーン | openssl s_client -showcerts -connect localhost:443 で中間証明書まで返ってくるか確認。 |
3. Docker デーモンのポート設定ミス
Docker Desktop → Settings → General → Expose daemon on tcp://localhost:2375が ON の場合、TLS を無効化した状態になることがあります。- 本番環境では必ず TLS 設定を有効に し、クライアント側で
DOCKER_CERT_PATHを正しく指すようにします。
検証・再発防止策 ― CI への組み込み例
ローカルでの手動検証コマンド
|
1 2 3 4 5 6 |
# Windows の CA を直接指定 curl --cacert C:\tmp\myca.crt https://dev.local -v # WSL 側からコンテナ内部へ docker exec -it nginx curl https://dev.local --cacert /etc/ssl/certs/ca-certificates.crt -v |
GitHub Actions で証明書有効期限を自動チェック
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
name: SSL Cert Expiration Check on: schedule: - cron: '0 3 * * *' # 毎日 03:00 UTC jobs: check: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Install mkcert & openssl run: | sudo apt-get update && sudo apt-get install -y libnss3-tools openssl curl -JLO "https://dl.filippo.io/mkcert/latest?for=linux/amd64" chmod +x mkcert-*-linux-amd64 sudo mv mkcert-*-linux-amd64 /usr/local/bin/mkcert - name: Verify cert expiration run: | openssl x509 -noout -enddate -in ./certs/dev.local.pem | \ awk -F= '{print "証明書有効期限:", $2}' |
- 自動更新:
mkcertのrenewコマンドは CA がローテーションされた際に再生成が必要です。上記ジョブの結果をトリガーにして、以下のシェルスクリプトを実行し、Docker Compose を再起動します。
|
1 2 3 4 5 6 7 |
#!/usr/bin/env bash set -e cd /path/to/project/certs mkcert -install # 必要なら CA 更新 mkcert dev.local "*.dev.local" localhost 127.0.0.1 ::1 docker compose restart nginx |
- cron 設定例(WSL)
|
1 2 3 |
# 毎週日曜 03:00 に自動更新 0 3 * * 0 /usr/local/bin/renew_certs.sh >> /var/log/renew_certs.log 2>&1 |
まとめと次のアクション
| 項目 | 実施すべきこと |
|---|---|
| ネットワーク | Docker のサブネットをカスタムし、VPN と衝突しないようにする。 |
| CA 同期 | Windows で使用している社内 CA を定期的に WSL/コンテナへインポート(自動化スクリプト推奨)。 |
| mkcert 活用 | ローカル開発環境の HTTPS 化を mkcert で統一し、証明書と CA を Docker ボリュームで共有。 |
| プロキシ設定 | Windows と WSL の HTTPS_PROXY/NO_PROXY を一致させ、Docker Desktop の UI 設定も併せて確認。 |
| 検証・CI | curl --cacert や openssl s_client で手動テストし、GitHub Actions/cron による有効期限チェックを導入。 |
以上のフローを順に実施すれば、WSL2 + Docker Desktop 環境での SSL エラーはほぼ解消できます。
次のステップとして、この記事の手順を自組織の開発マシンに適用し、CI パイプラインへ証明書検証ジョブを追加してください。
安全な HTTPS 開発環境構築は、継続的なメンテナンスと自動化が鍵です。 今すぐ実装に取り掛かり、エラーゼロの Docker ワークフローを手に入れましょう。