Cloudflare Tunnel + Access + WARPを使って、ローカルLLMのサービスを外部から使う

ぼくの今使っているPCには結構リッチなGPUを搭載しています。NVIDIA RTX4070です。これはメモリが12GByteあり、小規模なLLMのモデルを高速に動かすことができます。このGPUをできるだけ活用するため、外出先からもローカルで動かしたLLMのサービスにアクセスできる環境を構築しました。

ぼくはlulliecat.comというドメインをもっており、それをCloudflareで管理しています。Cloudflareには、TunnelとAccess、WARPという機能があります。これらを使うことで、ローカルのサービスに外部から安全にアクセスできる環境を作ることができます。

ローカルサーバーで動作するサービスをインターネットに公開し、外出先からも使えるようにするためには、サービスが公開されるポートをルーターで開放した上で、ポートをサーバーが動くマシンに転送する設定が必要です。この構成では、ルーターに直接外部からアクセスが到来します。そのため、ルーターで動くnftablesなどを正しく設定すると共に、様々なセキュリティ上の問題が発生しないように管理をする必要があります。ぼくはセキュリティに関しては素人なので、これはなかなか骨の折れる仕事です。 そもそも、公開したサービスは自分だけが使えるようにしたいため、そのために全世界に向けてポートを公開するのは避けた方が良いと思います。

Cloudflare TunnelとAccess、WARPを使うことで、この問題は解決します。 まず、Cloudflare Tunnelを使うことで、ポートを開けることなくローカルサーバーのサービスをインターネットに公開することができます。 外部からのアクセスはまずCloudflareが受け、それに対してTunnelがそのリクエストをローカルのサーバーに転送します。 そのため、サーバーが接続しているルーターのIPアドレスは公開されず、セキュリティ上の懸念がひとつ減ります。 同時に、Cloudflare Accessを使うことで、特定のユーザーだけがローカルサーバーのサービスにアクセスできるように制御することができます。 emailを用いたPIN認証と、WARPというVPNサービスによる認証を行うことで、外部からのアクセスを制御できます。これにより、自分のPCで動かしたLLMのサービスを外出先からも安全に利用できる環境を作ることができます。

以下では、これらの機能を実際に使うための具体的な手順を紹介します。

1. 準備するもの - Windows編

ドメインは例えばcomドメインが1年10ドルくらいです。Cloudflareのアカウントは、個人で使う程度の環境であれば無料で利用できます。 ドメインはCloudflareで管理してください。Cloudflareを通じてドメインを買うと、自動的にCloudflareで管理されます。 Cloudflare以外からドメインを買った場合は、移管が必要です。その方法は今回は省きます。 ローカルサーバーはご自分のPCなどを使用します。ぼくは、RTX4070搭載のWindows11のPCを使用しています。外出時も電源を入れっぱなしにして、ローカルサーバーを動かしています。 以下、Windows11を想定して説明を行います。

2. サーバーを導入する(1) Ollama

まず、サービスを提供するサーバーソフトウェアを導入します。今回は、LLMのモデルを動かし、HTTPを用いたAPIを提供するサーバーソフトウェアとして、Ollamaを使用しています。Visual Studio CodeなどのエディタからOllamaのサーバーに接続することにより、プログラムの作成や修正をLLMに任せたりできます。そこそこ便利です。

一応、簡単にOllamaの導入方法を説明します。 Download Ollamaのページから、ollamaをダウンロードし、インストールします。 これで、OllamaがHTTP APIとして提供され、ローカルサーバー上で動作します。APIは http://localhost:11434 に公開されています。 ブラウザからこのアドレスにアクセスすると、サーバーが動いている場合は「Ollama is running」というメッセージが表示されます。 もしサーバーが動いていない場合は、下記のコマンドをコマンドプロンプトから入力して再確認してください。

ollama serve

次に、Ollamaに導入できるモデルのリストから、お好みのモデルをダウンロードしてインストールします。 例えば、deepseek-r1の14bモデルをインストールには以下のコマンドを用います。

