見出し画像

【無料】データサイエンティストのポートフォリオ作り|Difyを使った生成AI系Webアプリの開発

こんにちは、青の統計学です。
ご覧いただきありがとうございます。

青の統計学では、日々データサイエンスの専門性を磨けるコンテンツを配信しています。色々見てやってください。

WEB版https://statisticsschool.com/
特徴:毎日更新、専門的な内容

LINE版https://lin.ee/jY1k9aj
特徴:限定特典、新着通知、アンケートや先行配信

note版https://note.com/bluestatistics
特徴:チートシート、長めで専門的なコンテンツ、

X(旧Twitter版)https://x.com/blue_statistics
特徴:毎日更新、データサイエンス系の優良教材を紹介、スタッフアカウントもよろしくお願いします。


記事の概要と目的

さて、今回は生成AIモデルを簡単にホスティングできるDifyを使って、Webアプリを作成しようと思います。

今回はドメインを作成して、ネットワーク周りを勉強しながらWEBアプリになるまで作ろうと思います。

ここで、ドメイン?デプロイ?など完全にわからなくてもOKです。
めちゃくちゃ丁寧に解説しています。


目的としては、データサイエンティストやWEB系エンジニアの転職や就職のためのポートフォリオ作り皆さんのアプリ作成ハードルを下げることです。

生成AIを使ったWEBアプリを作るのにも一通りWEBの知識やクラウドサーバーの知識が必要なので、streamlit等の簡単なデプロイよりも大変ですが、その分学びは大きいはずです。

本記事のアプリをそのまま真似て作るよりも、それを参考にして、ご自身独自のアプリを作ることをおすすめします。

何より、そのほうが楽しいと思います。



この記事はこんな人におすすめ

・生成AIを使ったWEBアプリを開発して、クラウドサーバーへのデプロイまで行いたい方
・データサイエンティストやIT系のエンジニアの転職のための、ポートフォリオ作りに悩んでいる方
開発経験を積んで行きたい
・資格勉強と並行して、実務に関係するITスキルをつけていきたい方

逆に普段からDIFYでアプリを作ってる方や、デプロイができる方にはおすすめできません。


逐一、用語や仕組みなどは解説しながら超ゆっくり説明していくので、専門知識に自信がなくてもついていけるはずです。むしろ苦手な方向けの記事になります!!

目次を読んでいただけると分かるのですが、基本情報技術者試験や応用情報技術者試験のネットワークやセキュリティ分野の勉強にもなると思います。

勉強しつつ、自分で何かを作る経験をしていただければと思います。


さて、早速やっていきましょう。
どんな知識が学べそうかは上の目次をご覧くださいませ。

別記事はこちら


ゴールの確認

今回は、以下のようなアプリを作成しようと思います。


クラウド環境とデプロイ|AWS

WEBアプリケーションを作成し、世界中に公開するには、サーバーが必要です。中でも、今ではクラウドサーバーを使って簡単にアプリをデプロイできます。

・AWS(amazon web service)
・Azure
・Google Cloud

上のようなサービスがありますが、今回はAWSのLightsailというサービスを使います。

ざっと紹介すると、Amazon LightSailは、AWSの仮想プライベートサーバー (VPS) サービスです。簡単にセットアップできる仮想マシンを提供し、ウェブサイトやウェブアプリケーションのホスティングをシンプルにするために設計されています。

EC2よりも柔軟性は低いですが、誰でも使い易いという特徴があります。

あと3ヶ月無料で使えるのも嬉しすぎる。(24年7月現在)


まずは、こちらからアカウントを作成して、「ルートユーザー」としてログインしてください。



手順1|インスタンス(仮想マシン)の作成

さて、AWSでは、EC2やLightSailなどのサービスで仮想マシンを「インスタンス」と呼びます

こいつをまず作成する必要があります。

インスタンスは、特定のコンピューティングリソース(CPU、メモリ、ストレージ)を持つ仮想サーバーです。

で、なぜインスタンスを最初に作成する必要があるかというと、ウェブサイトやアプリケーションをホスティングするためには、計算リソース(CPU、メモリ、ストレージ)が必要だからです。

インスタンスを作成することで、これらのリソースを確保できます。

そのほかの嬉しい点としては、ホストマシンから独立した環境を提供するため、アプリケーションの開発、テスト、デプロイを行う際に安全で安定した環境を提供できるという点です。


まず、Lightsailの画面に入りましたら、「インスタンスの作成」を押します。


インスタンスを選択

で、このようなインスタンスイメージの画面になりましたら、「オペレーティングシステム(OS)のみ」のUbuntu(22.04 LTS)を選択します。

OSの選択


補足|インスタンスロケーション

上の画面だと「東京」になっていますが、インスタンスロケーションは、クラウドプロバイダーのデータセンターの物理的な場所を指します。

AWSでは、このロケーションを「リージョン」と「アベイラビリティゾーン(AZ)」に分けて管理しています。

リージョンは、地理的に分散されたデータセンターの集合体です。各リージョンは独立しており、異なる場所に物理的に配置されています。

