DifyをVPSにセルフホストする手順|初期設定で開くポートを閉じてHTTPS公開

PRこの記事にはアフィリエイト広告が含まれます。紹介したサービスに申し込まれると、運営者が報酬を受け取ることがあります。評価や順位は報酬で変えていません。広告表記について

Dify は、LLM を使ったチャットボットやワークフローを画面上で組めるツールです。公式の Docker Compose を使えば数コマンドで起動できますが、初期設定のまま VPS で動かすと、インターネットに開いてしまうポートがあります。この記事では、公式の手順で構築したうえで、そのポートを閉じて Caddy で HTTPS 公開するところまでを解説します。

手順は 2026年10月21日 時点の最新版である Dify 1.17.1 で確かめました。

必要なスペック

公式ドキュメントの要件は CPU 2コア以上、メモリ 4GiB 以上です。手元で測ったところ、起動して何もしていない状態で約1.93GiB、再起動の直後には合計で約2.13GiB を使いました。2GB のプランでは足りません。

Dify 1.17.1 のメモリ使用量(再起動直後のピーク)合計 2.13 GiB。半分以上の余裕が残るのは 8GB のプランからです。OS や Docker 自体が使う分は含みません。
アプリ本体: 1.74 GiBデータベースとキャッシュ: 52 MiBベクトルDB: 95 MiBサンドボックス・プロキシ・プラグイン: 253 MiB2GB 不足4GB 余裕47%8GB 余裕73%合計 2.13 GiB
  • アプリ本体1.74 GiB
  • データベースとキャッシュ52 MiB
  • ベクトルDB95 MiB
  • サンドボックス・プロキシ・プラグイン253 MiB
コンテナ別の内訳を表で見る
グループコンテナメモリ
アプリ本体api401 MiB
アプリ本体api_websocket385 MiB
アプリ本体worker401 MiB
アプリ本体worker_beat378 MiB
アプリ本体web93 MiB
アプリ本体agent_backend126 MiB
データベースとキャッシュdb_postgres40 MiB
データベースとキャッシュredis12 MiB
ベクトルDBweaviate95 MiB
サンドボックス・プロキシ・プラグインsandbox55 MiB
サンドボックス・プロキシ・プラグインlocal_sandbox19 MiB
サンドボックス・プロキシ・プラグインplugin_daemon76 MiB
サンドボックス・プロキシ・プラグインssrf_proxy25 MiB
サンドボックス・プロキシ・プラグインagent_ssrf_proxy55 MiB
サンドボックス・プロキシ・プラグインnginx24 MiB

測定日 。macOS 上の Docker(OrbStack、arm64、割り当て 16GB)。docker stats で60回(3秒間隔)取得したコンテナごとの最大値の合計。docker compose restart の直後から測定。コンテナごとにピークの時刻は異なるため、合計は同時に使う量の上限の目安。

測り方とコンテナごとの内訳は、Dify に必要なメモリは何GBかで詳しく解説しています。

手順1:VPS に Docker を入れる

Docker のインストール、ファイアウォール、DNS の設定は、VPSにDocker ComposeでアプリをHTTPS公開する基本手順と同じです。公式ドキュメントは Docker Compose 2.24.0 以上を求めています。docker compose version で確認してください。

手順2:公式の手順で Dify を起動する

公式の手順は、最新のリリースのタグを指定してリポジトリを取得する方法です。この記事では、確かめた版を明示するためにタグを直接書いています。

git clone --branch 1.17.1 https://github.com/langgenius/dify.git
cd dify/docker
cp .env.example .env
docker compose up -d
docker compose ps

docker compose ps を実行すると、既定の設定(ベクトルDB は Weaviate、DB は PostgreSQL)では 16個のコンテナが並びます。そのうち init_permissions は初期設定用で、処理が終わると停止するのが正常です。

役割 コンテナ
アプリ本体 api、api_websocket、worker、worker_beat、web、agent_backend
データベースとキャッシュ db_postgres、redis
ベクトルDB weaviate
サンドボックス・プロキシ・プラグイン sandbox、local_sandbox、plugin_daemon、ssrf_proxy、agent_ssrf_proxy、nginx
初期設定(終了する) init_permissions

手順3:初期設定のままでは開いているポートを閉じる

起動した状態で、どのポートがサーバーの外に公開されているかを確認します。