ollama pull deepseek-r1:14b

モデルのページに、モデルのファイルサイズが書かれています。GPUのメモリと同程度かそれ以下のサイズのモデルであれば問題なく動作します。 インストール済みのモデルは以下のコマンドで確認できます。

ollama list

3. サーバーを導入する(2) open-webui

OllamaはHTTP経由のAPIだけを提供します。このAPIを解釈し、ブラウザ越しにチャットするようにLLMにアクセスするためには、Open WebUIというサーバーソフトウェアを使用します。ChatGPTにアクセスした時のような画面でLLMと会話できるため、とても便利です。

Open WebUIはDockerを用いて動作させるのが最も簡単です。ざっくりした手順は以下の通りです。

  • WSL2のインストール
  • Dockerのインストール
  • Open WebUIのDockerイメージのダウンロードと起動

まず、WSL2をインストールします。Windows10からWSL2を使う場合は、コマンドプロンプトから以下のコマンドを実行します。

wsl --install

次に、Dockerをインストールします。Dockerのホームページから、ご利用のOSに対応したDocker Desktopをダウンロードしてインストールします。 インストール時、「Use the WSL 2 based engine」にチェックを入れてください。

最後に、Open WebUIのDockerイメージをダウンロードし、起動します。以下のコマンドを実行してください。このコマンドはOpen WebUIの公式ドキュメントから抜粋しました。

docker run -d -p 3000:8080 --add-host=host.docker.internal:host-gateway -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main

http://localhost:3000/ にアクセスすると、Open WebUIの画面が表示されます。アカウントを登録し、LLMとチャットできることを確認してください。 これで、OllamaとOpen WebUIを組み合わせて、ブラウザからLLMにチャットできる環境が完成しました。

4. Cloudflare Tunnelの設定

OllamaやOpen WebUIなどの作成したサービスをインターネット上に公開し、外出先などからもアクセスできるようにします。

まず最初に、Ollamaの初期設定では外部からのアクセスを受け入れないため、環境変数の設定により外部からのアクセスを受け入れるように変更します。 Windowsの検索窓に「環境変数を編集」と入力して、編集画面を表示させます。 次に、ユーザー環境変数の項目へ、新規をクリックし、次の二つの環境変数を設定します。

変数名変数値
OLLAMA_HOST0.0.0.0
OLLAMA_ORIGINShttps://[ollama server FQDN]

OLLAMA_ORIGINSの箇所は、サービスを公開するサーバーのFQDN(ホスト名とドメイン名)を設定します。例えば、貴方の管理している ドメインがyourdomain.comで、ollamaのサービスをollamaというホスト名で公開する場合は、[ollama server FQDN]を「ollama.yourdomain.com」で置き換えてください。 後ほど説明する、Cloudflare tunnelにおいても、同じ[ollama server FQDN]を使用します。 変更後は、環境変数の変更を適用するため、Windowsを再起動してください。

次に、Cloudflare Zero Trust organizationの作成 が必要、のようです。すっかりやり方を忘れました…ヘルプによると、Cloudflare Dashbordに行き、左のサイドバーからZero Trustを 選択すると、organizationを入力するように促される、ようです。

次に、Cloudflareへのトンネルを作ります。ブラウザ上での作り方があり、これは簡単なのですが、このやり方だと複数のポートを同時に一つのcloudflaredというソフトからトンネルすることができません。 そのため、今回はサーバーPCのコマンドプロンプトから設定を行う方法を説明します。コマンドプロンプトを開き、自分のホームディレクトリ(C:\Users\[user name])にいることを確認したのちに、以下のコマンドを実行してください。

winget install --id Cloudflare.cloudflared
mkdir .cloudflared
cloudflared tunnel login
cloudflared tunnel create [tunnel name]

