リモート Mac の self-hosted runner で go mod download がタイムアウトや証明書エラーに落ちると、原因は「上流プロキシ」「出口 NAT」「GOPRIVATE 不一致」のどれかに偏りがちです。手作業の export GOPROXY=... だけでは runner 間で再現性が崩れるため、OpenClaw の onboarddoctorLaunchAgent 常駐を共通前提にし、HTTP プローブで選んだ連鎖をシェルに閉じ込め、CI の要約ログへ状態を書き戻すまでを一本のチェックリストにします。環境変数の意味の深掘りはGo modules・GOPROXY 決定マトリクスを併読ください。

go mod download 失敗の典型と観測ポイント

まずログに出る語を分類します。i/o timeout は帯域または DNS、x509 は企業プロキシのミドルウェア証明書、404 Not Found はミラー鮮度やプライベートモジュールの取り違えです。切り分けは go env GOPROXY GOPRIVATE GOSUMDB の三行を必ず残し、同一シェルで curl -fsSI を上流 URL に当てて往復を確認します。

ゲートウェイや自動化が同じ Mac で動く場合、Node と Go で HTTPS_PROXY の解釈が食い違うと「OpenClaw は生きているのに Go だけ死ぬ」という見かけが出ます。インストールとトラブルシュートで PATH と権限を揃えたうえで、本稿のラッパーを載せると原因が混線しにくくなります。

インストール/設定/切り分けチェックリスト(onboard・doctor・デーモン)

  • インストール: 公式手順どおり CLI を入れ、openclaw onboard で workspace と既定パスを生成。対話が難しい runner では環境変数で非対話に寄せます。
  • 健全性: openclaw doctor をパイプラインの前置ジョブに置き、警告が増えた差分をログに残す(Node 版・設定ファイルパス・トークン空欄など)。
  • 常駐: ゲートウェイを使う構成なら LaunchAgent とヘルスチェックの plist に StandardOutPathStandardErrorPath を固定し、launchctl kickstart で意図的再起動まで練習します。
  • 排错: 失敗時はログ末尾 200 行+lsof -nP -iTCP でポート競合、curl で 127.0.0.1 バインドの応答を確認。Go ジョブは go mod download -x を一発だけ試し URL を特定します。

GOPROXY ラッパー雛形:プローブ・フォールバック・リトライ閾値

以下は「候補連鎖を上から試し、HTTP で生きている最初のエントリを採用する」最小例です。各候補への到達は最大 3 試行、待機は 2 秒・4 秒・8 秒の指数バックオフとします(帯域が極端に悪い場合は 4/8/16 に延ばす)。プローブ URL は組織のミラーが提供する軽量パスに差し替えてください。

scripts/goproxy_pick.sh(テンプレート)
#!/usr/bin/env bash
set -euo pipefail

# 例: 左から試す連鎖(実環境の URL に置換)
CANDIDATES=(
  "https://corp-goproxy.example,https://proxy.golang.org,direct"
  "https://proxy.golang.org,direct"
  "direct"
)

PROBE_URLS=(
  "https://corp-goproxy.example/healthz"
  "https://proxy.golang.org"
  "https://sum.golang.org/lookup/github.com/golang/[email protected]"
)

probe_ok() {
  local url="$1"
  local attempt=1
  local max=3
  local delay=2
  while (( attempt <= max )); do
    if curl -fsS --max-time 8 -o /dev/null "$url"; then
      return 0
    fi
    sleep "$delay"
    delay=$(( delay * 2 ))
    attempt=$(( attempt + 1 ))
  done
  return 1
}

picked=""
for i in "${!CANDIDATES[@]}"; do
  if probe_ok "${PROBE_URLS[$i]}"; then
    picked="${CANDIDATES[$i]}"
    break
  fi
done

if [[ -z "$picked" ]]; then
  echo "goproxy_pick: all probes failed" >&2
  exit 1
fi

export GOPROXY="$picked"
echo "GOPROXY_SELECTED=$picked"

ジョブ内では source scripts/goproxy_pick.sh のあと go mod download を実行します。GOPRIVATE はリポジトリの .envrc や CI の環境設定で固定し、ラッパーは「公開経路の生存確認」に専念させると責務が分かれます。

CI ログへ書き戻す最小ステップ

runner 上の標準出力だけでは「どの連鎖で通ったか」が後追いしづらいので、要約ファイルへ一行出します。GitHub Actions なら GITHUB_STEP_SUMMARY へ追記するのが手軽です。

ワークフロー断片(例)
- name: Pick GOPROXY and download modules
  run: |
    source scripts/goproxy_pick.sh
    echo "## go modules" >> "$GITHUB_STEP_SUMMARY"
    echo "Using **$GOPROXY**" >> "$GITHUB_STEP_SUMMARY"
    go mod download
  env:
    GOTOOLCHAIN: local

ゲートウェイへ通知を集約済みなら、同じ要約を Webhook に POST してチャネルへ残す方法もあります(トークンと NO_PROXY は公式の境界に合わせてください)。

手動 export と自動プローブの比較

方式向くシーン注意点
手動で環境変数を書き換え単一 runner・短時間の検証・緊急回避runner 増加でドリフト、ログに痕跡が残りにくい
シェルラッパー+プローブ本番相当の self-hosted 群・跨境回線の揺らぎ採用連鎖がログに残り、再現手順が一文に収まる
LaunchAgent で定期プローブのみ障害検知とアラート先行、ビルド本体とは分離ビルド直前の一時障害は別途ラッパーが必要

結論:doctor でホストを整え、ビルド前ラッパーで GOPROXY を確定し、要約ログに一行書く三段が揃うと切り分けが最短になります。

まとめ

OpenClaw 側を onboarddoctor/デーモンで健全に保ち、Go 側は GOPROXY ラッパーにプローブとリトライ閾値を閉じ込めると、リモート Mac runner でも go mod download の失敗が説明可能なイベントになります。変数の意味や連鎖設計はマトリクス稿へ戻れるようにしておくと教育コストが下がります。

次の一手:MacPull ホームでリモート Mac の用途を確認し、ブログ一覧から関連記事へ。手順の確認はヘルプセンター(ログイン不要で閲覧できる範囲)、ノードの確保は購入ページからどうぞ。

リモート Mac・CI

GOPROXY の観測可能性を上げると、跨境ビルドがラクになります

プラン比較と公開ドキュメントはログインなしでご覧いただけます。