以下のような嬉しいポイントがあります。

  1. 低遅延:

    • リージョンを選択する際、ユーザーに最も近いリージョンを選ぶことで、ネットワーク遅延を最小限に抑えることができます。

  2. 障害の分離:

    • 一つのリージョンで障害が発生しても、他のリージョンには影響を与えません。そのため、災害復旧や高可用性を確保するために、複数のリージョンを使用することが一般的です。

アベイラビリティゾーンは、リージョン内に存在する複数の独立したデータセンターを指します。

  1. 高可用性:

    • 各AZは独立しており、物理的に隔離されているため、障害が発生しても他のAZには影響を与えません。なので、高可用性のシステムを構築することが可能です。

  2. 低レイテンシー接続:

    • 同じリージョン内のAZ間は高速で低遅延のネットワーク接続が提供されており、システム間の通信が迅速に行われます。

レイテンシー:ユーザーのアクション実行から、アプリからアクションへの応答が返されるまでの時間、または要求されたリソースが目的地に到達するまでにかかるネットワーク時間のことです。


補足|OS

今から作成するインスタンスには、コンピュータを操作するためのオペレーティングシステム(OS)が必要です。

今回のOSはUbuntuでいきます。
OSというのは、オペレーティングシステムのことで、作成したインスタンスの挙動を管理する上で大切な役割を持つソフトウェアのことです。

モバイルOSだと、androidやiOSがあるので聞き覚えがあると思います。
ただ、今回はサーバーOSのLinux distributionの一つ、Ubuntuです。

インスタンスにおけるOSの役割を簡単にまとめておきます。

①ハードウェア管理

  • リソースの割り当て:OSはインスタンス内のCPU、メモリ、ディスクストレージなどのハードウェアリソースを管理し、各プロセスやタスクに効率的に割り当てます。

  • デバイスドライバ:ハードウェアとソフトウェアの間の通信を可能にするデバイスドライバを提供し、仮想ハードウェアを適切に動作させます。

 ②ファイルシステム管理

  • データの保存とアクセス:ファイルシステムを提供し、データの保存、読み取り、書き込みを管理します。ユーザーやアプリケーションがファイルにアクセスしやすくするためのインターフェースを提供します。

 ③プロセス管理

  • タスクのスケジューリング:OSは同時に実行される複数のプロセスやスレッドを管理し、CPU時間を効率的に割り当てます。

  • プロセスの隔離と保護:各プロセスが独立して実行され、互いに影響を及ぼさないように管理します。これにより、システムの安定性とセキュリティが向上します。

④ネットワーク管理

  • ネットワーク接続の管理:OSはインスタンスのネットワーク設定を管理し、外部との通信を可能にします。ネットワークインターフェースの設定、IPアドレスの割り当て、ファイアウォールの管理などが含まれます。

インスタンスプランの選択

さて、OSが選択できたら具体的なリソースの選択です。

ケチって一番左のサイズにするとDifyをホスティングできないので注意してください。

2GB分のメモリがあれば十分とされています。




 手順2|SSHによるインスタンスへのアクセス


Amazon LightSail にはSSH接続による安全な通信を行い、インスタンスにアクセスする必要があります。

そのためのキーを作っておくための手順ですね。

  • デフォルトキー: デフォルトで提供されるキーペアを使用するオプションです。

  • 新規作成: 新しいSSHキーペアを作成し、ダウンロードすることができます。

  • 今すぐアップロード: 既存のSSHキーペアをアップロードして使用することができます。


ここでは、既存のSSHキーペアを使いますが、どのオプションを取っていただいても構いません。

キーペアが作り終わったと思うので、「インスタンスの作成」ボタンを押してください。

ちょっと時間が経つと、「Pending」ステータスから「Runnning」ステータス(実行中)にに変わるはずです。


接続というタブから、「ブラウザを使用する」という見出しの「SSHを使用して接続」というボタンをクリックします。


するとコマンドを打つウィンドウが立ち上がると思うので、こちらを入力してください。

curl -fsSL https://gist.githubusercontent.com/gijigae/50f400a5f91a39fbf2f0d0a652a9c409/raw/install-dify.sh -o install-dify.sh

sudo sh install-dify.sh

これ何をやっているかでいうと、install-dify.sh のファイルをLightsailのVM(先ほど作成したインスタンス)へダウンロードし、そのスクリプトを実行するためのコードです。

一つ目のコマンドを分解すると、

  1. curl:指定されたURLからスクリプトをダウンロード

  2. -fオプション:HTTPエラーが発生した場合にcurlを終了させます。

  3. -sオプション:進行状況メッセージを表示しません(静かに実行)。

  4. -Sオプション:エラーが発生した場合にエラーメッセージを表示します。

  5. -Lオプション:リダイレクトがあった場合に追従します。

  6. -o install-dify.sh:ダウンロードしたスクリプトをinstall-dify.shというファイル名で保存します。

sudo sh install-dify.sh

で、二行目のコマンドについては、

  1. sudo:管理者権限(スーパーユーザー権限)でコマンドを実行するために使用されます。(これじゃないと動かないコマンドがあったりします)

  2. sh install-dify.sh:ダウンロードしたスクリプトinstall-dify.shをシェル(sh)を使って実行します。Docker + Difyのインストールが始まります。

この一連のデプロイが完了するまで、5分くらいかかります。



補足|SSH(secure shell)接続

ここでは、上の手順で作ったSSHについて解説します。
作ったキーペアというのは、公開鍵と秘密鍵という用途の違う鍵のペアになります。

手順を説明します。

1. 接続の確立

クライアント(自分のコンピュータ)がサーバー(ここでは作ったインスタンス)に接続を要求すると、サーバーは公開鍵をクライアントに送信します。

2. 鍵交換

クライアントとサーバーは、公開鍵暗号を使用して一時的なセッションキーを生成します。このセッションキーを使用して、後続の通信を暗号化します。

3. ユーザー認証

クライアントは、秘密鍵を使用してサーバーに署名を行います。この署名がサーバーによって検証され、クライアントが正当なユーザーであることが確認されます。具体的には以下のように動作します。

  • サーバーがチャレンジ(ランダムな文字列)をクライアントに送信します。

  • クライアントは秘密鍵を使用してこのチャレンジに署名し、サーバーに返送します。

  • サーバーはクライアントから受け取った署名を、サーバー上に保存されている公開鍵を使用して検証します。(秘密鍵でかけた鍵は公開鍵でしか復号できない)

チャレンジの部分がパスワードの認証と大きく違う点ですね。

レスポンスを返せば、「秘密鍵を知っていることの証明」になるので、通信そのものにパスワードを流す必要がなく、そもそも盗聴の余地がなくなるということです。

パスワード認証よりも安全で、秘密鍵が盗まれない限り、不正なアクセスは困難です。


ちなみに上で接続した方法は、「ブラウザを使ったSSH接続」ですので、クライアントとなるのは、ご自身のローカルコンピュータではなく、AWS Management ConsoleやAWS LightSailのブラウザベースのSSHクライアントです

実は、ユーザーがLightSailコンソールからインスタンスに接続する際、AWSは内部で秘密鍵を使用してSSH接続を確立します。この過程はユーザーからは見えず、自動的に行われちゃうわけです

そもそも、AWSはセッション管理を行い、ユーザーがログインしている間はそのセッション情報を使用してリソースへのアクセスを許可しています。

これにより、ブラウザ(クライアント)から色々とインスタンスの操作ができるわけですね。


セキュリティやネットワーク周りをもっと勉強したい方はこちらもどうぞ




手順3|デプロイと、サイトへのアクセス

手順2でデプロイは完了しました。

早速サイトにアクセスしましょう。

http://IP Address/install

上のURLを作ってサイトへアクセスしてみてください。
エラーが出なければOKです。

まだHTTPS化はしていないので、HTTPSでURLを叩くと、「This site can't be reached」というエラーが出ると思います。この後やりましょう。

このIPアドレスの部分は下のように「Public IPv4」を選択します。


補足|IPv4とIPv6について


さて、パブリックIPv4やプライベートIPv4など色々とインスタンスに紐づくIPアドレスがあると思います。

ひとつずつ解説していきます。

パブリックIPv4アドレス

  • 役割: インターネット上から直接アクセスできる一意のIPアドレスです。このアドレスを使用することで、インターネット上の他のデバイスやユーザーがこのサーバーにアクセスできます。例えば、ウェブサイトのホスティングや公開APIのエンドポイントなどに使用されます。

  • 構造

    • 形式: 32ビットの数値

    • 表記: ドット十進表記(例: 192.168.1.1)

IPv4アドレスは4つのオクテット(8ビットの単位)に分かれており、それぞれが0から255までの値を取ります。例えば、IPv4アドレス 192.168.1.1 は以下のように2進数で表現されます。

192    .168    .1      .1
11000000.10101000.00000001.00000001


プライベートIPv4アドレス

  • 役割: プライベートネットワーク内で使用されるIPアドレスです。インターネットから直接アクセスすることはできませんが、同じネットワーク内の他のデバイスやサービスからNAT(Network Address Translation)を介して通信するために使用されます例えば、内部のデータベースサーバーやアプリケーション間の通信に利用されます。

使用例としては、同じVPC内の他のインスタンスがこのアドレスを使用して通信します。

構造はパブリックIPとおんなじです。


パブリックIPv6アドレス

  • 役割: インターネット上から直接アクセスできる一意のIPv6アドレスです。IPv4アドレスの枯渇を補完するために使用され、より多くのデバイスがインターネットに接続できるようにします。インターネット上のユーザーがアクセスするために使用しますが、IPv6対応のネットワークが必要ってことですね。

  • 構造

    • 形式: 128ビットの数値

    • 表記: コロン十六進表記(例: 2001:0db8:85a3:0000:0000:8a2e:0370:7334)

IPv6アドレスは16ビットのブロックに分かれており、それぞれが4桁の十六進数で表現されます。IPv6アドレス 2001:0db8:85a3:0000:0000:8a2e:0370:7334 は以下のように2進数で表現されます。(2進数で表すと長い汗)

2001:0db8:85a3:0000:0000:8a2e:0370:7334
0010000000000001:0000110110111000:1000010110100011:0000000000000000:0000000000000000:1000101000101110:0000001101110000:0111001100110100




セキュアな通信|HTTPS化


AWSLightSailでDifyをクローンすることができましたね。