[tunnel name]は任意の名前で置き換えてください。半角英数字ならなんでも大丈夫です。これでトンネルの作成までできました。

次に、トンネルを通じて公開するサービスを設定します。 C:\Users\[user name]\.cloudflared\config.yml というテキストファイルを作成し、以下の内容を書き込んでください。

tunnel: [tunnel UUID]
credentials-file: C:\Users\[username]\.cloudflared\[tunnel UUID].json
originRequest:
  connectTimeout: 30s

ingress:
  - hostname: [ollama server FQDN]
    service: http://localhost:11434
  - hostname: [OpenWebUI server FQDN]
    service: http://localhost:3000
  - service: http_status:404

cloudflare tunnel loginすると、C:\Users\[user name]\.cloudflared\[tunnel UUID].json というファイルが作成されます。 [tunnel UUID]はこのファイル名の.jsonを除いた部分です。これを上記ファイルの[tunnel UUID]の箇所に設定してください。 hostnameの箇所は、サービスを公開するサーバーのFQDN(ホスト名とドメイン名)を設定します。例えば、貴方の管理している ドメインがyourdomain.comで、ollamaのサービスをollamaというホスト名で公開する場合は、[ollama server FQDN]を「ollama.yourdomain.com」で置き換えてください。 [OpenWebUI server FQDN]も同様に好きな名前に決めて設定してください。

次に、CloudflareのDNS設定で、上記で設定したhostname (ollama.yourdomain.comなど)をCloudflareのDNSに登録します。 ollama.yourdomain.comとopen-webui.yourdomain.comという名前を使っている場合は、以下のコマンドを実行してDNSに登録します。ollamaとopen-webuiの箇所はご自分で設定したホスト名に置き換えてください。

cloudflared tunnel route dns [tunnel name] ollama
cloudflared tunnel route dns [tunnel name] open-webui

次に、設定したトンネルが動作するかテストします。次のコマンドを実行します。

cloudflared --config=C:\Users\[username]\.cloudflared\config.yml tunnel run [tunnel name]

[tunnel name]は上記で設定した名前で置き換えてください。正しく動作している場合は、Cloudflare Zero Trustのページ、左サイドバーから「ネットワーク > Tunnels」を選び、設定した名前のトンネルがリストアップされ、「HEALTHY」というステータスになっていることが確認できます。 また、ollama.yourdomain.com と open-webui.yourdomain.com にブラウザからアクセスできることも確認してください。 httpではなく、httpsであることに注意してください。無料でhttpsにしてくれます。Cloudflare万歳。 コマンドプロンプトでCtrl-Cを押してcloudflaredを停止します。

最後に、Windowsを再起動してもcloudflaredが自動的に起動してトンネルが構築されるようにサービスを設定します。以下のコマンドを実行します。

サービスの作成だけは、コマンドプロンプトではなく、Windows PowerShellから行います。コマンドプロンプトからscコマンドを使うことでもできるはずなのですが、 ちょっと使い方が微妙にわからなかったのでこちらを使いました。

New-Servine

Name: と問われるので、そこは「cloudflared」と入力します。 次に、BinaryPathName: と聞かれるので、以下の内容を入力してください。

"C:\Program Files (x86)\cloudflared\cloudflared.exe" tunnel --config C:\Users\[username]\.cloudflared\config.yml run [tunnel name]

最後に、コマンドラインから作成したこのサービスを起動します。

sc start cloudflared

これで、Windowsを再起動してもcloudflaredが自動的に起動してトンネルが構築されるようになります。 また、ollama.yourdomain.com と open-webui.yourdomain.com にブラウザからアクセスできることも確認してください。 これで、外出先からもローカルのLLMに接続し、チャットができるようになりました。

5. Cloudflare Accessの設定

