
Claude Code や ChatGPT Pro でノリノリで作業している最中、突然「Usage Limit(利用制限)」で手が止まったことはないかな?
今回は、Google Colab×Ollama×Cloudflare Tunnelを組み合わせた、完全無料&URL固定型のAIフェイルオーバー(予備機)環境の構築手順を解説するよ!
1. 開発の壁と従来の無料代替案の限界
メインAIを活用した開発・執筆現場では、本来抱えていた開発上の課題と、無料代替環境を構築・運用しようとした際に直面する技術的課題の2つのレイヤーが存在します。
本来の課題(開発現場でのボトルネック)
① 利用制限(Usage Limit)による作業の強制中断
Claude CodeやChatGPT Proなどの最高峰モデルは極めて強力ですが、高頻度で試行錯誤を繰り返すとすぐにトークン上限に達し、作業が強制ストップしてしまいます。
② 追加コストへの心理的ハードル
制限を回避するために有料APIを従量課金で追加利用すると、思わぬ出費に繋がります。できれば 「完全無料の範囲」 で同等の代替環境を作りたいところです。
従来の無料代替案で直面する課題(技術・運用上のボトルネック)
③ 毎回URLを更新する手間(Quick Tunnelの限界)
無料の代替環境としてGoogle ColabとOllamaを組み合わせる際、ランダムURLを発行する Quick Tunnel(trycloudflare.com)を使うと、Colabを再起動するたびに VS Code(Roo Code等)や Aider, Cherry Studio の Base URL を設定し直す必要がありました。
2. 全体像:登場する3つの要素
これらの課題を解決するため、独自ドメインを活用した 固定URL(例: https://ai.example.com/v1) によるバックアップ環境を定義します。
https://ai.example.com/v1 (固定URL)
- Cloudflare:変わらない「固定の看板(URL)」を出してくれる窓口
- Google Colab:バックグラウンドでQwen3.5 9Bを動かす「計算機」
- ローカルPC:実際に指示を出す「手元のアプリ(VS Code, Aider, Cherry Studio等)」
- Colab再起動時のURL貼り替え作業が不要(0回): Base URLはずっと
https://ai.example.com/v1のまま固定。 - Cloudflareの403エラーでブロックされない: 権限のある正規のNamed Tunnelとして通信。
- 自分専用の固定サブドメインでAPI化: 普段使っているクライアント(VS Code / Aider / Cherry Studio等)の接続設定を二度と変更する必要がありません。
3. 最適なテクノロジー選定
検証を重ねた結果、最も手軽で強力な組み合わせとして以下の構成を導き出しました。
| 要素 | 最適な選定 | 選定の理由 |
|---|---|---|
| 実行基盤 | Google Colab (無料T4 GPU) | VRAM 15GBが無料で使え、「制限時だけ起動する」オンデマンド利用と相性抜群。 |
| 推論エンジン | Ollama | OpenAI互換(/v1)やAnthropic互換APIを提供。モデル管理が圧倒的に楽。 |
| モデル | Qwen3.5シリーズ (qwen3.5:9b 等) | 高い日本語精度とコード生成能力を誇り、用途に応じてモデル切り替えも自由自在。 |
| 接続方式 | Cloudflare Named Tunnel | 独自ドメインに紐づけた固定URLを提供し、Colab再起動時もクライアント側の設定変更が不要。 |
4. Phase 1:初回のみの完全セットアップ(全4ステップ)
初期構築時は、「Cloudflare」と「Google Colab」の画面を交互に操作して進める(約3分・初回のみ) 点が最大のポイントです。
【Step 1】 Cloudflare: トンネル新規作成 ➔ Debianを選択して Token(eyJ...)をコピー
↓ (Cloudflareの画面を開いたまま維持)
【Step 2】 Google Colab: コード実行 ➔ コピーしたTokenを貼り付けてコネクタ起動!
↓
【Step 3】 Cloudflare: タブに戻り「Next」をクリック ➔ ドメイン(公開アプリケーション)を設定して保存
↓
【Step 4】 ローカルPC: 手元アプリ(VS Code / Aider CLI / Web UI)に固定URLを設定!
Step 1. Cloudflare側:トンネルの「枠組み」を作成する
- Cloudflare Dashboard にログインし、左メニューから 「ネットワーク」 ➔ 「Tunnels」 を開きます。
- 「トンネルを作成」 をクリックします。
- トンネル名(例:
colab-qwenなど自分が識別できる名前)を入力し、青色の 「トンネル作成」 ボタンをクリックします。
- トンネル作成後の「環境設定(Install connector)」画面で、OSに 「Debian」(アーキテクチャ: 64-bit)を選択します。(※Colabの実行環境であるLinux/Debianに合わせて選択します)
- 画面に表示されたコマンドの中から
eyJ...から始まる非常に長い英数字の文字列(トークン)だけ をコピーして手元にメモします。
Cloudflareは「トンネルの口」を用意しただけで、まだ向こう側(Colab)から誰も接続しに来ていないため、「接続待機中」のまま右下の「Next」ボタンが押せなくなります。そのため、一旦Cloudflareのタブを開いたままColabへ移動します。
Step 2. Colab側:コードを実行してトンネルを一時起動する
Google Colab側でGPU環境を用意し、先ほど取得したTokenを渡してコネクタ(cloudflared)を立ち上げます。
- Google Colabで新しいノートブックを作成し、「ランタイム」 ➔ 「ランタイムのタイプを変更」 で 「T4 GPU」 を選択して保存します。
- セルに以下の統合Pythonスクリプトを貼り付け、コード先頭の
PUBLIC_URLをご自身のドメインURL(例:https://ai.example.com)に書き換えて再生ボタンを押します。 - 実行が進み、セクション9で
Cloudflare Tunnel Token:の入力ボックスが表示されたら、Step 1でメモしたeyJ...のトークンを貼り付けてEnterを押します。
- ログに
[OK] Cloudflare Named Tunnelプロセス起動と表示されればOKです!
Colab側からCloudflareに向けて「繋がったよ!」と合図が送られました。
code
統合Pythonスクリプトを表示(1セルで実行可能)
expand_more
# ============================================================
# Google Colab: Ollama + Qwen3.5 9B + Cloudflare Named Tunnel
#
# 事前準備 (Cloudflare Dashboard):
# 1. ネットワーク -> Tunnels で Tunnel を作成
# 2. Public Hostname 設定 (例: ai.example.com -> http://127.0.0.1:11434)
# 3. Tunnel Token をコピー
# ============================================================
# 0. 設定 (※ご自身のドメイン・使いたいモデルに変更してください)
MODEL = "qwen3.5:9b"
OLLAMA_HOST = "0.0.0.0:11434"
OLLAMA_LOCAL_URL = "http://127.0.0.1:11434"
PUBLIC_URL = "https://ai.example.com" # ご自身のドメインURLに書き換え
# 1. GPU確認
print("=" * 70 + "\n1. GPU確認\n" + "=" * 70)
!nvidia-smi
# 2. 必要なパッケージ・ツールのインストール
print("\n" + "=" * 70 + "\n2. 必要なツールをインストール\n" + "=" * 70)
!apt-get update -qq && apt-get install -y -qq zstd > /dev/null
print("Ollamaをインストール中...")
!curl -fsSL https://ollama.com/install.sh | sh
print("\ncloudflaredをインストール中...")
!curl -L -s https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64 -o /usr/local/bin/cloudflared
!chmod +x /usr/local/bin/cloudflared
print("[OK] インストール完了")
# 3. バージョン確認
print("\n" + "=" * 70 + "\n3. バージョン確認\n" + "=" * 70)
!ollama --version
print()
!cloudflared --version
# 4. 既存プロセス整理
print("\n" + "=" * 70 + "\n4. 既存プロセスを整理\n" + "=" * 70)
import subprocess, time, requests, json, os, getpass
subprocess.run(["pkill", "-f", "ollama serve"], capture_output=True)
subprocess.run(["pkill", "-f", "cloudflared"], capture_output=True)
time.sleep(2)
print("[OK] 既存プロセス整理完了")
# 5. Ollama起動
print("\n" + "=" * 70 + "\n5. Ollama起動\n" + "=" * 70)
ollama_env = os.environ.copy()
ollama_env["OLLAMA_HOST"] = OLLAMA_HOST
ollama_env["OLLAMA_ORIGINS"] = "*"
ollama_process = subprocess.Popen(["ollama", "serve"], env=ollama_env, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
print("Ollama API起動を待っています...")
ollama_ready = False
for i in range(60):
try:
if requests.get(f"{OLLAMA_LOCAL_URL}/api/tags", timeout=2).status_code == 200:
ollama_ready = True
print("[OK] Ollama API起動成功")
break
except Exception:
pass
time.sleep(1)
if not ollama_ready:
raise RuntimeError("Ollama APIを起動できませんでした")
# 6. モデル確認・ダウンロード
print("\n" + "=" * 70 + f"\n6. モデル確認・ダウンロード\n" + "=" * 70)
print(f"使用モデル: {MODEL}")
res = requests.get(f"{OLLAMA_LOCAL_URL}/api/tags", timeout=10)
existing_models = [m["name"] for m in res.json().get("models", [])]
if any(m == MODEL for m in existing_models):
print(f"[OK] {MODEL} は既に存在します")
else:
print(f"[ダウンロード] {MODEL} をダウンロードします (初回は数分かかります)...")
res_pull = subprocess.run(["ollama", "pull", MODEL], capture_output=False)
if res_pull.returncode != 0:
raise RuntimeError(f"{MODEL} のダウンロードに失敗しました")
print(f"[OK] {MODEL} ダウンロード完了")
# 7. モデル一覧
print("\n" + "=" * 70 + "\n7. モデル一覧\n" + "=" * 70)
res = requests.get(f"{OLLAMA_LOCAL_URL}/api/tags", timeout=10)
available_models = [m["name"] for m in res.json().get("models", [])]
for m in available_models:
print(" -", m)
if MODEL not in available_models:
raise RuntimeError(f"モデル {MODEL} が見つかりません")
print(f"\n[OK] 使用モデル確認: {MODEL}")
# 8. ローカル推論テスト (ウォームアップ & タイムアウト5分)
print("\n" + "=" * 70 + "\n8. ローカル推論テスト\n" + "=" * 70)
print("モデルをGPUへロードしています...")
def test_local_model():
try:
payload = {"model": MODEL, "messages": [{"role": "user", "content": "こんにちは。日本語で短く自己紹介してください。"}], "stream": False}
res = requests.post(f"{OLLAMA_LOCAL_URL}/api/chat", json=payload, timeout=300)
print("HTTP Status:", res.status_code)
if res.status_code != 200:
print(res.text[:2000])
return False
msg = res.json().get("message", {}).get("content", "")
print("\n[モデル応答]\n" + "-" * 50 + f"\n{msg}\n" + "-" * 50)
return True
except Exception as e:
print("[エラー]:", e)
return False
if not test_local_model():
raise RuntimeError("ローカルモデル推論に失敗しました")
print("\n[OK] ローカル推論成功")
# 9. Cloudflare Tunnel Token入力
print("\n" + "=" * 70 + "\n9. Cloudflare Named Tunnel設定\n" + "=" * 70)
TUNNEL_TOKEN = None
try:
from google.colab import userdata
TUNNEL_TOKEN = userdata.get('CLOUDFLARE_TUNNEL_TOKEN')
if TUNNEL_TOKEN:
print("[OK] ColabシークレットからTunnel Tokenを自動読み込みしました")
except Exception:
pass
if not TUNNEL_TOKEN:
print("""
Cloudflare Dashboardで作成した Named Tunnel の Token を入力してください。
※Tokenは入力時に非表示になります。
""")
TUNNEL_TOKEN = getpass.getpass("Cloudflare Tunnel Token: ")
if not TUNNEL_TOKEN:
raise ValueError("Cloudflare Tunnel Tokenが入力されていません")
print("\n[OK] Tunnel Token取得完了")
# 10. Cloudflare Named Tunnel起動
print("\n" + "=" * 70 + "\n10. Cloudflare Named Tunnel起動\n" + "=" * 70)
print("Cloudflare Tunnelを起動しています...")
tunnel_process = subprocess.Popen(["cloudflared", "tunnel", "run", "--token", TUNNEL_TOKEN], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
time.sleep(10)
if tunnel_process.poll() is not None:
print("[エラー] Cloudflare Tunnelが終了しました")
raise RuntimeError("Cloudflare Named Tunnelの起動に失敗しました")
print("[OK] Cloudflare Named Tunnelプロセス起動")
# 11. 外部API接続診断
print("\n" + "=" * 70 + "\n11. 外部API接続診断\n" + "=" * 70)
print("接続先:", PUBLIC_URL)
def check_endpoint(name, method, endpoint, **kwargs):
print(f"\n[{name}]")
try:
if method == "GET":
res = requests.get(endpoint, timeout=60, **kwargs)
else:
res = requests.post(endpoint, timeout=300, **kwargs)
print("HTTP Status:", res.status_code)
print("Server:", res.headers.get("server"))
if res.status_code != 200:
print("Response:", res.text[:1000])
return False
print(f"[OK] {name}")
return True
except Exception as e:
print(f"[エラー] {name}:", e)
return False
local_ok = check_endpoint("1. Colab内 Ollama API", "GET", f"{OLLAMA_LOCAL_URL}/api/tags")
local_v1_ok = check_endpoint("2. Colab内 OpenAI互換API", "GET", f"{OLLAMA_LOCAL_URL}/v1/models")
external_models_ok = check_endpoint("3. Cloudflare経由 OpenAI /v1/models", "GET", f"{PUBLIC_URL}/v1/models")
external_chat_ok = check_endpoint("4. Cloudflare経由 Chat Completion", "POST", f"{PUBLIC_URL}/v1/chat/completions", json={"model": MODEL, "messages": [{"role": "user", "content": "こんにちは。日本語で一言だけ返してください。"}], "stream": False})
# 12. 最終結果
print("\n" + "=" * 70 + "\n■ 最終診断結果\n" + "=" * 70)
print("Local Ollama API:", "OK" if local_ok else "FAIL")
print("Local OpenAI API:", "OK" if local_v1_ok else "FAIL")
print("Cloudflare /v1/models:", "OK" if external_models_ok else "FAIL")
print("Cloudflare Chat API:", "OK" if external_chat_ok else "FAIL")
# 13. 接続情報
if local_ok and local_v1_ok and external_models_ok and external_chat_ok:
print("\n" + "=" * 70 + "\n[成功] 全ての診断に成功しました\n" + "=" * 70)
print(f"\n【OpenAI互換API】\nBase URL: {PUBLIC_URL}/v1\nModel: {MODEL}\nAPI Key: ollama")
print(f"\n【Ollama API】\nBase URL: {PUBLIC_URL}")
print(f"\n【Claude Code / Anthropic互換】\nBase URL: {PUBLIC_URL}\nAuth Token: ollama")
else:
print("\n" + "=" * 70 + "\n[注意] 一部の診断に失敗しました\n" + "=" * 70)
print("""
確認項目:
1. Cloudflare Named TunnelがRunningになっているか
2. Public Hostnameが設定されているか (Service: http://127.0.0.1:11434)
3. PUBLIC_URLが正しいドメインになっているか
4. Cloudflare Tunnel Tokenが正しいか
""")
# 14. Colab終了防止用メッセージ
print("\n" + "=" * 70 + "\n[重要]\n" + "=" * 70)
print("""
このColabセッションを終了すると、Ollama -> Qwen3.5 9B -> Cloudflare Tunnel の全てが停止します。
バックアップAIとして使用中は、このColabセッションを実行したままにしてください。
""")
Step 3. Cloudflare側に戻る:固定ドメインを紐付ける
Cloudflare Dashboardのタブに戻ると、コネクタの接続が検知されて右下の 「Next(次へ)」 ボタンが押せるようになっています(※またはTunnels一覧画面から作成したトンネルの 「+ ルートを追加」 をクリックします)。
- ルートのタイプ選択ダイアログで 「公開アプリケーション」(パブリックホスト名を介してローカルアプリケーションをインターネットに公開する)を選択します。
- パブリックホスト名(Public Hostname)の設定画面で以下を入力して保存します:
- Subdomain:
ai(※ご自由にお好みのサブドメイン名を入力。空欄でルートドメインのままでもOK) - Domain: (※ご自身の所有・管理するドメインを選択)
- Path: (空欄のまま)
- Type:
HTTP - URL:
localhost:11434(または127.0.0.1:11434)
- Subdomain:
- 右下の 「Save tunnel」(またはルート保存)をクリックします。
指定した固定ドメイン(例: https://ai.example.com)に来たリクエストが、自動的にColabのOllamaへと繋がる永久的な仕組みが完成しました!
Step 4. ローカルPC側:手元アプリに固定設定を入れる
手元のアプリ(VS Code / Aider CLI / Cherry Studio 等)に、永久固定の接続設定を登録します。
① VS Code(開発・コーディング用)
VS Code拡張機能(Roo Code, Cline, Continue 等)のプロバイダ設定で以下を登録:
- Provider:
OpenAI Compatible(またはOllama) - Base URL:
https://ai.example.com/v1(※ご自身の固定URL) - Model Name:
qwen3.5:9b(またはColabで指定したモデル名) - API Key:
ollama(ダミーでOK)
② CLI(Aider ターミナルAIコーディングツール)
# 1. pipx で Aider をインストール (初回のみ)
pipx install aider-chat
# 2. 固定ドメインを指定して Aider を起動
aider --openai-api-base https://ai.example.com/v1 --openai-api-key ollama --model openai/qwen3.5:9b
~/.zshrc 等に export OPENAI_API_BASE="https://ai.example.com/v1" と export OPENAI_API_KEY="ollama" を記述しておけば、aider --model openai/qwen3.5:9b だけでいつでも即座に接続できます!
③ ブラウザUI(文章執筆・雑談用)
Cherry Studio や Page Assist 等に登録:
- Base URL:
https://ai.example.com/v1 - Model Name:
qwen3.5:9bを選択
5. Phase 2:2回目以降の日常運用(制限が来た時)
明日以降、ChatGPT ProやClaude Codeで利用制限がかかった時は、行ったり来たりの作業は一切不要 です!
わずか3ステップで作業再開!
- Google Colabを開いて「セルを実行」する
- トークン(
eyJ...)を貼り付けて Enter を押す - 手元のアプリ(AiderやVS Code)でそのまま会話・コーディングを再開する!
※手元アプリのURL設定やCloudflareの画面を操作する必要は今後一切ありません。
Google Colabの左サイドバーにある「シークレット(鍵アイコン)」に、名前 CLOUDFLARE_TUNNEL_TOKEN でトークン文字列を保存し「ノートブックからのアクセス」をONにしておくと、スクリプト実行時に自動でトークンが読み込まれます。
これを設定しておけば、Step 2のトークン手貼りすら不要になり、「Colabを開いてセルを再生するだけ(実質1ステップ・ワンクリック)」で即座に予備機を起動できるようになります!
6. 動作テスト&導通確認
実際に接続をテストし、動作確認を行います。
テスト1: Colab側の導通確認
Colabのセルを再実行すると、外部API接続診断で4項目すべてが [OK] になり、無事に開通したことが確認できます。

テスト2: CLI / Aider でのコーディング・チャットテスト
ターミナルやVS Codeからリクエストを送り、Qwen3.5から正常に日本語でコードや回答が返ってくるか確認します。

7. まとめ

メインAIの利用制限に悩まされている方は、ぜひ「Google Colab × Cloudflare Named Tunnel」による固定ドメインの予備機システムを試してみてね!
完全無料で構築できて、作業の手を止めない最強のバックアップ環境が手に入るよ!