ただ、よく見ていただくと通信のプロトコルがHTTPのままであることに気がつきます。

カスタマー観点で、通信内容はセキュアであることは望ましいし、サイトの順位にも関わりますので、SSLの証明書を発行し、HTTPSの設定を行うことが望ましいです。

ドメインも独自のものが欲しいですね。


手順4|独自ドメインの作成

では、Light Sailコンソールから独自ドメインを作成するところから始めましょう。

まず、下のように [ドメインと DNS] タブを選択します。
[ドメインの登録] を選択し、登録するドメインを指定します。

その後、取得したいドメイン(なんでもOK)を入力し、 ドメインの登録をしてください。

年間14ドル〜のような利用料金の画面が出るはずです。

まあ勉強代ですね…



手順5|静的なIPアドレスの作成とHTTPSポートの許可


Webサイトのドメイン名とIPアドレスを紐づけるためには、DNS(Domain Name System)と呼ばれるシステムを用います。ただ、インスタンスを再起動して、もしIPアドレスが頻繁に変更されてしまうと、双方の紐づけが解除されてDNSシステムで管理ができなくなってしまうため、WebサーバーのIPアドレスを固定(静的なもの)する必要があります。

なので、今回の静的IPの作成が必要なのです。

さて、ネットワーキングタブを選択して、「静的IPをアタッチ」を選択します。

※静的IPをアタッチしないと、インスタンスを再起動した際にIPアドレスが変更されてしまいます。

インスタンスはパブリック IPv4 アドレスとして静的 IP を使用しており、インスタンスを停止して起動しても、静的 IP は変更されません(ここが嬉しいポイント)。



さて、静的IPを区別する文字列を入力します。
上のように「StaticIP-dive」としています。

その後、「作成及びアタッチ」ボタンをおします。


次は、HTTPSポートの許可をします。
「IPv4ファイアウォールのルール追加」でHTTPSを許可します。

これは、ここまで作成したインスタンスで暗号化した通信を許可するために必要です。

ちょっと補足をすると、ファイアウォールルールで「HTTPS」を許可する設定は、外部からのHTTPSトラフィックを受け入れることを意味しており、具体的には、インターネット上の任意のIPv4アドレスからポート443へのアクセスを許可しています。

ちなみにHTTPSは、デフォルトでTCPポート番号443を使用します。ポート443は、ウェブブラウザがHTTPS経由でサーバーにアクセスするための標準ポートです。(デフォルト値)



補足|静的なIPアドレスとは


静的IPアドレス(Static IP Address)は、ネットワークデバイスに対して手動で設定される固定のIPアドレスです。


特徴

  1. 固定されたIPアドレス: 一度設定された静的IPアドレスは、デバイスがネットワークに接続されている限り変わることがありません。

  2. 手動設定: ネットワーク管理者が手動でデバイスに割り当てます。

  3. 安定性: サーバーやネットワーク機器の設定が変更されることなく、長期間にわたって安定した通信が可能です。


*例えば、ローカル環境では、社用のネットワークプリンターやルーターのように、複数の端末からアクセスする機器を利用する際、固定IPアドレスの方が通信が安定するため、プライベートIPアドレスを固定IPアドレスとして設定することがあります。

他にも、使用例で言うと、ISPから静的IPアドレスを取得することで、自宅やオフィスのネットワークデバイスに固定のグローバルIPアドレスが割り当てられます。家やオフィスのネットワークに外部からリモートでアクセスする場合に便利です。

まとめると利点はこんな感じです。

  • リモートアクセス: リモートデスクトップやVPNなどで特定のデバイスに接続する場合、IPアドレスが変わらないため接続が容易です。

  • サーバーのホスティング: ウェブサーバー、メールサーバー、FTPサーバーなど、外部からのアクセスが必要なサーバーに対して、安定したアクセスを提供できます。

  • ネットワーク管理: 固定IPを使用することで、ネットワーク内のデバイスを容易に管理・監視できます。


これに対して、動的IPアドレス(Dynamic IP Address)はDHCP(Dynamic Host Configuration Protocol)サーバーによって自動的に割り当てられ、一定期間後に変更される可能性があります。



補足|HTTPとHTTPSについて

ここまででWebブラウザとインスタンス間で暗号化通信を許可することができました、

とはいえHTTPとHTTPSで何が違うのでしょうか?
詳しく見ていきましょう。

HTTPSは、HTTPにセキュリティ機能を追加したプロトコルです。

具体的には、SSL/TLS(Secure Sockets Layer/Transport Layer Security)を使用してデータを暗号化(公開鍵暗号方式で、共通鍵を受け渡し、データを暗号化)し、通信の機密性、整合性、認証を保証します。

以下のような特徴を持ちます。

  1. 暗号化:データが暗号化されて送信されるため、通信内容が第三者に傍受されても解読できません。

  2. 認証:SSL/TLS証明書を使用して、サーバーの身元を確認します。これにより、クライアントは接続先が正当なサーバーであることを確認できます。

  3. データの整合性:データが改ざんされていないことを保証します(データが送信途中で変更されていないかを確認するための仕組みがあるので)

暗号化の仕組みまでちゃんと理解したい方は、こちらをみると良いと思います。