docker compose ps --format '{{.Service}}\t{{.Ports}}'

手元の Dify 1.17.1 では、2つのサービスの合わせて3つのポートが、すべての接続元(0.0.0.0)に公開されていました。

サービス ポート 用途
nginx 80、443 Dify の画面と API
plugin_daemon 5003 プラグインのリモートデバッグ

ufw で塞いでも届きます

Docker 公式ドキュメントによると、Docker で公開したポートへの通信は ufw のルールが適用される前に振り分けられます。ufw で 5003番を許可していなくても、外から届く状態になります。プラグインを開発しないなら、このポートを公開する必要はありません。

.env の EXPOSE_PLUGIN_DEBUGGING_PORT を書き換えて閉じたくなりますが、手元の 1.17.1 の docker-compose.yaml では、同じ変数がプラグインのリモートインストール用ポートの設定にも使われていました。127.0.0.1:5003 のような値を入れると、そちらにも同じ値が渡ってしまいます。

そこで、公式のファイルは書き換えず、上書き用のファイルでポートの公開だけを外します。dify/docker に、次の内容で docker-compose.override.yaml を作ります。

services:
  nginx:
    ports: !reset []
  plugin_daemon:
    ports: !reset []

!reset は、元のファイルで設定された値を取り消す Docker Compose の書き方です。このファイル名は docker compose が自動で読み込むため、起動のコマンドは変わりません。

docker compose up -d
docker compose ps --format '{{.Service}}\t{{.Ports}}'

これで、サーバーの外に公開されるポートはなくなります。nginx の 80番と443番も閉じますが、次の手順で Caddy を Dify のネットワークに参加させるため問題ありません。

手順4:Caddy を前に置いて HTTPS で公開する

Dify とは別のディレクトリ(例:~/caddy)に、次のファイルを作ります。Caddy を Dify の Compose が作るネットワーク(dify/docker で起動した場合は docker_default)に参加させ、Dify の nginx へ転送します。

compose.yaml:

services:
  caddy:
    image: caddy:2.11.7
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
      - "443:443/udp"
    environment:
      - DIFY_DOMAIN=${DIFY_DOMAIN}
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy_data:/data
      - caddy_config:/config
    networks:
      - dify

networks:
  dify:
    external: true
    name: docker_default

volumes:
  caddy_data:
  caddy_config:

Caddyfile:

{$DIFY_DOMAIN} {
	reverse_proxy nginx:80
}

.env:

DIFY_DOMAIN=dify.example.com

ネットワーク名は docker network ls で確認できます。Dify を別の名前のディレクトリで起動した場合は、「ディレクトリ名_default」になります。

docker compose up -d

ブラウザで https://dify.example.com/install を開き、管理者アカウントを作成します。

手元で確かめた結果

ドメインの代わりに dify.localhost と Caddy の内部証明書を使って、同じ構成を動かしました。

確認したこと 結果
Caddy 経由の HTTPS で Dify の画面が開くか ログイン画面が日本語で表示された
Caddy 経由で API が応答するか /console/api/setup がステータス 200 を返した
HTTP で開いたときの動き HTTPS へ転送された(ステータス 308)
ホストから 80番、5003番に直接届かないか どちらも接続できなかった

アップデートするときの注意

公式ドキュメントは、アップデートの手順は版によって異なるため、リリースページで対象の版の案内を確認するよう求めています。あわせて、次の2点を挙げています。

  • 新しい版の .env.example と手元の .env を比べ、追加や変更された変数を反映する
  • docker-compose.yaml を書き換えていた場合は、古いファイルを使い続けず、新しい版のファイルに変更を入れ直す(新しい版で必要なサービスが増えることがあるため)

実際に 1.16.1 から 1.18.0 まで上げた手順と注意点は、Dify のアップデート手順にまとめています。

この記事の方法なら、公式の docker-compose.yaml は書き換えていません。アップデートで取り込み直す必要があるのは、上書き用の docker-compose.override.yaml だけです。ただし、新しい版でポートを公開するサービスが増えていないかは、アップデートのたびに docker compose ps で確認してください。

出典

  1. Deploy Dify with Docker Compose(Dify 公式ドキュメント)(に確認)
  2. Dify のリリース一覧(GitHub)(に確認)
  3. Merge Compose files(Docker 公式)(に確認)
  4. Packet filtering and firewalls(Docker 公式)(に確認)