このままですと、アクセス制限がかけられていないため、誰でも公開されたサービスにアクセスできるようになっています。 Cloudflare Accessを使用して、特定のユーザーのみにアクセスを制限することができます。 今回は、登録したemailとOne Time PINを用いた認証、及びCloudflare WARPというVPNを使用した認証について説明します。 以下、ブラウザでCloudflare Zero Trustのページにアクセスし、そこから作業します。 ぼくはもう一度設定してしまい、手順は忘れたので、いくつか間違いがあるかもしれません。ご了承ください…

まず、One Time PINの設定を行います。 左側のサイドバーから、「設定 > 認証」を選び、ログイン方法の「新規追加」をクリックします。One-Time PINを選んで追加します。

次に、左側のサイドバーから「Access > ポリシー」を選択し、「ポリシーを追加する」を押します。 まずポリシー名を入力します。なんでもいいです。例えば、「Allow Access to Ollama and OpenWebUI」と設定します。 アクションは「Allow」であることを確認してください。セッション時間はお好みで。デフォルトの「アプリケーションセッションタイムアウトと同じ」でいいと思います。

ルールも追加します。セレクターに「emails」を選び、値にあなたのemailアドレスを入力します。 他にもセレクタがあるので、ヘルプを参照して設定もできます。

最後に、ポリシーを適用するサービスを設定します。左側のサイドバーから「Access > アプリケーション」を選択し、「アプリケーションを追加する」を押します。 「セルフホスト」をクリックし、アプリケーション名を入力します。名前はなんでもいいです。セッション時間もお好みで。 デフォルトの24時間だと毎日認証が必要で面倒くさい、という人はもっと長いセッション時間を選んでください。

「+パブリックホスト名を追加」をクリックし、まずollamaサーバーを設定します。入力方法はデフォルトのまま、 サブドメインに最初に設定したホスト名(例えばollama)を、ドメインにあなたのドメイン名(yourdomain.com)を入力します。 同様に、open-webuiサーバーも設定します。サブドメインにopen-webui、ドメインにyourdomain.comを入力します。

次に、Accessポリシーを設定します。「既存のポリシーを選択」をクリックし、先ほど作成したポリシー名にチェックを入れて確認をクリックします。

次に、WARPによる認証も有効にします。一番下の「WARP認証をオンにする」スライドボタンを緑色のチェックが入った状態にしてください。

一通りの設定は終わりました。一番右下の「次へ」をクリックします。表示される「エクスペリエンス設定」はそのままで大丈夫です。一番右下の「次へ」をクリックします。 「詳細設定」もそのままで大丈夫です。一番右下の「保存」を押して、アプリケーションの追加を終了します。

以上の作業を終えると、Cloudflare Accessが有効になり、特定のユーザーのみにアクセスを制限することができます。 また、ollama.yourdomain.com と open-webui.yourdomain.com にブラウザからアクセスすると、email入力が促され、PINコードも必要になることを確認してください。

6. Cloudflare WARPの導入

ブラウザからサービスにアクセスするだけですと、これで十分です。一方、VSCodeからはこのままだとサービスにアクセスできません。PINによる認証がVSCode上で行えないからです。 そこで、Cloudflare WARPというVPNを導入し、その認証情報を使うことで、VSCodeからもサービスにアクセスできるようにします。

の、ですが…どうやったのか全て忘れました…多分こうじゃないか、というのを書きます。すいません…

まず、左サイドバーから「設定」を選び、「WARPクライアント」を選択します。デバイス追加権限の管理をクリックし、Accessポリシーの「既存のポリシーを選択」をクリックして、 先ほど作成したポリシー名にチェックを入れて確認をクリックします。ログイン方法タブをクリックし、One Time PINが設定されていること、WARP認証IDがチェックされていることを確認します。

次に、外出先からアクセスするのに使うマシンにWARPクライアントを導入します。WARPのダウンロードとインストールを行います。WARPを起動し、右下のギアアイコンをクリックします。Preferences > Accountに移動し、「Login with Cloudflare Zero Trust」を選びます。 ここで入力するのは、Cloudflare Zero Trustにアクセスしたときに一番最初に設定したorganizationの名前です。 emailによるOne Time PIN認証が走るはずです。認証を通すとログイン完了となります。WARPクライアントTOPのスライドボタンが緑色になっていることを確認することで、 Clodflareに接続されていることを確認することができます。これで、VSCodeからもサービスにアクセスできるようになります。