SSL/TLS認証については、以下に詳しく記述しています。




手順6|静的IPと作成した独自ドメインの紐付け


さて、ここまで作った静的IP(アタッチ済み)と独自ドメインを紐付けます。

これにより、ユーザーがドメイン名(こっちの方がわかりやすい)を入力するだけで、正しいサーバーにアクセスできるようになります。

上述しましたが、このプロセスはDNS(Domain Name System)を使用して実現されます。DNSは、ドメイン名をIPアドレスに変換する役割を持ち、DNSサーバーはこの変換を行うためのデータベースを保持しています。


サイドバーからドメインとDNSを選択し、「DNSゾーンの作成」をクリックします。

ドメインのソースは「Amazon Route53」で登録されているドメインを使用で、DNSゾーンを作成してください。

自分で作成したドメインを選択し、割り当てタブに移動します。
「割り当てを追加」で、先ほど作成し静的IPアドレスを選択します。

以下のような画面になればOKです。


次に、DNSレコードのタブに移動し、Aレコードが作成されていることを確認してください。



Aレコード(Address Recordの略)は、DNSにおけるレコードの一種で、特定のドメイン名をIPv4アドレスに対応付ける役割を持ちます。

これにより、ユーザーがドメイン名を入力すると、そのドメイン名が対応するIPアドレスに解決され、そのIPアドレスを持つサーバーに接続されます。構成要素は以下のとおりです。

  • ホスト名: ドメイン名またはサブドメイン名(例: example.comやwww.example.com)。

  • タイプ: レコードのタイプ。Aレコードの場合は「A」。

  • : 対応するIPv4アドレス(192.0.2.1など)。

  • TTL(Time to Live): レコードの有効期限を秒単位で指定します。この時間が経過すると、再度DNSサーバーから最新の情報を取得します。デフォルトでいいです。


最後にドメインタブに移動し、「ドメインに移動」というボタンを押してください。

ドメインのページに飛ぶと思います。

詳細/連絡先情報/アドバンストのうち、詳細タブに移動し、Lightsail ネームサーバーを使用を押してください。

これで上のような状態になれば完了です。
無事に静的IPアドレスと独自ドメインの紐付けができました。




手順7|Certbotのインストール

ここからHTTPS化の工程は結構手強いです。

先ほど、difyをデプロイしたように、ブラウザを使ったSSH接続をしましょう。


SSHを使用して接続をクリック


さて、以下のコマンドを実行してCertbotをインストールします。

sudo snap install core 
sudo snap refresh core sudo 
snap install --classic certbot

Certbotは、Let's Encryptの証明書を取得および更新するための自動化ツールです。一つずつコードを紐解きます。

  • sudo snap install core

    • 内容:Snapパッケージマネージャーのコアパッケージをインストールします。

  • sudo snap refresh core

    • 内容:コアパッケージを最新バージョンに更新します。

  • sudo snap install --classic certbot

    • 内容:Certbotをインストールします。

SnapはLinuxディストリビューション間で共通のパッケージ管理システムであり、独立して動作するため依存関係の問題が少ないです。




手順8|SSL証明書の取得


では、パッケージがインストールできたのでSSL証明書を取得していきます。

sudo service apache2 stop
sudo certbot certonly --standalone -d example.com


example.com

の部分は、ご自身で作ったドメインにしてください。

こちらもコードを解説していきます。

sudo service apache2 stop

このコマンドは、Apacheサーバーを一時的に停止します。

Certbotが動作するためには、ポート80(HTTP)および443(HTTPS)がCertbotによって使用できるようにする必要があります。なので、既存のWebサーバーがこれらのポートを占有している場合、一時的に停止する必要があるのです。

sudo certbot certonly --standalone -d example.com

二つ目のコマンドを実行すると、Certbotはスタンドアロンモードで一時的なWebサーバーを起動し、指定したドメイン名(この場合はexample.com)の証明書を取得します。

成功すると、証明書と秘密鍵が次のパスに保存されます

  • 証明書のパス: /etc/letsencrypt/live/example.com/fullchain.pem

  • 秘密鍵のパス: /etc/letsencrypt/live/example.com/privkey.pem


これでSSL証明書を取得できました!

当然取得するだけではアクセスはできないのです。


あとはサーバ側のファイルの設定を変更する必要があります。もうちょい具体的に言うと、取得した証明書と秘密鍵を使用して、Webサーバーの設定を更新し、HTTPS接続を有効にすることができます。





手順9|vimエディタを使い、docker-compose.yamlを修正


まず、 /Dockerディレクトリに移動してみましょう。

cd ~/dify/docker/

cd コマンドは、指定されたディレクトリに移動します。

この場合は、ホームディレクトリ内の dify/docker ディレクトリに移動しています。cdコマンド自体は、めちゃくちゃ使う頻度が多いので覚えておくと良いと思います。


次に、docker-compose.yamlをvimで開きます。

sudo vi docker-compose.yaml 
  • vi: テキストエディタのVimを起動

  • docker-compose.yaml: Docker Composeの設定ファイルです。このファイルには、複数のDockerコンテナの設定が記述されています。

