はじめに
この記事では、Dify の利用を検討している方向けに、Azure VM へDifyをデプロイし、さらにEntraID認証 を統合してセキュリティを確保する手順を解説します。
目的
- Azure VMにDifyをデプロイする。
- Entra ID認証を導入し、セキュリティを確保する。
前提条件
- Azureサブスクリプションを持っていること
- SSH接続が可能な環境があること
- 基本的なLinuxコマンドの知識があること
構成
Azure VM上に、nginx、および、Difyを構築します。
nginxはクライアントからのSSL通信を受け付け(SSL終端)、
その通信をDifyへ転送するリバースプロキシとして構成されます。
1. Azure VMの構築
まず、Azure VMを準備します。OSはUbuntu24.04にしました。
SSH(22)、HTTP(80)、HTTPS(443)ポートを許可します。
ネットワークセキュリティグループの設定について、
この後、HTTP-01 チャレンジ(後述)があるので、IPアドレスでのアクセス制限は後で実施するようにします。
2. 確認用Webアプリケーションのデプロイ
Entra ID認証とNginxの設定が正しく機能するかを確認するため、シンプルなFlaskアプリケーションをデプロイします。
Python, pip, venvのインストール
Pythonのバージョンはその都度変えてください。
sudo apt update
sudo apt install python3 python3-pip -y
sudo apt install python3.12-venv
仮想環境の作成と有効化
python3 -m venv venv
source venv/bin/activate
Flaskのインストール
pip install Flask
簡単なFlaskアプリケーションの作成と動作確認
以下のコードでapp.pyを作成します。
from flask import Flask, request
app = Flask(__name__)
port = 8080 # このポートでリッスンします
@app.route('/')
def home():
user_info = '認証されていません。'
# oauth2-proxy が追加するヘッダーからユーザー情報を取得
user = request.headers.get('X-Auth-Request-User', 'N/A')
email = request.headers.get('X-Auth-Request-Email', 'N/A')
groups = request.headers.get('X-Auth-Request-Groups', 'N/A')
if user != 'N/A' or email != 'N/A':
user_info = f"""
<p><strong>認証済みユーザー情報:</strong></p>
<ul>
<li><strong>ユーザー:</strong> {user}</li>
<li><strong>メールアドレス:</strong> {email}</li>
<li><strong>グループ:</strong> {groups}</li>
</ul>
"""
html_content = f"""
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>テスト Web アプリ</title>
<style>
body {{ font-family: sans-serif; margin: 40px; background-color: #f4f4f4; color: #333; }}
.container {{ background-color: #fff; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }}
h1 {{ color: #0056b3; }}
ul {{ list-style-type: none; padding: 0; }}
li {{ margin-bottom: 8px; }}
strong {{ color: #007bff; }}
</style>
</head>
<body>
<div class="container">
<h1>ようこそ、テスト Web アプリへ!</h1>
<p>このページは、Azure VM 上で動作し、Nginx と oauth2-proxy を通してアクセスされています。</p>
{user_info}
<p>リバースプロキシと認証が正しく設定されていることを確認してください。</p>
</div>
</body>
</html>
"""
return html_content
if __name__ == '__main__':
app.run(host='0.0.0.0', port=port)
下記プロンプトで起動します。
python3 -m app
起動し、アクセス可能なことを確認します。
アクセス後は仮想環境を終了します。
deactivate
3. Entra IDのアプリケーション登録
DifyへのアクセスにEntra ID認証を利用するため、Azure Portalでアプリケーションを登録します。
- Azure Portal へのサインイン
- Microsoft Entra IDを検索して選択
- 左メニューの「アプリの登録」を選択し、「+ 新規登録」をクリック
- アプリケーションの登録 ページで以下を設定:
- 名前: 任意の分かりやすい名前 (例: MyWebApp-OAuth2Proxy)
- サポートされているアカウントの種類: 要件に応じて選択します。通常は「この組織ディレクトリのみに含まれるアカウント (シングル テナント)」または「任意の組織ディレクトリ内のアカウント (任意の Azure AD ディレクトリ - マルチテナント)」を選択します。
- リダイレクト URI (オプション):
- プラットフォーム: 「Web」を選択
- URI: https://<任意>.<リージョン名>.cloudapp.azure.com/oauth2/callback
oauth2-proxy のデフォルトのコールバックパスは /oauth2/callback です。
- 「登録」をクリック
登録が完了すると、アプリケーションの概要ページが表示されます。以下の情報をメモします。
アプリケーション (クライアント) ID
ディレクトリ (テナント) ID
- 左メニューの「証明書とシークレット」を選択
- 「+ 新しいクライアント シークレット」をクリック
- 説明: 任意の分かりやすい説明 (例: oauth2-proxy-secret)
- 有効期限: 推奨される期間を選択します。
「追加」をクリックします。
- 作成されたシークレットの「値」を必ずメモする
※この値はページを離れると二度と表示されません。
4. NginxとCertbotのインストール
HTTPS通信を有効にし、SSL証明書を取得するためにNginxとCertbotを導入します。
Nginxのインストール
sudo apt update
sudo apt install nginx -y
sudo systemctl enable nginx
sudo systemctl start nginx
Certbotのインストール
Certbotは、ウェブサイトをHTTPS化するために必要なSSL/TLS証明書を、無料で自動的に取得・インストール・更新できるツールです。便利。
そのために、Snapパッケージを最新化した上で、インストールしています。
sudo snap install core
sudo snap refresh core
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
Nginxの初期設定 (HTTP-01 チャレンジ用)
Let's Encryptが証明書を発行してくれるのは、「あなたが本当にそのドメインの所有者であること」を確認するためです。この確認方法の一つが「HTTP-01チャレンジ」です。
HTTP-01チャレンジの仕組みは非常にシンプルです。
- Certbotが、サーバーの特定のURL (http://<ドメイン>/.well-known/acme-challenge/<トークン>) に、ランダムな文字列(トークン)を含むファイルを作成するよう要求します。
- Let's Encryptの認証局が、インターネット経由でそのURLにアクセスし、ファイルの内容が正しいことを確認します。
- 確認が成功すれば、「このサーバーは確かにこのドメインを管理している」と判断され、証明書が発行される、という流れです。
このプロセスが正しく機能するためには、Let's Encryptの認証局が、指定されたURLにアクセスしたときに、正しくファイルに到達できるようなNginxの設定が必要です。
具体的な手順は下記の通りです。下記でnanoを起動し、ファイルを編集します。
sudo nano /etc/nginx/sites-available/<任意>.<リージョン名>.cloudapp.azure.com
ファイルに書く内容は下記の通りです。
server {
listen 80;
server_name <任意>.<リージョン名>.cloudapp.azure.com;
location /.well-known/acme-challenge/ {
root /var/www/html;
}
location / {
return 301 https://$host$request_uri;
}
}
シンボリックリンクを作成し、Nginx を再起動します。
sudo ln -s /etc/nginx/sites-available/<任意>.<リージョン名>.cloudapp.azure.com /etc/nginx/sites-enabled/
sudo systemctl restart nginx
SSL証明書の取得
下記を実行します。
sudo certbot --nginx -d <任意>.<リージョン名>.cloudapp.azure.com
プロンプトが表示されたら、メールアドレスを入力し、利用規約に同意します。
これにより、Certbot が自動的に Nginx の設定を更新し、証明書を取得してくれます。
SSL証明書自動更新の設定を確認
sudo snap services certbot
このコマンドの出力で、certbot.renew サービスが enabled になっており、timer 列に何らかのスケジュール (例: daily, 00:00,12:00) が表示されていれば、自動更新は正しく設定されています。
実際に更新が機能するかどうかをテストするには、以下のコマンドを実行します。このコマンドは、証明書の有効期限が近づいている場合にのみ実際の更新が行われます。
sudo certbot renew --dry-run
--dry-run オプションは、実際の証明書を要求せずに更新プロセスをシミュレートします。このコマンドがエラーなく完了すれば、自動更新のメカニズムは機能していると判断できます。
5. oauth2-proxyのインストールと設定
Entra ID認証とNginxを連携させるためのプロキシとして、oauth2-proxyを導入します。
1. oauth2-proxy のダウンロード
GitHubリポジトリを確認し、最新のリリースバージョンをダウンロードします。
wget https://github.com/oauth2-proxy/oauth2-proxy/releases/download/v7.10.0/oauth2-proxy-v7.10.0.linux-amd64.tar.gz
tar -xvf oauth2-proxy-v7.10.0.linux-amd64.tar.gz
sudo mv oauth2-proxy-v7.10.0.linux-amd64/oauth2-proxy /usr/local/bin/
sudo rm -rf oauth2-proxy-v7.10.0.linux-amd64 oauth2-proxy-v7.10.0.linux-amd64.tar.gz
2. oauth2-proxy の設定ファイルまたは環境変数の準備
oauth2-proxy の設定は、コマンドライン引数、環境変数、または設定ファイルで行えます。ここでは systemd サービスファイルで環境変数を使用する例を示します。
Cookie シークレットの生成
セッション Cookie の署名と暗号化に使用されるランダムな文字列を生成します。
python3 -c 'import os; print(os.urandom(16).hex())'
例: 7b3d1f... (長いランダムな文字列が出力されるのでメモしてください)
3. systemd サービスの作成
sudo nano /etc/systemd/system/oauth2-proxy.service
[Unit]
Description=OAuth2 Proxy for Entra ID
After=network.target
[Service]
ExecStart=/usr/local/bin/oauth2-proxy \
--http-address="0.0.0.0:4180" \
--upstream="http://localhost:8080" \
--provider="azure" \
--client-id="<アプリの登録:アプリケーションID>" \
--client-secret="<アプリの登録:クライアントシークレット>" \
--redirect-url="https://<任意>.<リージョン名>.cloudapp.azure.com/oauth2/callback" \
--oidc-issuer-url="https://login.microsoftonline.com/<テナントID>/v2.0" \
--cookie-secret="<Cookie シークレットの生成で作成したシークレット>" \
--cookie-domain="<任意>.<リージョン名>.cloudapp.azure.com" \
--cookie-secure=true \
--cookie-expire=24h \
--set-xauthrequest=true \
--email-domain="*" # すべての Entra ID ユーザーを許可する場合。特定のドメインのみ許可する場合は 'yourtenant.onmicrosoft.com' など。
Environment="GOMAXPROCS=1" # 必要に応じて調整
Restart=always
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=oauth2-proxy
[Install]
WantedBy=multi-user.target
注意点:
- --upstream: Web アプリケーションがリッスンしている内部アドレスとポート。
- --redirect-url: Entra ID アプリ登録で設定したリダイレクト URI と同じである必要があります。
- --cookie-domain: 認証 Cookie のドメイン。yourdomain.com または .yourdomain.com を指定します。
- --email-domain: 認証を許可するメールアドレスのドメイン。* は任意のドメインを許可します。特定の Entra ID テナント内のユーザーのみを許可する場合は、テナントのドメイン (例: yourtenant.onmicrosoft.com) を指定します。
- --oidc-issuer-url: これは Entra ID (Azure AD) の OIDC ディスカバリーエンドポイントです。common または特定のテナント ID (<Your_Tenant_ID>) を指定します。シングルテナントの場合は https://login.microsoftonline.com/< Your_Tenant_ID >/v2.0 が一般的です。
4. oauth2-proxy サービスの有効化と起動:
sudo systemctl daemon-reload
sudo systemctl enable oauth2-proxy
sudo systemctl start oauth2-proxy
sudo systemctl status oauth2-proxy
下記コマンドでログを確認し、エラーがないことを確認してください。
sudo journalctl -u oauth2-proxy -f
6. Nginxの設定更新
oauth2-proxyと連携するようにNginxの設定を更新します。
Nginxのバーチャルホスト設定ファイルの編集
既存の内容を以下の内容で上書きします。Certbot によって追加された SSL 証明書のパスはそのまま利用します。
sudo nano /etc/nginx/sites-available/<任意>.<リージョン名>.cloudapp.azure.com
server {
listen 80;
server_name <任意>.<リージョン名>.cloudapp.azure.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name <任意>.<リージョン名>.cloudapp.azure.com;
# Certbot が生成したSSL証明書とキーのパス
ssl_certificate /etc/letsencrypt/live/<任意>.<リージョン名>.cloudapp.azure.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/<任意>.<リージョン名>.cloudapp.azure.com/privkey.pem;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1h;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE';
ssl_prefer_server_ciphers on;
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
# oauth2-proxy の認証エンドポイント
location /oauth2 {
proxy_pass http://localhost:4180; # oauth2-proxy がリッスンしているアドレスとポート
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Scheme $scheme; # oauth2-proxy が HTTPS を認識できるように
proxy_set_header Cookie $http_cookie; # クッキーを転送
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_buffering off;
}
# Web アプリケーションへのリバースプロキシと認証
location / {
auth_request /oauth2/auth; # oauth2-proxy に認証を要求
error_page 401 = /oauth2/start?rd=$request_uri; # 認証失敗時に oauth2-proxy のログインページへリダイレクト
# oauth2-proxy から受け取ったユーザー情報を Web アプリケーションに転送
auth_request_set $user $upstream_http_x_auth_request_user;
auth_request_set $email $upstream_http_x_auth_request_email;
proxy_set_header X-Auth-Request-User $user;
proxy_set_header X-Auth-Request-Email $email;
# Web アプリケーションへのプロキシ設定
proxy_pass http://localhost:8080; # Web アプリケーションのポート
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
この設定によるポート別の挙動について記載します。
ポート80 (HTTP)
ポート80でアクセスすると、HTTPリクエストはHTTPS (ポート443) へと、301 Moved Permanentlyステータスコードでリダイレクトされます。要するに、HTTPS通信を強制します。ポート443 (HTTPS)
ポート443でアクセスすると、SSL通信のための必要な処理がなされ、リクエストを認証します。 その後、Webアプリケーションまたはoauth2-proxyへプロキシされます。1. URIが/oauth2で始まる場合
リクエストは、http://localhost:4180で稼働しているoauth2-proxyにプロキシされます。
2. その他のURI (/oauth2以外)
リクエストはまずoauth2-proxyによって認証され、認証が成功した場合にのみ、http://localhost:8080で稼働しているWebアプリケーションにプロキシされます。
最後に、Nginx の設定をテストし、再起動します。
sudo nginx -t
sudo systemctl restart nginx
7. 認証の確認
2.で作成した確認用Webアプリケーションにアクセスし、Entra ID認証が正しく機能することを確認します。
確認用アプリケーションの起動
source venv/bin/activate
python3 -m app
ブラウザからドメインにアクセスし、Entra IDの認証画面が表示されること、認証後、正しくアプリケーションにアクセスできることが確認できるはずです。
8. Difyの構築
いよいよDifyをデプロイします。DockerとDocker Composeを使用します。
DockerとDocker Composeのインストール
sudo apt-get update
# ca-certificates と curlのインストール
sudo apt-get install ca-certificates curl
# Dockerの公式リポジトリをシステムのソースリストに追加
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
# Docker、Docker Composeをインストール
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# 現在のユーザをdockerグループに追加
sudo usermod -aG docker $USER
# 新しく追加されたグループの変更を現在のシェルセッションに適用
newgrp docker
# Docker動作確認
docker run hello-world
# Docker Composeバージョン確認
docker compose version
Difyの公式リポジトリをクローンまたはダウンロード
git clone https://github.com/langgenius/dify.git
cd dify/docker
cp .env.example .env
Difyの設定ファイルの編集
リバースプロキシとして設定したnginxは、ポート443で受け取ったトラフィックを、ポート8080に転送するようにしたので、Difyはポート8080で待ち受ける必要があります。
.envを下記の通り書き換えます。
EXPOSE_NGINX_PORT=8080
EXPOSE_NGINX_SSL_PORT=4430 # 使わないので適当に
Docker Composeを利用したDifyの起動
docker compose up -d
あとは、Difyにアクセスしてみて完了です!
https://<任意>.<リージョン名>.cloudapp.azure.com/install
まとめ
この記事では、Azure VM上にDifyをデプロイし、Entra ID認証を組み合わせることで、セキュアなAIチャットボット開発環境を構築する手順を解説しました。これにより、社内でのDifyの試用を安全かつスムーズに進めることができます。