Skip to main content

Deployment Methods

Install Older Version

Use the --branch flag to install a specific version:
The rest of the setup is identical to installing the latest version.

Install Using ZIP Archive

For network-restricted environments or when git is unavailable:
Alternatively, download the ZIP on another device and transfer it manually. To upgrade:

Clone Fails with “Remote branch null not found”

The clone command in Deploy Dify with Docker Compose resolves the latest Dify version through the GitHub API. When that request fails (usually due to GitHub’s rate limit on unauthenticated requests), jq outputs null, and git reports fatal: Remote branch null not found in upstream origin. Clone with an explicit version instead. Find the latest version number on Dify releases, then run:
Cloning without --branch also works. The Compose file on main pins the latest released images, so you still run release builds, but the deployment files themselves (the Compose file and environment templates) track development and can drift from the tagged release.

Backup Procedures

Create Backup Before Upgrading

Always backup before upgrading to prevent data loss:
This creates a timestamped backup for easy restoration.

Reverse Proxy Setup

Login Session Drops with Split Frontend and Backend Subdomains

If you have split web and API across subdomains behind a reverse proxy (for example, app.example.com for the UI and api.example.com for the backend), authentication cookies cannot reach both hosts. Login appears to succeed, but the session is dropped on the next request. Set both variables in .env, then restart Dify:
  • COOKIE_DOMAIN: set to the shared top-level domain (e.g., example.com). Leading dots are optional.
  • NEXT_PUBLIC_COOKIE_DOMAIN: set to 1 to enable cross-subdomain cookies on the frontend.
Cookies cannot cross top-level domains, so the frontend and backend must share the same registrable domain. For full details, see environment variables.

Sign-In Emails Blocked for Everyone Behind Cloudflare or Another Proxy

Everyone is refused sign-in codes and password-reset emails at once: “Too many emails have been sent from this IP address recently. Please try again later.” From 1.18.0, this can happen on any deployment with Cloudflare, a load balancer, or another proxy in front of the bundled Nginx. Dify takes each visitor’s IP address from the bundled Nginx. Behind a proxy, Nginx sees only the proxy’s address, so all your visitors share its limits. If your proxy forwards straight to the api and web containers and bypasses the bundled Nginx, as some Cloudflare Tunnel and Nginx Proxy Manager setups do, skip the steps below. Instead, make sure that:
  • Your proxy sets X-Forwarded-For. Otherwise every visitor appears with the proxy’s address.
  • The API is reachable only through your proxy. Anyone who can reach it directly can choose the address Dify sees.
If your proxy forwards to the bundled Nginx, tell Nginx which proxy to trust:
1

Find Your Proxy's Address

Each line of the Nginx access log (docker compose logs nginx) starts with the address your proxy connects from. Take it from the log even for a proxy on the same server, rather than assuming 127.0.0.1.For Cloudflare connecting directly to Nginx, skip this step.
2

Create real-ip.conf

Create docker/nginx/conf.d/real-ip.conf for your setup. Nginx already loads every .conf file in that directory, and upgrades leave yours in place.
For a proxy that sets X-Forwarded-For:
Never trust 0.0.0.0/0, ::/0, or a network that untrusted machines share. Anyone who can reach Nginx could then choose the IP address Dify sees.
3

Reload Nginx

New lines in docker compose logs nginx should now start with visitors’ own addresses instead of the proxy’s. Visitors no longer share the blocked address, so they can request emails again right away.
Last modified on October 23, 2026