yamlはjsonと違って、コメントアウトができるので、人間がわかりやすいようなドキュメントやAPIの仕様書とかを記述するのに向いています。


さて、ファイルと開いてやることは377行目以降の下記の2行を変更します。

  nginx:
    image: nginx:latest
    restart: always
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./nginx/proxy.conf:/etc/nginx/proxy.conf
      - ./nginx/conf.d:/etc/nginx/conf.d
      - /etc/letsencrypt:/etc/letsencrypt <--変更
    depends_on:
      - api
      - web
    ports:
      - "80:80"
      - "443:443" <--#を削除する

NGINXが80番ポートと443番ポート(HTTPSのデフォルトのポート番号でしたね)をリッスンし、HTTPとHTTPSの両方のトラフィックを処理できるようになります。

最後に、コマンドモードで:wqで保存してvimを終了します。
→wが保存で、qで終了と覚えましょう。



補足|NGINXとリバースプロキシ


さて、手順9について何をやっているのかいまいち掴めない方もいらっしゃると思います。ここでは、リバースプロキシとして働くNGINXというWEBサーバについて解説します。

まず、リバースプロキシについて解説しましょう。

リバースプロキシは、クライアントからのリクエストを受け取り、そのリクエストを適切なバックエンドサーバーに転送するサーバーです。


やることとしては、クライアントとリバースプロキシ間の通信を暗号化し、バックエンドサーバーに平文のリクエストを送信します。

これにより、クライアントはリバースプロキシを通してバックエンドサーバーにアクセスするため、クライアントはバックエンドサーバーの存在や位置を直接知ることはありません(バックエンドのIPアドレスやネットワーク情報を隠すことができる)


リバースプロキシは、SSL/TLS証明書の管理と更新を集中管理できるので、今回NGINXの設定ファイルをいじって、443ポートをリッスンする必要があったというわけです。




手順10|vimエディタを使い、default.confを修正


default.confはNGINXのデフォルト設定ファイルで、サーバーの基本設定を定義します。インストール時に作成され、一般的な設定が含まれていますが、運用に合わせてカスタマイズが可能です。

まずは、/conf.dディレクトリに移動します。

cd ~/dify/docker/nginx/conf.d/



default.confをvimで開きます。

sudo vi default.conf 



「server_name」に独自ドメインを記載します。

server_name 独自ドメイン;

NGINXサーバーがどのドメイン名に対応するかを指定しています。

server_nameディレクティブに独自ドメインを設定することで、そのドメインに対するリクエストがこのサーバーブロックで処理されるようになります。


以下のコメントアウトされている部分のコメントを外します。
default.conf

listen 443 ssl;
ssl_certificate ./../ssl/your_cert_file.cer;
ssl_certificate_key ./../ssl/your_cert_key.key;
ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;

手順9でもやりましたが、HTTPSを有効にし、SSL/TLS証明書を設定します。

  • listen 443 ssl;: サーバーがポート443(HTTPSのデフォルトポートでしたね)でSSL/TLSを使用してリクエストを待ち受けるようにします。

  • ssl_certificateとssl_certificate_key: SSL/TLS証明書と秘密鍵のファイルパスを指定します。サーバーがSSL/TLS通信を行うための証明書を読み込みます。

  • ssl_protocols: 使用するSSL/TLSプロトコルのバージョンを指定します。ここでは、TLSv1.1、TLSv1.2、TLSv1.3が有効化されています。

  • ssl_prefer_server_ciphers: サーバーが暗号スイートの選択において優先権を持つように設定します。

  • ssl_session_cacheとssl_session_timeout: SSLセッションのキャッシュ設定を行います。セッションキャッシュのサイズと有効期限を設定することで、パフォーマンスを向上させます。まあデフォルトでいいです。


あと少しです。
下の2行を修正します。

ssl_certificate ./../ssl/cert_file.cer;
ssl_certificate_key ./../ssl/your_cert_key.key;

ssl_certificate /etc/letsencrypt/live/独自ドメイン/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/独自ドメイン/privkey.pem;

察しがつくかもしれませんが、これは SSL/TLS証明書と秘密鍵のファイルパスを正しく設定するための修正です。

  • ssl_certificate: サーバー証明書ファイルのパスを指定します。サーバーがクライアントとセキュアな通信を確立するための証明書を使用します。

  • ssl_certificate_key: 証明書に対応する秘密鍵ファイルのパスを指定します。秘密鍵は証明書とペアで機能し、暗号化通信を可能にします。



最後に、Dockerを再起動します。

sudo docker-compose down
sudo docker-compose up -d


お疲れ様でした。
これでHTTPS化は完了です。

https://example.comでアクセスできると思います。

次はいよいよdifyを触っていきましょう。
個人的には、次の工程が工夫のしがいがあるし、一番楽しいと思います。

この先で作ったDifyアプリをAPIとして、同じドメインでUIを変えたWEBアプリを作る、など色々応用ができるはずです。


補足|dockerファイルとNGINX設定ファイルの制御スコープ

さて、手順9でも同じようなことをやったので、なんでNGINXのファイルもいじる必要があるのかと感じるかもしれません。

ここでは、docker-compose.yamlとdefault.confの違いをはっきりさせましょう。


