お久しぶりでございます
今回はEC2上にDify(OSS版)を構築して、それをドメイン名 + HTTPS で構築してみました
なお、あくまでインフラの観点でDifyを構築して公開するまでなので、GeminiなどのAPIキーを取得し、AIアプリケーションを作るみたいなことはしません
■環境
プラットフォーム:AWS EC2
OS:AlmaLinux9
アプリケーション:Dify Community Edition
■流れ
1. DNSのレコード登録
2. docker-composeのインストール
3. Dify のインストール
4. Difyのドメイン設定
5. DifyのHTTPS設定
6. 公開
■手順
※EC2への構築と接続は事前に済ませている想定です
1. DNSのレコード登録
今回は独自ドメインでDifyを構築してみるので、まずはDNS上でレコードを登録します
※ドメイン名はテストとして dify.quick-infra.net にしました
dify.quick-infra.net IN A 【EC2のIPアドレス】
dig +noall +answer dify.quick-infra.net
dify.quick-infra.net. 300 IN A 【EC2のIPアドレス】
→ dig でAレコードが返答されればOKです
2. docker-composeのインストール
Dify Community Edition は、既に公開されているgitのdocker-composeで稼働するので、docker-compose と git をEC2内にインストールします
まずは git をインストールします
dnf install git
次に docker-compose をインストールするので、過去のこの辺りの記事を参考します
【Docker】docker-composeを利用してVM上に独自ドメインでWebサイトを公開する
[root@ip-10-0-10-193 ~]# /usr/local/bin/docker-compose --version Docker Compose version v5.2.0
3. Dify のインストール
Difyをインストールするまでの準備が整ったので、実際に構築してみます
git clone https://github.com/langgenius/dify.git
[root@ip-10-0-10-193 ~]# ls -la total 28 dr-xr-x---. 4 root root 131 Jun 27 07:30 . dr-xr-xr-x. 18 root root 235 Aug 5 2024 .. -rw-r--r--. 1 root root 18 Feb 11 2022 .bash_logout -rw-r--r--. 1 root root 141 Feb 11 2022 .bash_profile -rw-r--r--. 1 root root 429 Feb 11 2022 .bashrc -rw-r--r--. 1 root root 100 Feb 11 2022 .cshrc drwxr-xr-x. 22 root root 4096 Jun 27 07:30 dify -rw-------. 1 root root 20 Jun 27 07:28 .lesshst drwx------. 2 root root 29 Jun 27 07:02 .ssh -rw-r--r--. 1 root root 129 Feb 11 2022 .tcshrc
→カレントディレクトリ配下に dify ディレクトリが存在することを確認する
そして、.env ファイルを作成します
cd dify/docker
cp .env.example .env
それでは、一旦起動してみます
docker-compose up -d
docker container ps
[root@ip-10-0-10-193 docker]# docker container ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 1e2b0b500ea5 nginx:latest "sh -c 'cp /docker-e…" About a minute ago Up About a minute 0.0.0.0:80->80/tcp, [::]:80->80/tcp, 0.0.0.0:443->443/tcp, [::]:443->443/tcp docker-nginx-1 c799862267e8 langgenius/dify-api:1.15.0 "/bin/bash /entrypoi…" About a minute ago Up About a minute 5001/tcp docker-worker_beat-1 a42551fcafd5 langgenius/dify-api:1.15.0 "/bin/bash /entrypoi…" About a minute ago Up About a minute (health: starting) 5001/tcp docker-api-1 fb2f13e992fd langgenius/dify-api:1.15.0 "/bin/bash /entrypoi…" About a minute ago Up About a minute 5001/tcp docker-api_websocket-1 06c7e6a6d868 langgenius/dify-api:1.15.0 "/bin/bash /entrypoi…" About a minute ago Up About a minute 5001/tcp docker-worker-1 41a2f7cdc86b langgenius/dify-plugin-daemon:0.6.3-local "/usr/bin/tini -g --…" About a minute ago Up About a minute 0.0.0.0:5003->5003/tcp, [::]:5003->5003/tcp docker-plugin_daemon-1 f0bdd837cc74 postgres:15-alpine "docker-entrypoint.s…" About a minute ago Up About a minute (healthy) 5432/tcp docker-db_postgres-1 b92b18e4ee97 langgenius/dify-web:1.15.0 "/bin/sh ./entrypoin…" About a minute ago Up About a minute 3000/tcp docker-web-1 54b5f7c122ae redis:6-alpine "docker-entrypoint.s…" About a minute ago Up About a minute (healthy) 6379/tcp docker-redis-1 0ea71c4b8b9a langgenius/dify-sandbox:0.2.15 "/entrypoint.sh" About a minute ago Up About a minute (healthy) docker-sandbox-1 4ebceab1b5a0 semitechnologies/weaviate:1.27.0 "/bin/weaviate --hos…" About a minute ago Up About a minute docker-weaviate-1 2365abf75998 ubuntu/squid:latest "sh -c 'cp /docker-e…" About a minute ago Up About a minute 3128/tcp docker-ssrf_proxy-1
→ 初回起動は5分ほどイメージの取得に時間がかかりましたが、各コンテナが問題なく起動したことを確認しました
起動が完了したら一度ブラウザからec2のIPアドレスを入力し、Difyのセットアップ画面が表示されることを確認します
→ 一旦大丈夫そうですね
4. Difyの独自ドメイン設定
先ほどEC2のパブリックIPであれば、ブラウザからセットアップ画面が表示されることを確認したので、次は独自ドメインでアクセスできるようにします
docker-compose.ymlを確認したところ、Web側は nginx を利用しているので、nginxのconfファイルでドメインを設定します
dify/docker/nginx/docker-entrypoint.sh を確認したところ、envsubst を利用して、環境変数を読み込んだconfファイルを作成するようにしていました
#!/bin/bash
HTTPS_CONFIG=''
if [ "${NGINX_HTTPS_ENABLED}" = "true" ]; then
# Check if the certificate and key files for the specified domain exist
if [ -n "${CERTBOT_DOMAIN}" ] && \
[ -f "/etc/letsencrypt/live/${CERTBOT_DOMAIN}/${NGINX_SSL_CERT_FILENAME}" ] && \
[ -f "/etc/letsencrypt/live/${CERTBOT_DOMAIN}/${NGINX_SSL_CERT_KEY_FILENAME}" ]; then
SSL_CERTIFICATE_PATH="/etc/letsencrypt/live/${CERTBOT_DOMAIN}/${NGINX_SSL_CERT_FILENAME}"
SSL_CERTIFICATE_KEY_PATH="/etc/letsencrypt/live/${CERTBOT_DOMAIN}/${NGINX_SSL_CERT_KEY_FILENAME}"
else
SSL_CERTIFICATE_PATH="/etc/ssl/${NGINX_SSL_CERT_FILENAME}"
SSL_CERTIFICATE_KEY_PATH="/etc/ssl/${NGINX_SSL_CERT_KEY_FILENAME}"
fi
export SSL_CERTIFICATE_PATH
export SSL_CERTIFICATE_KEY_PATH
# set the HTTPS_CONFIG environment variable to the content of the https.conf.template
HTTPS_CONFIG=$(envsubst < /etc/nginx/https.conf.template)
export HTTPS_CONFIG
# Substitute the HTTPS_CONFIG in the default.conf.template with content from https.conf.template
envsubst '${HTTPS_CONFIG}' < /etc/nginx/conf.d/default.conf.template > /etc/nginx/conf.d/default.conf
fi
export HTTPS_CONFIG
if [ "${NGINX_ENABLE_CERTBOT_CHALLENGE}" = "true" ]; then
ACME_CHALLENGE_LOCATION='location /.well-known/acme-challenge/ { root /var/www/html; }'
else
ACME_CHALLENGE_LOCATION=''
fi
export ACME_CHALLENGE_LOCATION
env_vars=$(printenv | cut -d= -f1 | sed 's/^/$/g' | paste -sd, -)
envsubst "$env_vars" < /etc/nginx/nginx.conf.template > /etc/nginx/nginx.conf
envsubst "$env_vars" < /etc/nginx/proxy.conf.template > /etc/nginx/proxy.conf
envsubst "$env_vars" < /etc/nginx/conf.d/default.conf.template > /etc/nginx/conf.d/default.conf ★
# Start Nginx using the default entrypoint
exec nginx -g 'daemon off;'
また、dify/docker/nginx/conf.d/default.conf.template を確認したところ、server_name が ${NGINX_SERVER_NAME} の変数を読み込むようになっていました
# Please do not directly edit this file. Instead, modify the .env variables related to NGINX configuration.
server {
listen ${NGINX_PORT};
server_name ${NGINX_SERVER_NAME};
location /console/api {
proxy_pass http://api:5001;
include proxy.conf;
}
location /api {
proxy_pass http://api:5001;
include proxy.conf;
}
~省略~
これらのことより docker-compose .yml 上の nginxサービスにすでに記載されている ${NGINX_SERVER_NAME:-_} が存在していました
~省略~
# used for reverse proxying the API service and Web service.
nginx:
image: nginx:latest
restart: always
volumes:
- ./nginx/nginx.conf.template:/etc/nginx/nginx.conf.template
- ./nginx/proxy.conf.template:/etc/nginx/proxy.conf.template
- ./nginx/https.conf.template:/etc/nginx/https.conf.template
- ./nginx/conf.d:/etc/nginx/conf.d
- ./nginx/docker-entrypoint.sh:/docker-entrypoint-mount.sh
- ./nginx/ssl:/etc/ssl # cert dir (legacy)
- ./volumes/certbot/conf/live:/etc/letsencrypt/live # cert dir (with certbot container)
- ./volumes/certbot/conf:/etc/letsencrypt
- ./volumes/certbot/www:/var/www/html
entrypoint:
[
"sh",
"-c",
"cp /docker-entrypoint-mount.sh /docker-entrypoint.sh && sed -i 's/\r$$//' /docker-entrypoint.sh && chmod +x /docker-entrypoint.sh && /docker-entrypoint.sh",
]
environment:
NGINX_SERVER_NAME: ${NGINX_SERVER_NAME:-_} ★
NGINX_HTTPS_ENABLED: ${NGINX_HTTPS_ENABLED:-false}
~省略~
そのため、dify/docker/.env 内の NGINX_SERVER_NAME に dify.quick-infra.net を設定してみます
~省略~ # Nginx and Docker Compose NGINX_SERVER_NAME=_ NGINX_HTTPS_ENABLED=false NGINX_PORT=80 ~省略~
↓
# Nginx and Docker Compose NGINX_SERVER_NAME=dify.quick-infra.net NGINX_HTTPS_ENABLED=false NGINX_PORT=80 NGINX_SSL_PORT=443 NGINX_SSL_CERT_FILENAME=dify.crt
コンテナを再作成します
docker-compose down
docker-compose up -d
コンテナ内のconfファイル上で設定されていることを確認します
[root@ip-10-0-10-193 conf.d]# docker exec -i -t 9796615058e3 cat /etc/nginx/conf.d/default.conf | grep server_name
server_name dify.quick-infra.net;
→ Nginxコンテナ内のdefault.confで dify.quick-infra.net が設定されていることを確認する
そして、ブラウザ上から接続できることを確認します
→ 最初に設定したFQDNで接続できることを確認しました
5. DifyのHTTPS設定
それでは大本命のHTTPS化を設定してみます
なお、Dify ではLet’s Encrypt を利用したSSL化に対応しているので、こちらで実現してみます
まずはSSL証明書を取得するため、dify/docker/.env 内で下記個所を書き換えます
※基本的には dify/docker/certbot/README.md の内容に沿って対応します
※下記は値を修正 NGINX_SSL_CERT_FILENAME=fullchain.pem NGINX_SSL_CERT_KEY_FILENAME=privkey.pem NGINX_ENABLE_CERTBOT_CHALLENGE=true ※下記は追記する CERTBOT_DOMAIN=dify.quick-infra.net CERTBOT_EMAIL=example@dify.quick-infra.net
コンテナの削除
docker-compose down
ネットワークの削除
docker network prune
certbotのコンテナ起動
docker compose --profile certbot up --force-recreate -d
証明書発行用スクリプトの実行
docker compose exec -it certbot /bin/sh /update-cert.sh
→下記のように発行が成功すればOKです
[root@ip-10-0-10-193 docker]# docker compose exec -it certbot /bin/sh /update-cert.sh Certificate does not exist. Obtaining a new certificate... Saving debug log to /var/log/letsencrypt/letsencrypt.log Account registered. Requesting a certificate for dify.quick-infra.net Successfully received certificate. Certificate is saved at: /etc/letsencrypt/live/dify.quick-infra.net/fullchain.pem Key is saved at: /etc/letsencrypt/live/dify.quick-infra.net/privkey.pem This certificate expires on 2026-09-25. These files will be updated when the certificate renews. NEXT STEPS: - The certificate will need to be renewed before it expires. Certbot can automatically renew the certificate in the background, but you may need to take steps to enable that functionality. See https://certbot.org/renewal-setup for instructions. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - If you like Certbot, please consider supporting our work by: * Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate * Donating to EFF: https://eff.org/donate-le - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Certificate operation successful Please ensure to reload Nginx to apply any certificate changes.
次にNginxをHTTPS化します
先ほどと同じように dify/docker/.env 内で下記個所を末尾に追記します
NGINX_HTTPS_ENABLED=true
Nginxコンテナのみを再作成します
sudo docker compose --profile certbot up -d --no-deps --force-recreate nginx
→下記のようにNginxコンテナが起動していればOKです
[root@ip-10-0-10-193 docker]# docker container ps | grep nginx 182762839e2c nginx:latest "sh -c 'cp /docker-e…" 26 seconds ago Restarting (1) 4 seconds ago docker-nginx-1
6. 公開
最後にブラウザ上から 独自ドメイン名 + HTTPS で接続可能か確認してみます
ホーム画面
→ 独自ドメイン名 + HTTPS でコンテンツが公開されたことを確認しました
★トラブルシューティング
・NginxをHTTPS化直後ブラウザから確認したところ、ブラウザ上でエラーが出ました
その際、Nginxコンテナにて下記エラーが出力されていたので、一旦 docker-compose down と up -d を実施し、ブラウザ上からHTTPSで表示されることを確認しました
なお、根本対応としては、default.conf.template 上で当該箇所のコメントアウトなどを実施する必要があると思います
2026/06/27 09:16:33 [emerg] 9#9: host not found in upstream "plugin_daemon" in /etc/nginx/conf.d/default.conf:48 nginx: [emerg] host not found in upstream "plugin_daemon" in /etc/nginx/conf.d/default.conf:48
■最後に
いかがでしたでしょうか
始めてセルフホストのサーバーで Difyを構築してみましたが、それなりにうまくいった気がします
ただ、正直な所感として、独自ドメインやSSL化を実施するには、それなりにインフラの知識とDocker周りの知識が必要であり、公式の手順に則った場合でもうまくいかないことがあったので、
エンジニアの方以外が基盤を構築するとなると少し躓きそうかなとも感じました。
より実運用に即して、Let’s Encrypt のcronを用いた自動証明書更新や特定IPからのみ接続できるようにするようなことを試してみたいと思います。



