Hosting
Fly.io
目標: 永続ストレージ、自動 HTTPS、Discord/チャンネルアクセスを備えた Fly.io マシン上で OpenClaw Gateway を実行します。
必要なもの
- flyctl CLI がインストール済み
- Fly.io アカウント(無料枠で利用可能)
- モデル認証: 選択したモデルプロバイダーの API キー
- チャンネル認証情報: Discord ボットトークン、Telegram トークンなど
初心者向けクイック手順
- リポジトリをクローンし、
fly.tomlをカスタマイズ - アプリとボリュームを作成し、シークレットを設定
fly deployでデプロイ- SSH で接続して設定を作成するか、Control UI を使用
Fly アプリを作成
git clone https://github.com/openclaw/openclaw.gitcd openclaw # 任意の名前を選択fly apps create my-openclaw # 通常は 1GB で十分fly volumes create openclaw_data --size 1 --region iad近くのリージョンを選択してください。一般的な選択肢: lhr(ロンドン)、iad(バージニア)、sjc(サンノゼ)。
fly.toml を設定
アプリ名と要件に合わせて fly.toml を編集します。リポジトリで追跡されている fly.toml は、以下に示す公開テンプレートです。deploy/fly.private.toml は、公開 IP を使用しない堅牢化されたバリアントです(プライベートデプロイを参照)。
app = "my-openclaw" # アプリ名primary_region = "iad" [build] dockerfile = "Dockerfile" [env] NODE_ENV = "production" OPENCLAW_PREFER_PNPM = "1" OPENCLAW_STATE_DIR = "/data" NODE_OPTIONS = "--max-old-space-size=1536" [processes] app = "node dist/index.js gateway --allow-unconfigured --port 3000 --bind lan" [http_service] internal_port = 3000 force_https = true auto_stop_machines = false auto_start_machines = true min_machines_running = 1 processes = ["app"] [[vm]] size = "shared-cpu-2x" memory = "2048mb" [mounts] source = "openclaw_data" destination = "/data"OpenClaw Docker イメージのエントリーポイントは tini で、デフォルトでは node openclaw.mjs gateway を実行します。Fly の [processes] は、ENTRYPOINT を変更せずに Docker の CMD を置き換えます(ここでは、同じコンパイル済みエントリーポイントである node dist/index.js gateway ... を直接実行します)。そのため、プロセスは引き続き tini の下で実行されます。
主要設定:
| 設定 | 理由 |
|---|---|
--bind lan |
Fly のプロキシが Gateway に到達できるよう、0.0.0.0 にバインドします |
--allow-unconfigured |
設定ファイルなしで起動します(後で作成します) |
internal_port = 3000 |
Fly のヘルスチェックのため、--port 3000(または OPENCLAW_GATEWAY_PORT)と一致させる必要があります |
memory = "2048mb" |
512MB では小さすぎるため、2GB を推奨します |
OPENCLAW_STATE_DIR = "/data" |
ボリューム上に状態を永続化します |
シークレットを設定
# 必須: 非ループバックバインド用の Gateway 認証トークンfly secrets set OPENCLAW_GATEWAY_TOKEN=$(openssl rand -hex 32) # モデルプロバイダーの API キーfly secrets set ANTHROPIC_API_KEY=example-anthropic-key-not-real # 任意: その他のプロバイダーfly secrets set OPENAI_API_KEY=example-openai-key-not-realfly secrets set GOOGLE_API_KEY=... # チャンネルトークンfly secrets set DISCORD_BOT_TOKEN=example-discord-bot-token非ループバックバインド(--bind lan)には、有効な Gateway 認証パスが必要です。この例では OPENCLAW_GATEWAY_TOKEN を使用しますが、gateway.auth.password または正しく設定された非ループバックの信頼済みプロキシデプロイでも要件を満たします。SecretRef の契約については、シークレット管理を参照してください。
これらのトークンはパスワードと同様に扱ってください。シークレットを openclaw.json に保存しないようにするため、API キーとトークンには設定ファイルよりも環境変数/fly secrets を使用することを推奨します。
デプロイ
fly deploy最初のデプロイでは Docker イメージがビルドされます。デプロイ後に確認します。
fly statusfly logsHTTP/WebSocket リスナーが起動すると、Gateway の起動ログに gateway ready が記録されます。Fly 自体のヘルスチェックは、fly.toml に従って internal_port = 3000 を監視します。また、イメージの Docker HEALTHCHECK ディレクティブは、デフォルトポート 18789 上の /healthz もポーリングしますが、このデプロイでは Gateway を --port 3000 に上書きしているため使用されません。
設定ファイルを作成
マシンに SSH 接続し、適切な設定を作成します。
fly ssh consolemkdir -p /datacat > /data/openclaw.json << 'EOF'{ "agents": { "defaults": { "model": { "primary": "anthropic/claude-opus-4-6", "fallbacks": ["anthropic/claude-sonnet-4-6", "openai/gpt-5.4"] }, "maxConcurrent": 4 }, "list": [ { "id": "main", "default": true } ] }, "auth": { "profiles": { "anthropic:default": { "mode": "token", "provider": "anthropic" }, "openai:default": { "mode": "token", "provider": "openai" } } }, "bindings": [ { "agentId": "main", "match": { "channel": "discord" } } ], "channels": { "discord": { "enabled": true, "groupPolicy": "allowlist", "guilds": { "YOUR_GUILD_ID": { "channels": { "general": { "allow": true } }, "requireMention": false } } } }, "gateway": { "mode": "local", "bind": "auto", "controlUi": { "allowedOrigins": [ "https://my-openclaw.fly.dev", "http://localhost:3000", "http://127.0.0.1:3000" ] } }, "meta": {}}EOFOPENCLAW_STATE_DIR=/data を使用する場合、設定パスは /data/openclaw.json です。
https://my-openclaw.fly.dev を実際の Fly アプリのオリジンに置き換えてください。Gateway の起動時には、ランタイムの --bind と --port の値からローカル Control UI のオリジンが初期設定されるため、設定が存在しない初回起動でも処理を続行できます。ただし、Fly 経由でブラウザからアクセスするには、gateway.controlUi.allowedOrigins に正確な HTTPS オリジンを指定する必要があります。
Discord トークンは、次のいずれかから取得できます。
- 環境変数
DISCORD_BOT_TOKEN(シークレットには推奨)。設定に追加する必要はなく、Gateway が自動的に読み取ります - 設定ファイル
channels.discord.token
適用するために再起動します。
exitfly machine restart <machine-id>Gateway にアクセス
Control UI
fly openまたは、https://my-openclaw.fly.dev/ にアクセスします。
設定済みの共有シークレットで認証します。OPENCLAW_GATEWAY_TOKEN の Gateway トークン、またはパスワード認証に切り替えた場合はパスワードを使用します。
ログ
fly logs # ライブログfly logs --no-tail # 最近のログSSH コンソール
fly ssh consoleトラブルシューティング
「アプリが想定されたアドレスでリッスンしていない」
Gateway が 0.0.0.0 ではなく 127.0.0.1 にバインドされています。
修正: fly.toml のプロセスコマンドに --bind lan を追加します。
ヘルスチェックの失敗 / 接続拒否
Fly が設定済みポート上の Gateway に到達できません。
修正: internal_port が Gateway のポート(--port 3000 または OPENCLAW_GATEWAY_PORT=3000)と一致していることを確認します。
OOM / メモリの問題
コンテナが再起動を繰り返すか、強制終了されています。兆候: SIGABRT、v8::internal::Runtime_AllocateInYoungGeneration、または通知なしの再起動。
修正: fly.toml でメモリを増やします。
[[vm]] memory = "2048mb"または、既存のマシンを更新します。
fly machine update <machine-id> --vm-memory 2048 -y512MB では小さすぎます。1GB でも動作する場合がありますが、負荷が高い場合や詳細ログを有効にした場合は OOM が発生する可能性があります。2GB を推奨します。
Gateway ロックの問題
コンテナの再起動後、Gateway が「すでに実行中」というエラーで起動を拒否します。
ランタイムロックファイルは、永続 /data ボリューム上ではなく、<tmpdir>/openclaw-<uid>/gateway.<hash>.lock
および gateway.state.<hash>.lock(Linux:
/tmp/openclaw-<uid>/gateway.*.lock)に存在するため、通常はコンテナを完全に再起動すると、コンテナファイルシステムの他の部分とともに削除されます。ロックが残り(たとえば、コンテナファイルシステムを保持する fly machine restart の場合)起動を妨げる場合は、手動で削除します。
fly ssh console --command "rm -f /tmp/openclaw-*/gateway.*.lock"fly machine restart <machine-id>設定が読み取られない
--allow-unconfigured は起動ガードを回避するだけです。/data/openclaw.json を作成または修復することはないため、実際の設定が存在し、通常のローカル Gateway 起動に必要な "gateway": { "mode": "local" } が含まれていることを確認してください。
設定が存在することを確認します。
fly ssh console --command "cat /data/openclaw.json"SSH 経由で設定を書き込む
fly ssh console -C はシェルのリダイレクトをサポートしていません。設定ファイルを書き込むには、次の手順を使用します。
# echo + tee(ローカルからリモートへパイプ)echo '{"your":"config"}' | fly ssh console -C "tee /data/openclaw.json" # または sftpfly sftp shell> put /local/path/config.json /data/openclaw.jsonファイルがすでに存在する場合、fly sftp が失敗することがあります。先に削除してください。
fly ssh console --command "rm /data/openclaw.json"状態が永続化されない
再起動後に認証プロファイル、チャンネル/プロバイダーの状態、またはセッションが失われる場合、状態ディレクトリがボリュームではなくコンテナファイルシステムに書き込まれています。
修正: fly.toml に OPENCLAW_STATE_DIR=/data が設定されていることを確認し、再デプロイします。
更新
git pullfly deployfly statusfly logsここでは、git pull + fly deploy が管理された手順です。Dockerfile からイメージを再ビルドするため、CLI/Gateway のバージョン、ベース OS イメージ、Dockerfile の変更がすべて同時に更新されます。実行中のコンテナ内での openclaw update は同じ操作ではありません。これは、イメージが Docker でビルドされた dist/ ツリーとして提供され、検出対象となる .git チェックアウトも npm 管理のグローバルインストールも含まれていないためです。VM 形式のインストールでの手順については、更新を参照してください。
マシンコマンドの更新
完全な再デプロイを行わずに起動コマンドを変更するには、次の手順を使用します。
fly machines listfly machine update <machine-id> --command "node dist/index.js gateway --port 3000 --bind lan" -y # またはメモリ増加と同時にfly machine update <machine-id> --vm-memory 2048 --command "node dist/index.js gateway --port 3000 --bind lan" -y後で fly deploy を実行すると、マシンコマンドは fly.toml に記載された内容に戻ります。再デプロイ後に手動変更を再適用してください。
プライベートデプロイ(堅牢化)
デフォルトでは、Fly は公開 IP を割り当てるため、Gateway は https://your-app.fly.dev でアクセス可能となり、インターネットスキャナー(Shodan、Censys など)から検出されます。
公開 IP なしで堅牢化したデプロイを行うには、deploy/fly.private.toml を使用します。これには [http_service] が含まれていないため、公開イングレスは割り当てられません。
プライベートデプロイを使用する場合
- 送信呼び出し/メッセージのみ(受信 Webhook なし)
- Webhook コールバックは ngrok または Tailscale トンネルで処理
- Gateway へのアクセスにはブラウザではなく SSH、プロキシ、または WireGuard を使用
- インターネットスキャナーからデプロイを隠す必要がある場合
セットアップ
fly deploy -c deploy/fly.private.tomlまたは、既存のデプロイを変換します。
# 現在の IP を一覧表示fly ips list -a my-openclaw # パブリック IP を解放fly ips release <public-ipv4> -a my-openclawfly ips release <public-ipv6> -a my-openclaw # 今後のデプロイでパブリック IP が再割り当てされないよう、プライベート設定に切り替えfly deploy -c deploy/fly.private.toml # プライベート専用 IPv6 を割り当てfly ips allocate-v6 --private -a my-openclawこの後、fly ips list には private タイプの IP のみが表示されます。
VERSION IP TYPE REGIONv6 fdaa:x:x:x:x::x private globalプライベートデプロイへのアクセス
オプション 1:ローカルプロキシ(最も簡単)
fly proxy 3000:3000 -a my-openclaw# ブラウザーで http://localhost:3000 を開くオプション 2:WireGuard VPN
fly wireguard create# WireGuard クライアントにインポートし、内部 IPv6 経由でアクセス# 例:http://[fdaa:x:x:x:x::x]:3000オプション 3:SSH のみ
fly ssh console -a my-openclawプライベートデプロイでの Webhook
パブリックに公開せずに Webhook コールバック(Twilio、Telnyx など)を使用するには、次の方法があります。
- ngrok トンネル:コンテナ内またはサイドカーとして ngrok を実行
- Tailscale Funnel:Tailscale 経由で特定のパスを公開
- アウトバウンドのみ:一部のプロバイダー(Twilio)は、Webhook なしでアウトバウンド通話に対応
plugins.entries.voice-call.config 配下での ngrok を使用した音声通話設定の例:
{ plugins: { entries: { "voice-call": { enabled: true, config: { provider: "twilio", tunnel: { provider: "ngrok" }, webhookSecurity: { allowedHosts: ["example.ngrok.app"], }, }, }, }, },}ngrok トンネルはコンテナ内で実行され、Fly アプリ自体を公開することなくパブリック Webhook URL を提供します。転送されたホストヘッダーが受け入れられるよう、webhookSecurity.allowedHosts をトンネルのホスト名に設定します。
セキュリティ上のトレードオフ
| 項目 | パブリック | プライベート |
|---|---|---|
| インターネットスキャナー | 検出可能 | 非表示 |
| 直接攻撃 | 可能 | ブロック |
| Control UI へのアクセス | ブラウザー | プロキシ/VPN |
| Webhook の配信 | 直接 | トンネル経由 |
注意事項
- Fly.io は x86 アーキテクチャを使用します。この Dockerfile は x86 と ARM の両方に対応しています。
- WhatsApp/Telegram のオンボーディングには、
fly ssh consoleを使用します。 - 永続データは
/dataのボリュームに保存されます。 - Signal では、イメージに signal-cli(Java ベースの CLI)が必要です。カスタムイメージを使用し、メモリを 2GB 以上に維持してください。
コスト
推奨設定(shared-cpu-2x、2GB RAM)では、使用量に応じて月額約 $10~15 を見込んでください。無料利用枠で基本使用量の一部をまかなえます。現在の料金については、Fly.io の料金を参照してください。
次のステップ
- メッセージングチャンネルを設定:チャンネル
- Gateway を設定:Gateway の設定
- OpenClaw を最新の状態に維持:更新