docker-compose.yaml

  • レベル: Dockerコンテナレベル

  • 役割: ホストマシン(ご自身のサーバーやパソコン)のポートをDockerコンテナ内の特定のポートにマッピングします。

  • 効果: 外部からホストマシンの特定のポートにアクセスすると、そのリクエストが対応するコンテナのポートに転送されます。

これにより、外部からホストマシンのポート80にアクセスすると、そのリクエストはNGINXコンテナのポート80に転送されます。同様に、ホストマシンのポート443にアクセスすると、そのリクエストはNGINXコンテナのポート443に転送されます。

具体で言うと、portsセクションで "80:80" と "443:443" を指定することで、ホストのポート80と443をそれぞれコンテナのポート80と443にマッピングできます。


NGINX設定ファイル(default.conf)

  • レベル: アプリケーション(NGINX)レベルでの設定。

  • 効果: NGINXがリクエストを受け取った際に、どのポートでリクエストを待機し、どう処理するかを決定します。

  • ポート80: HTTPリクエストを受け取ります。この場合、リクエストはリバースプロキシとして設定されたバックエンドサーバー(ここではapiサービス)に転送されます。

  • ポート443: HTTPSリクエストを受け取ります。SSL/TLS証明書を使ってセキュアな通信を行う設定を追加します。ssl_certificateとssl_certificate_keyで指定された証明書と秘密鍵を使用してHTTPS通信を行います。←今回はこれを追加した。


イラストにするとこんな感じです。


NGINXはdockerコンテナ内のアプリケーションレイヤーに位置し、docker-compose.yamlで定義されたポートマッピングを通じてホストからのリクエストを受け取ります。




生成AIのホスティング|DIFY


手順11|openAIやAnthoropicのAPI取得

Difyは手持ちのAPIキーを使う必要があります。

まだでしたら、OpenAIやAnthropicなどのAPIキーを用意してください。

用意できると、モデルプロバイダーの画面で、モデルが利用できることがご覧の通りわかります。

openAIは以下になります。(すみません、なぜか埋め込めない..)

https://platform.openai.com

Anthropicは以下です。




手順12|difyによるアプリの作成


さて、デプロイしたDifyを使っていきます。

Difyを使用することでチャットボットやAIアシスタント、テキスト生成・分析ツール、カスタムアシスタントなどさまざまなAIアプリケーションを作成できるのが魅力です。

この場でやり方を細かく教えずとも、色々動かしていけばやり方はわかってくるはずです。

身の回りにどんな課題があって、その原因は何か、そしてそれを解決するためにどんなアプリを作ろう、と課題ベースで考えるのが、広く長く使ってもらえるアプリを作るための考え方です。

上記のように堅苦しく考えるのではなく、既成プロダクトのお手伝いをするような、例えばチャットボットなどを作ってみたり、またはアキネーターのようなジョークツールを作ってみるのも面白いかもしれませんね。


ーチャットボットー

今回は、チャットボットを選択します。

自分のサイト内で、ユーザーの学習を補助するためのツールを作ろうと思います。アプリの名前や説明を記載すると、「スタジオ」というドラッグ&ドロップでアプリのフローが組める画面になります。

完成版はこのサイトの右端で見れます。
API利用料がかかるので、そのうちやめているかもしれません笑

