Cloudflare Quick Tunnels を使って Vagrant + VMware Fusion のローカル環境で Webhook 受信してみたの巻

Date:

Share post:

ローカル環境でテストしているときに、こんな場合があります。
  • 外部サービスから Webhook を受信したい。
  • ただ、グローバル IP があっても、内向きのアクセス経路を作れない(社内 LAN のルーター設定は触れない)。

社内ネットワークの外から見るとグローバル IP はあるものの、社内の PC や VM へはルーターのポート転送(NAT)がないと届きません。ルーター設定を触れない環境では、インターネットからローカルへ直接アクセスする経路を自分では作れない、という状態になります。

加えて Webhook について少し書くと、Webhook は、GitHub・Stripe・SendGrid などの外部サービスが、こちらの URL に HTTPS で POST してくる仕組みです。つまり「こちらから API を叩く」のではなく、「相手からこちらに届く」必要があります。 localhost や 192.168.x.x の URL は外部から見えないため、そのままでは Webhook を受け取れません。

このような場合にどう対応する方法があるものかとネットで調べてみたところ、渡りに船で見つけたサービスが Cloudflare Quick Tunnels です。今回は、社内 LAN 上の Vagrant + VMware Fusion 環境で 外部サービスの Webhook を受信するための手順を書いてみようと思います。

まず、Cloudflare Quick Tunnels についてどのようなものかを書いてみたいと思います。

公式の図と説明もあるのでリンクをつけましたが、 Cloudflare Quick Tunnels は、ローカルに cloudflared を置き、サーバー側から Cloudflare へ外向きに接続を張る仕組みです。

通常、社内ネットワークは「外への通信は通すが、外からの直接アクセスは拒否」という設定になっていることが多いです。Cloudflare Quick Tunnels はこの前提に合わせて、ルーターで内向きの穴を開けずに外部と通信します。

外部サービス(SendGrid など)は Cloudflare が発行する URL(Quick Tunnels なら *.trycloudflare.com)に HTTPS で POST します。Cloudflare がそれを受け取り、すでに張ってあるトンネル経由でローカルの Web サーバーへリクエストを渡します。

ここでひとつ誤解されやすいのが、「外向き接続だけなら送信しかできないのでは?」という点です。実際には VM 側から Cloudflare へ接続を張り、その TCP 接続を維持したまま HTTP のリクエスト/レスポンスをやり取りします。接続の開始は「内→外」ですが、トンネルが確立されれば外部からローカルへ届く Webhook も受け取れます。

ここまでの説明が長くなってきたので、次は実際に接続できるか確認してみます。今回は、社内 LAN 上の Vagrant VM で Web サーバーを動かし、cloudflared で Quick Tunnels を張って、外部から HTTPS でアクセスできるかを見ます。

【今回の環境】
ホスト: macOS + Vagrant + VMware Fusion
ゲスト: Rocky Linux + Webmin + Virtualmin + LAMP
トンネル: cloudflared(Quick Tunnels)

また例によって Webmin / Virtualmin の設定等は割愛します(笑)。今回は EC-CUBE が表示できる環境にしています。

1)cloudflared をインストール

VM に SSH して、cloudflared をインストールします。

$ vagrant ssh
$ sudo su -

# curl -fsSL https://pkg.cloudflare.com/cloudflared.repo | tee /etc/yum.repos.d/cloudflared.repo
# dnf install -y cloudflared
# cloudflared --version
cloudflared version 2026.6.1 (built 2026-06-18-14:33 UTC)

バージョンが表示されれば OK です。

2)cloudflared を起動する(が失敗・・・)

それでは早速 cloudflared を起動してみます。

$ sudo su -
# cloudflared tunnel --url http://120.0.0.1:80

起動に失敗してコケています。原因を探ります。

failed to request quick Tunnel: Post "https://api.trycloudflare.com/tunnel":
dial tcp: lookup api.trycloudflare.com on 192.168.XXX.2:53: no such host

最後の方にメッセージが出ています。注目するのはメッセージの最後の部分です。

  • api.trycloudflare.com … cloudflared がトンネル作成時に接続する先
  • 192.168.XXX.2:53 … 名前解決に使った DNS サーバー(ホストと同じ LAN 上の DNS )
  • no such host … その DNS では名前を解決できなかった

DNSの名前解決のところで止まっている模様です。そのため、VM内でどのDNSを使用しているかを確認してみます。

# cat /etc/resolv.conf

nameserver がホストと同じ LAN 上の DNS (192.168.XXX.2)になっています。

続けて、外部ドメインが解決できるのかを確認してみます。

正常なら IP アドレスが返りますが、警告のメッセージが出ていて名前解決ができていません。

VM に設定されていた DNS(192.168.XXX.2)では解決できないため、
パブリック DNS(1.1.1.1 など)を使うようにします。変更にあたって、コネクション名を確認します。
 
Wired connection 1 というコネクション名となっているのでこれを使用します。
 
