Cloudflare Tunnel 構築（後編）

[前編](https://qiita.com/b-wind/items/d47eb0e9aef33a3b4327)では Cloudflare DNS を使用してドメインを運用する環境を整えました。
後編は Dify Server をインターネット側から接続できるようにしていきます。

<img width="80%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90456/d0ec9a94-3f1a-467a-8edb-35309836ce88.png" />

## インターネット接続用 トンネルの作成
Dify Server からインターネットへ接続する「専用線」にあたる『トンネル』を作成します。

このトンネルの入り口ですが、実はインターネットに直結してはいません。
Cloudflare Netwaork の先には「Edge Server（エッジサーバー）」と呼ばれるサーバーが多数 存在し、外部のPC/スマホからのアクセスは すべて エッジサーバー を介して Dify Server へ到着する仕組みです。

<img width="90%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90456/b8e36f7e-1d38-4076-b30b-8ef73c8d9f03.png" />

:::note info
一般的に、ブラウザは 地理的に一番近いエッジサーバーへアクセスします。 
:::

### ① トンネルの作成
Zero Trust 画面を開き、「ネットワーク」-「Tunnels」をクリックします。

<img width="40%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90456/ce5a7650-8b8d-4b9a-a3f4-f82cf1ae2667.png" />

画面中央の「トンネルを追加する」ボタンをクリックします。

<img width="90%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90456/c11eb6ce-87aa-40b8-84f7-f8c9f9fe33c4.png" />

トンネルの種類として「**Cloudflared**」を選択します。
枠内 または「選択する Cloudflared」ボタンをクリックします。

<img width="90%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90456/f798e8f4-fc36-4ca4-8bcf-c2f21dd25026.png" />

「トンネル名」欄に任意の名前を入力します。
入力後、「トンネルを保存」ボタンをクリックします。

<img width="90%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90456/cdd9a12d-9e8b-401f-907f-7430e969b873.png" />

:::note info
トンネル名は後から変更することも可能です。
:::

### ② cloudflared の導入
トンネルを形成するために Cloudflare Naetrork との通信を行う、「cloudflared」のインストトール環境を選択します。
今回は Dify と同じ Docker 環境に導入するので、「Docker」ボタンをクリックします。

<img width="90%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90456/a1f0ea6c-95b2-47d5-94dc-58b60bb05fab.png" />

「cloudflared」のコンテナイメージを導入するコマンドが表示されます。
右端のコピーアイコンで、```docker run```コマンド全体をコピーしてください。

<img width="90%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90456/3730bf37-b22f-47ca-bae6-48567b0b4e5e.png" />

そのままでも問題なく実行できますが、次の二つのオプションを付加することにします。

|オプション|説明|
|:-|:-|
|-d　　　　　　　　|プロセスをバックグラウンドで実行する。|
|--network=host|ホストOSのネットワーク環境へダイレクトに接続する。<br/>ポートマッピング や NAT 処理も行われないので、ネットワーク性能の低下を抑制できる。|

:::note warn
```--network=host```を指定するとネットワーク利用時のオーバーヘッドが軽減する代わりに、ホストOS との「論理的なネットワーク境界」も無くなります。
コンテナ内のアプリケーションに脆弱性が含まれていた場合、コンテナを介してホストOSが危険にさらされる恐れもあります。
:::
　
```docker run```コマンドのオプションに、上表のオプションを追加します。

<img width="70%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90456/f0a8dbb1-cea3-46d7-bcc6-f151cc851f03.png" />

　
Ubuntu の端末画面を開き、コマンドを実行します。

```bash
$ docker run -d --network=host cloudflare/cloudflared:latest tunnel --no-autoupdate run --token eyJhIjoiZGZ (以下省略)
Unable to find image 'cloudflare/cloudflared:latest' locally
latest: Pulling from cloudflare/cloudflared
51c1b6699f43: Pull complete 
2e4cf50eeb92: Pull complete 
4e9f20d26c87: Pull complete 
0f8b424aa0b9: Pull complete 
d557676654e5: Pull complete 
d82bc7a76a83: Pull complete 
d858cbc252ad: Pull complete 
1069fc2daed1: Pull complete 
b40161cd83fc: Pull complete 
3f4e2c586348: Pull complete 
80a8c047508a: Pull complete 
e95e5abe292b: Pull complete 
04155d74e8b4: Pull complete 
7c2744d8f2aa: Pull complete 
Digest: sha256:522827fe622024 (以下省略)
Status: Downloaded newer image for cloudflare/cloudflared:latest
d45d53821 (以下省略)
```
　
```docker run```コマンドが成功すると「Connectors」欄の表示が切り替わります。
この状態は、トンネルが開通したことを示しています。
続けて「次へ」ボタンをクリックします。

<img width="90%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90456/c3bbb977-ed86-435c-9e64-3aa0b07b6ab0.png" />

### ③ パブリックホスト名の登録

トンネル経由で接続する「パブリックホスト」を登録します。
登録したパブリックホスト名（サブドメイン名）は DNS の Aレコード として登録され、インターネット側からの名前問い合わせに対して「サーバーのIPアドレス」を返却します。

:::note info
登録画面には IPアドレス の入力欄がありません。
にも関わらず ```nslookup``` や ```dig``` コマンドでは IPアドレスが返却されます。

実は 返却されるのは「cloudflare が運用する IPアドレス」です。
パブリックホスト名 一つに対して複数の IPアドレス が自動的に割り当てられます。

以下は、```dig```コマンドの実行結果（一部）です。
```text
dify.■■■■■■■.■■■.	105	IN	A	104.21.80.1
dify.■■■■■■■.■■■.	105	IN	A	104.21.96.1
dify.■■■■■■■.■■■.	105	IN	A	104.21.48.1
dify.■■■■■■■.■■■.	105	IN	A	104.21.112.1
dify.■■■■■■■.■■■.	105	IN	A	104.21.64.1
dify.■■■■■■■.■■■.	105	IN	A	104.21.16.1
dify.■■■■■■■.■■■.	105	IN	A	104.21.32.1

■■■■■■■.■■■.		172605	IN	NS	aliza.ns.cloudflare.com.
■■■■■■■.■■■.		172605	IN	NS	mitch.ns.cloudflare.com.
```

上記は、パブリックホスト名として「dify」を登録した後の確認結果です。
cloudflare 管理下の IPアドレス や ネームサーバー名 が登録されています。
:::
　

**パブリックホスト名** として、「サブドメイン」「ドメイン」「パス（省略可）」を入力します。（インターネット側からアクセスするときの URL を表しています）

**サービス** の「タイプ」「URL」には、「<font color="red">cloudflared コンテナからアクセスするときの プロトコル/URL</font>」を入力します。

|項目　　　　　　　|設定内容　　　　　　　|備考|
|:-|:-|:-|
|サブドメイン|dify||
|ドメイン|(登録先ドメイン)|
|タイプ|HTTP||
|URL|localhost:20080|```--network=host```オプションを付けてコンテナを起動しているので、localhostでも接続可能。

 
<img width="90%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90456/0e1aa3ce-8963-403e-8a21-711e8169074b.png" />

「トンネルを保存」ボタンをクリックすると、パブリックホスト名の登録は完了です。

## 接続確認

Dify Server と同じネットワーク内に存在する、別PCのブラウザからアクセスしてみます。
接続先の URL は「https://dify.■■■■■■■.■■■ 」です。

<img width="90%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90456/7fffa647-10dd-4c72-9fe8-63bdf0a7161f.png" />

特に問題なくログインページが表示されました。
証明書も正式なものが適用されているようです。

<img width="70%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90456/f4a7ee05-425c-4e86-a701-476823b7b31f.png" />

### なぜ dify.■■■■■■■.■■■ でアクセスできるのか？
同じネットワーク内に存在するとは言え、別のPC から「dify.■■■■■■■.■■■」という名前で Dify Server へアクセスできています。
Home Network 内の DNS サーバー や PC内の hosts ファイルも編集していません。
どういう理屈で接続できているのでしょうか？

<img width="90%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90456/b755f233-8445-48cc-815f-22aad21d406c.png" />

「一度 インターネットへ出た後、cloudflare の Edge Server 経由でアクセスしている」が、その答えとなります。

かなりの回り道なので通信パフォーマンスの低下は否めませんが、特に何もしなくても 同じ URL でアクセスできるなら それに越したことはありません。
（正直、Home Network 内で独自の名前解決を図るのは面倒くさいのです）

回り道の影響が顕著に表れるまで、当面 このまま運用することにします。


## HTTPS通信の強制
ところで、この時点では「http://dify.■■■■■■■.■■■ 」を指定したときも Dify Server へ接続できてしまいます。
デリケートな情報を扱うことを考えると、暗号化されない「HTTP通信」が可能 という状況は 好ましくありません。

通信設定を変更し、「HTTP で接続されたら強制的に HTTPS に切り替える」ことにします。
　

cloudflare へログインし、アカウント ホーム画面の ドメイン名をクリックします。

<img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90456/3861c4ca-0dde-44e7-97f1-c9f06ddba754.png" />

SSL/TLS メニューを展開し、「エッジ証明書」をクリックします。

<img width="40%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90456/2b48dcf4-15d0-4341-afcb-ed6eac05b2b8.png" />

「常に HTTPSを使用」を「ON」状態に変更します。（既定は「OFF」）

<img width="90%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90456/319cd225-b8f3-40dc-8500-45da00af1d51.png" />

これで「http://dify.■■■■■■■.■■■ 」の接続が 自動的に「https://dify.■■■■■■■.■■■ 」へ切り替わるようになりました。

## 終わりに
「Dify によるアプリ開発」の環境構築が、ようやく ひと段落付きました。
自宅・外出先 のどちらでも、全く同じように開発作業を進めることが可能です。

ただ…

公開したアプリに対する アクセス制限 を行う仕組みがありません。
アプリの URL を知っているユーザーは、何の確認もなくアプリを利用できてしまうのです。

これはセキュリティの観点からは「問題あり」です。
「アプリへのアクセス制限」の実現方法を模索する必要がありそうです。

いろいろと検討中ですが、別の機会を設けて 試行錯誤 することにしましょう。