さて、ワークフローやチャットボットなど色々種類はありますが、今回はチャットボットを選びます。(ここからは記事と同じものを作らないでください。皆さん自身のアプリを好きなように作ってください。

モデルの部分ですが、前の手順でAPIキーを入力して認証が成功していると、LLMを選んだ時にモデルが選べます。


LLMモデルの選択

LLMモデルが選択できると、以下のようなプロンプトが設定できます。
ユーザが入力したテキストを変数として利用して、文脈に沿った回答ができるように変数を埋め込んであげてください。


補足|temperatureとTop Pなどのハイパーパラメータについて

ハイパーパラメータについて

さて、モデルが出力するテキストで温度やtop kなど見慣れないものがあると思います。

これは、LLMモデルの出力を調整し、特定のタスクや要件に適した応答を生成するために重要なものです。

デフォルトでもいいですが、テストをしながらいじってみてください。

Temperature (温度): 生成テキストの多様性を制御します。次のソフトマックス関数で表現できます。

$${ P(x_i) = \frac{\exp(x_i/T)}{\sum_j \exp(x_j/T)} }$$

ここで、$${ T }$$ は temperature パラメータです。$${ T }$$ が低いほど、より確実な選択がなされ、高いほど、より多様な出力が生成されます。

急にデータサイエンスの話になってしまいすみません。
ソフトマックス関数はこちらでも扱っています。


Top P (核サンプリング): 累積確率分布の閾値を設定し、その閾値を超える最小の語彙集合から単語を選択します。

$${ \text{Top P} = \min{k : \sum_{i=1}^k P(x_i) \geq p} }$$

$${ P(x_i) }$$ は確率の降順でソートされた単語の確率分布です。

Top k: 各ステップで最も可能性の高い k 個の次の単語のみを考慮し、その中から選択します。サンプリングですね。

$${ \text{Top k} = {x_1, x_2, ..., x_k} \text{ where } P(x_1) \geq P(x_2) \geq ... \geq P(x_k) }$$

Max Tokens: 生成されるテキストの最大長を制限します。数式的な表現はありませんが、制約条件として表現できます。

$${ \text{Generated Tokens} \leq \text{Max Tokens} }$$

まとめると、Temperature と Top P は多様性と一貫性のバランスを取るのに役立ち、Top k は考慮する語彙を制限し、Max Tokens は出力の長さを管理します。

デフォルトでもいいですが、ぜひいじってみてください。


編集画面

会話の開始機能まで作ると、よりホスピタリティのあるチャットbotになりそうです。

さて、「公開」ボタンを押して、アプリを公開します(このあと何度でも編集はできます。)


備考ですが、このアプリを自分のサイトに埋め込む方法について解説します。Webサイトのチャットボットとして扱いたいので、公開用のモーダルの中に「埋め込む」というボタンがあるはずですので、こちらをクリックします。

これはDify無料版でもできるはずです。

埋め込みを選択

*ワークフローなど、チャットボット以外のアプリだとこのボタンが表出しない場合があるのでご注意ください。


iframeを埋め込もう!

次にやることは、DifyからコピーしたコードをWordPressのWPCodeへ貼り付けます。

wordpressの管理画面

WPCodeプラグインのメニューから「Add Snippet」を選択しますと次の画面が表示されます。

ページから「Add Your Custome Code」をクリックし、Snippetの名前など必要な情報を入力してください。Snippetが有効(Active)になっていないと、ページを保存してもチャットボットが表出しないので注意してください。


Snippetを保存した後、Difyチャットボット用のショートコードをコピーしてください。こちらのコードはChatbotを埋め込むページに貼り付けます。

全てのページに埋め込みたい場合は、ショートコードではなく、Auto Insertを選択してください。


補足|WEBページの描画タイミングとfunction.phpについて


ただ、上記のやり方だとプラグイン間のjavascriptが競合したりでうまくスニペットが動かない場合があります。

そんな時は、function.phpに以下のような関数を追加するとやりたきことが達成できます。

function add_dify_chatbot_script() {
    if ( is_single() || is_page() ) {  // 投稿ページや固定ページにのみ追加
        ?>
        <script>
        window.difyChatbotConfig = {
            botId: 'YOUR_BOT_ID',
            // その他の必要な設定
        };
        </script>
        <script src="https://your-dify-chatbot-script-url.js" async></script>
        <?php
    }
}
add_action('wp_footer', 'add_dify_chatbot_script');

function.phpは、WordPressのテーマ機能を定義するファイルです。

このファイルは、ページの生成プロセスの早い段階で読み込まれます。wp_footer フックを使用することで、ページのレンダリングの最適なタイミングでスクリプトを挿入できます。

これにより、DOMの準備が整った後でスクリプトが実行されることが保証されます。

*ちなみにDOMは、Document Object Modelの略称です。HTMLやXMLドキュメントなどのマークアップ言語と、CSSをJavaScriptなどのプログラミング言語からアクセスできるようにするためのAPIのことです。
これにより、HTMLやXMLの構造を定義し、文書へのアクセスをはじめ、操作や変更が可能となります。


DOMのイメージ図


もうちょいちゃんと解説します。

大前提として、WordPressはリクエストを受け取ると、まずwp-config.phpを読み込み、次にwp-load.phpを実行します。その後、テーマのfunctions.phpが読み込まれます。

↑WordPressコアの初期化後、かつページコンテンツの生成前に発生

この時点で、functions.phpに定義された関数や添付されたアクションがWordPressのメモリに登録されます。

wp_footerフックは、WordPressのテンプレート階層の最後、この辺りはHTMLがわかっていると想像しやすいのですが、</body>タグの直前に実行されます。

このフックは、ページの主要なコンテンツがすべて生成された後に発火します。

その後、ブラウザがHTMLを解析し、DOMツリーを構築する過程で、</body>タグの直前に配置されたスクリプトは、ほぼすべてのDOM要素が利用可能になった時点で実行されます。

上記の嬉しい点が二つほどあります。

①ページの主要コンテンツの読み込みをブロックされない
②スクリプトが参照するDOM要素がすでに存在することを保証される



実行順序の詳細をまとめると、

  • WordPressがページを生成 → HTMLの開始部分を出力

  • ページコンテンツを生成

  • wp_footerフックが呼び出され、登録された関数(この場合、チャットボットスクリプト)を実行

  • </body>タグと残りのHTMLを出力

  • ブラウザがHTMLを受け取り、解析を開始する

  • DOMの構築が完了に近づくと、チャットボットスクリプトが実行される


なので、ページが全部描画された後に、下のこいつが出てくると思います。

やあ


違う視点で見ると、このようにテーマファイル内でスクリプトを管理することで、不正なコード挿入のリスクを低減します。実は、データベースに保存されるプラグイン設定(WP Code)よりも安全な方法です。


以上です。
お疲れ様でした!

青の統計学では、寄稿や運用に参加していただけるメンバーなどを募集中です。ぜひこちらから問い合わせてみてください。


頂いた活動費は、全て「青の統計学」活動費用に使います!note限らずサービス展開していくのでお楽しみに!