ただ resolv.conf は、起動のたびに NetworkManager が作り直すことがあります。
VM 内で一度だけ手動変更しても、再起動で 192.168.XXX.2 に戻る可能性があるため、
Vagrantfile に次のように記述し、起動時に毎回パブリック DNS が使われるようにします。
 
    # ゲスト起動時に DNS を固定(192.168.XXX.2 対策)
    # 注意: nmcli con down/up は SSH 経路を切るため使わない
    config.vm.provision "shell", run: "always", inline: <<-SHELL
      nmcli con mod "Wired connection 1" ipv4.dns "1.1.1.1 8.8.8.8"
      nmcli con mod "Wired connection 1" ipv4.ignore-auto-dns yes
      nmcli device reapply eth0
    SHELL

3)Vagrant 再起動

Vagrantfile を修正したので、再起動してパブリック DNS が使用されるようにします。

最後の方のメッセージで、プロビジョニングのシェルが動いたことが確認できます。それでは先ほどと同じように、 VM に ssh で入って確認してみます。

パブリック DNS が使用されていることの確認と、名前解決ができて IP アドレスが取得できています。

4)cloudflared 起動(また別の問題・・・)

ここでもう一度、cloudflared を起動してみたのですがちょっと問題があったので、画像のキャプチャがないので記録で残します。

# cloudflared  tunnel --url http://127.0.0.1:80

上記コマンドで cloudflared 自体は起動したのです。しかしながら、トンネルの確認を行うためにホストPC側から以下コマンドを実行したところ、400エラーとなってしまいました。

$ curl -I Cloudflare Quick Tunnelsから払い出されたURL

なんでかなと思い、よくよく思い出してみると今回は EC-CUBE を入れた環境です。

EC-CUBE の設定( .env )に TRUSTED_HOSTS 環境変数があり、ここで許可されていないと参照できないことを思い出しましたので、以下のように設定しました。

気を取り直して、今度こそと curl を 実行したら 今度は 301 リダイレクトがループするという状態になってしまいました。

これもなんでかなと考えてみると、

# cloudflared  tunnel --url http://127.0.0.1:80
原因は、cloudflared が VM 内へ HTTP(80)で届けている一方、ローカルサイトは自己証明書の HTTPS(443)で動いているためです。外側はすでに HTTPS なのに、内側では「まだ HTTP」と見えて 301 が繰り返されていました。
 
そのため、cloudflared の転送先をローカルの HTTPS に合わせて変更します。
自己証明書を使っているので、証明書検証をスキップするオプション( –no-tls-verify )も付けました。
 

5)cloudflared 今度こそ起動

4)の経緯がありましたので、cloudflared を一度落として、再度以下コマンドで起動させます。

# cloudflared tunnel --url https://127.0.0.1:443 --no-tls-verify

無事起動しました・・・。

起動が成功すると、https://xxxx.trycloudflare.com のような URL が表示されます。ただし、Quick Tunnels では、cloudflared を起動するたびにこの URL が変わります。URL をメモしても再起動後には使えないので、検証で起動のたびに表示された URL を確認してください。
 
では、ホスト PC 側から curl で確認してみます。
 

200 で 返ってきています。

では、インターネット越しでローカル環境のサイトが表示できるかを確認してみます。

表示されました!

6) Webhook の確認

今回自分が確認したかったのは、Webhook がローカル環境で受けられるかということでしたので、実験のために以下を準備しました。

webhook-test.php

<?php
// 検証用: トンネル経由の POST 確認
$logFile = __DIR__ . '/webhook-test.log';

file_put_contents(
    $logFile,
    date('c') . ' ' . file_get_contents('php://input') . "\n",
    FILE_APPEND
);

header('Content-Type: application/json');
http_response_code(200);
echo json_encode(['ok' => true]), PHP_EOL;

中身は簡単なものですが、POSTされてきたら、内容をログファイルに書き込み、 response を返す処理です。ソースはドキュメントルートに設置して、ログはドキュメントルート直下の webhook-test.log に出力します。

ホスト PC を外部サービスと見做し、以下コマンドで POST します。

$ curl -i -X POST "https://【 Cloudflare Quick Tunnels で払い出されたURL】/webhook-test.php" -H "Content-Type: application/json" -d '[{"event":"test"}]'

【ホスト側】

【ゲスト側】

ローカル環境にPOSTされていることが確認できました!

7)最後に

今回は、ルーターのポート転送なしで、ローカルの Vagrant 環境を Cloudflare Quick Tunnels 経由で一時的に外部公開し、 Webhook の POST が届くところまで確認しました。
 
色々ありましたが・・・
 
Cloudflare Quick Tunnels は起動のたび URL が変わり、検証向けの一時的な仕組みではありますが、ルーターの変更をすることなく外部サービスとやりとりの確認ができたり、一時的にローカル環境のサイトを公開できたりできるのは便利だなと思いました。
 
一時的なものではなく、再起動しても同じ URL が必要な場合は、別の Cloudflare Tunnels の構成を検討してください。あとは、一時的に外部と通信可能な状態になるので、検証が終わったら cloudflared を止めて、閉じることをお忘れなく。
 

Related articles