SSD Nodes Learn Hosting plans →
Guides Matt ConnorBy Matt Connor · Updated 2026-08-28

Self-host Dify on a VPS with Docker Compose

Six containers, so budget 4 GB of RAM. Replace every secret in .env before you boot it, then create the admin account at /install before a stranger does.

What Dify is, and what you are signing up to run

Dify is a self-hostable platform for building applications on top of large language models. You get a web interface for designing chat apps, agents, and retrieval pipelines, an API to call them from your own code, and one place to manage prompts, datasets, and model keys. It is the kind of tool a small team stands up so everyone builds on one shared private base, rather than scattering API keys across scripts. If words like agent, tool call, and retrieval pipeline are still fuzzy, working through those concepts from scratch first will make Dify's builder screens read as familiar controls rather than a wall of unlabelled switches.

Running it yourself means running several moving parts. Dify ships as a set of Docker containers: an API server, a background worker, a web frontend, a Postgres database, a Redis cache, and a vector database, all wired together with Docker Compose. That is more than a single binary, but Compose handles the wiring, and a VPS with a couple of gigabytes of RAM to spare runs it comfortably. If that VPS is also going to run something else, size it from measured numbers rather than advertised ones, because the real RAM floors of PhotoPrism and Immich sit well above their published minimums, and a photo server sharing the box will starve Dify's database and vector store first. CPU contention bites the same way: a Jellyfin library reskinned as a 90s video store costs almost nothing to serve while it is just browsing artwork, but the moment someone starts a transcode, Dify's worker queues behind it. The consolation is that Dify's container count is fixed however many apps you build on it, which is a gentler shape of bill than OpenBot, where every AI coworker gets its own container and its own browser and each new hire pushes the memory floor up again.

Because Dify holds your model API keys and, often, private documents you have loaded for retrieval, treat the box it runs on as sensitive from the first minute. This guide installs it, then hardens it the way you would harden any service that holds secrets.

Prerequisites

You need a VPS running Ubuntu 24.04 with Docker and the Docker Compose plugin installed, and a user with sudo or membership of the docker group. If Docker is new to you, the basics of Docker Compose on a VPS covers the install and the core commands this guide assumes. A domain name pointed at the server is worth having, because you will want TLS in front of Dify rather than a bare IP address.

Step 1: Get Dify and its Compose files

Dify keeps its Docker setup in the main repository. Clone it and move into the docker directory:

git clone https://github.com/langgenius/dify.git
cd dify/docker
cp .env.example .env

The .env file is the whole configuration. Read it before you start anything. The values that matter first are the ones that set passwords and secrets: SECRET_KEY, the Postgres password, and the Redis password. The example file ships with placeholder values, and leaving them as shipped is the single most common way a self-hosted Dify ends up compromised. Generate a real secret key:

openssl rand -base64 42

Paste that into SECRET_KEY, and set a strong, unique value for every password field in the file.

Step 2: Start it

Bring the stack up:

docker compose up -d

The first run pulls several images and initialises the database, so give it a minute. Check that the containers are healthy:

docker compose ps

Every service should read running. Dify serves its web interface through a bundled nginx container on port 80 by default. On your first visit to http://YOUR_SERVER/install you create the admin account. Do that immediately, before anything else can reach the port, because until that account exists anyone who loads the page can claim it and own your instance.

Step 3: Do not expose it raw. Put TLS and a firewall in front

Here is where most quick installs stop and most incidents begin. Dify's own nginx listens on port 80, in the clear, on every interface. You do not want your admin login and your model keys travelling over plain HTTP, and you do not want the internal services reachable from outside.

Lock the box down with a default-deny firewall that allows only SSH and web traffic:

sudo ufw default deny incoming
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable

Remember that a firewall which only covers IPv4 can leave the same ports open on IPv6, the IPv6 firewall gap that catches so many self-hosters. Confirm both stacks are filtered.

For TLS, the cleanest path is to bind Dify's web port to loopback and run a reverse proxy with a Let's Encrypt certificate in front, so the only thing on the public internet is the proxy speaking HTTPS. Dify's .env lets you change the exposed port; set it to bind on 127.0.0.1 and point your proxy at that. The agent-hardening ideas in running an AI agent safely on a VPS apply here too: keep the moving parts on loopback, expose only what must be public, and let one hardened front door speak TLS. Where a tool's interface is for you alone and never needs a certificate at all, skip the proxy and reach it over an SSH tunnel, the way self-hosting the open-kritt security scanner keeps its dashboard bound to loopback and forwarded to your laptop instead of published. If a whole team needs Dify but the public internet does not, an overlay network scales that idea past one laptop: advertising the server's private subnet to your tailnet lets every approved device reach the builder on a private address while the firewall stays shut to everything but SSH. If you administer this box through a coding agent rather than by hand, settle how much it may do unsupervised before you hand it the keys, because the permission mode you leave Claude Code in decides whether it stops to ask before rewriting .env or restarting the stack. If you end up with one session tailing container logs while another edits the proxy config, those two sessions can pass text to each other on the same box, which beats copying output between terminals every time you restart the stack.

Step 4: Keep it patched

Dify moves quickly, and updates include security fixes. Updating is a pull and a restart from the docker directory:

git pull
docker compose pull
docker compose up -d

Read the release notes before a major version jump, because Dify occasionally changes the .env schema between releases, and a new variable you have not set can stop a container from starting.

Step 5: Back up what you cannot regenerate

Two things on a Dify box are irreplaceable: the Postgres database, which holds your apps, users, and settings, and the volume that stores uploaded documents and the vector index. Both live under Docker volumes in the docker directory. Snapshot them on a schedule, and copy the snapshots off the server. Those snapshots carry every model key and uploaded document in a single file, so encrypt them before they leave the box, for the same reason a Vaultwarden backup turns out to be the weak point of an otherwise solid password server. A model API key can be reissued; the app you spent a week building cannot. The same reasoning governs any agent whose state has to outlive the machine it runs on: keeping KiroCrew running as an always-on container comes down to snapshotting the memory and schedules that would otherwise disappear at the next reboot.

When you want the agents you build here to reach past your own datasets and search the live web, pointing them at a self-hosted SearXNG instance keeps the query stream on hardware you control, though it is worth reading up on the prompt injection surface that opens before you switch it on. For a more autonomous, code-running agent, see self-hosting Agent Zero, and building your own AI agent on a VPS covers the foundations beneath all of them.

FAQ

What are the system requirements to self-host Dify?

Dify runs as a Docker Compose stack of about half a dozen containers, so plan for a VPS with at least 2 GB of RAM free, ideally 4 GB, plus a couple of CPU cores and enough disk for your uploaded documents and the vector index. The memory pressure comes from the database and vector store, not from Dify itself.

Is it safe to expose Dify directly on port 80?

No. Dify's bundled web server listens on plain HTTP, and it fronts your admin login and your model API keys. Put a reverse proxy with a Let's Encrypt certificate in front, bind Dify's own port to loopback, and let only the HTTPS proxy face the internet. Pair that with a default-deny firewall that covers both IPv4 and IPv6.

How do I update a self-hosted Dify?

From the docker directory, run git pull, then docker compose pull and docker compose up -d to fetch new images and restart. Read the release notes first, because Dify sometimes adds new .env variables between versions, and a missing one can stop a container from coming up.

What is the first thing to do after installing Dify?

Visit /install and create the admin account immediately. Until that account exists, anyone who can reach the page can claim it. Set it up the moment the containers are healthy, and before you open the firewall to the world.