7. VSCodeのContinueからのアクセス

ぼくはとりあえずVSCodeでLLMを使える拡張はいくつかあるようですが、ぼくはとりあえず、Continueを使っています。 以下、Continueでollamaにアクセスする設定を紹介します。

VSCodeの拡張機能からContinueを導入し、一番左側のバーからContinueのアイコンを選択します。 上の方にギアアイコンがあるので、これをクリックします。そうすると、config.jsonが開きます。 ここの設定を以下のように変更してください。

{
  "models": [
    {
      "model": "AUTODETECT",
      "title": "Autodetect",
      "provider": "ollama",
      "apiBase": "https://ollama.yourdomain.com/"
    }
  ],
  "tabAutocompleteModel": {
    "title": "qwen2.5-coder:7b",
    "provider": "ollama",
    "model": "qwen2.5-coder:7b",
    "apiBase": "https://ollama.yourdomain.com/"
  },
  "tabAutocompleteOptions": {
    "contentLength": 8192,
    "maxTokens": 8192,
    "temperature": 0.01,
    "debounceDelay": 500,
    "maxPromptTokens": 8192
  },
  "embeddingsProvider": {
    "provider": "ollama",
    "model": "nomic-embed-text:latest",
    "maxChunkSize": 512,
    "maxBatchSize": 5,
    "apiBase": "https://ollama.yourdomain.com/"
  },
  "contextProviders": [
    {
      "name": "code",
      "params": {}
    },
    {
      "name": "docs",
      "params": {}
    },
    {
      "name": "diff",
      "params": {}
    },
    {
      "name": "terminal",
      "params": {}
    },
    {
      "name": "problems",
      "params": {}
    },
    {
      "name": "folder",
      "params": {}
    },
    {
      "name": "codebase",
      "params": {}
    }
  ],
  "slashCommands": [
    {
      "name": "share",
      "description": "Export the current chat session to markdown"
    },
    {
      "name": "cmd",
      "description": "Generate a shell command"
    },
    {
      "name": "commit",
      "description": "Generate a git commit message"
    }
  ]
}

modelはollamaでpullしたモデルを設定してください。これでVSCodeからLLMにアクセスできます。

まとめ

Cloudflareはとても優秀なのですが、とにかく設定が複雑で、絶対に覚えられないなこれ、と思ったのでメモとしてこの記事を作成しました。 将来のぼく、これを見て頑張ってくれ…

8. おまけ: llama.cppのWSL2上でのビルド

WSL2ではCUDAも使えます。以下、WSL2上でCUDAを使ったllama.cppをbuildする手順です。nixを導入して、flakeを使ってビルド環境を構築しています。 また、事前にCUDA SDK on WSLも導入しておいてください。オフィシャルのドキュメントのコピペで大丈夫です。

mkdir ~/.config/nix
echo "experimental-features = nix-command flakes" > ~/.config/nix/nix.conf
git clone https://github.com/ggerganov/llama.cpp.git
cd llama.cpp
sh <(curl -L https://nixos.org/nix/install) --no-daemon
nix develop
cmake -B build -DGGML_CUDA=ON
cmake --build build --config Release -j 32

echo 'LD_LIBRARY_PATH=/usr/local/cuda-12.6/targets/x86_64-linux/lib:/usr/lib/wsl/lib:/home/[username]/llama.cpp/build/ggml/src/ggml-cuda /home/[username]/llama.cpp/build/bin/llama-server -m $1 -ngl 48 -b 4096' >> run.sh
chmod +x run.sh
./run.sh [model_path]

疲れたしおまけなので雑に…なんとか読み解いてください…