【Dify】Dify(OSS版)をEC2上に独自ドメインとHTTPSで公開してみた

お久しぶりでございます

今回は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からのみ接続できるようにするようなことを試してみたいと思います。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA