Dify is an open-source platform for building LLM (large language model)–based applications. It offers a visual workflow engine, prompt/agent support, RAG (retrieval augmented generation) pipelines, model management, observability, and APIs. The idea is to let users go from prototype to production in a unified environment, while retaining full control over infrastructure and data (unlike proprietary hosted LLM platforms).
Because Dify is a multi-service architecture (API, web frontend, worker, storage, database, vector DB, caching, etc.), self-hosting involves coordinating all of these components. The “self-hosted” version is officially supported (via Docker Compose) in the Dify docs.
In this guide, I walk you through deploying Dify on a DigitalOcean Droplet (or equivalent) with production considerations: DNS, TLS, backups, external databases, scaling, and updates.
Before diving in, let’s clarify some design decisions and trade-offs you’ll face:
- Single VM (Droplet) vs multi-node. For simplicity at first, you can deploy everything (app, DB, cache, vector DB, etc.) on one Droplet. But for reliability or performance you might later separate components (e.g. external PostgreSQL, Redis, object storage).
- Use of external managed DB vs self-hosted DB. Offloading your database and vector store to a managed service can help with backups, high availability, upgrades, and durability.
- TLS / HTTPS termination. You’ll want TLS via Let’s Encrypt or other CA. You may run a reverse proxy (nginx, Caddy) fronting the Dify stack.
- Resource sizing. Dify is nontrivial in resource needs—CPU, RAM, I/O. Start moderate and scale.
- Upgradability & state management. Store state persistently (e.g. volumes). Make sure upgrades are safe.
- Monitoring, logging, and backups. Plan for metrics, log retention, snapshots, and restoration.
With those in mind, I’ll show you how to deploy an initial production-capable instance and then cover enhancements.
Step 1: Provision your DigitalOcean Droplet
- In your DigitalOcean dashboard, create a new Droplet. Choose a region close to your users.
- Pick an OS image—Ubuntu 22.04 LTS is a safe choice.
- Choose a size: for experimentation, 2 vCPUs + 8 GB RAM is a reasonable minimum; for heavier use, go up (e.g. 4 vCPU, 16 GB, or more).
- Add SSH keys for secure login (don’t use only password).
- Ensure you enable IPv6 if needed and allow internet access.
- (Optional) Add block storage volumes if you want data separation (e.g. for object store).
- Once created, note the public IP or floating IP of your server.
At this point, you should be able to SSH into the new server:
ssh root@<your_droplet_ip>
Step 2: Prepare the server environment
On the droplet:
- Update packages:
apt update && apt upgrade -y
- Install prerequisites:
apt install -y curl git wget
- Install Docker and Docker Compose. You can follow official Docker instructions, or:
apt install -y docker.io
systemctl enable --now docker
# Install docker-compose plugin
apt install -y docker-compose
- Create a non-root user (e.g.
difyadmin
) and give it Docker permissions:
adduser difyadmin
usermod -aG docker difyadmin
Then switch to that user:
su - difyadmin
- (Optional) Install fail2ban, UFW firewall:
apt install -y ufw
ufw allow OpenSSH
ufw allow 80,443
ufw enable
Step 3: Acquire Dify’s self-hosted Docker setup
Dify’s documentation provides a Docker Compose approach.
Clone the repo (or the self-hosted template):
git clone https://github.com/langgenius/dify.git
cd dify
Inside you’ll find a docker-compose.yml
(or similar) and environment variable files (e.g. .env
, docker/.env.example
). You’ll need to adjust those.
Key things to configure:
- Postgres connection details
- Redis connection
- Storage (object store / MinIO) config
- Domain names / hostnames
- TLS / HTTPS (if internal, or via reverse proxy)
- Secrets, API keys, JWT keys
Edit the .env
or config
file:
POSTGRES_USER=…
POSTGRES_PASSWORD=…
POSTGRES_DB=…
REDIS_HOST=redis
REDIS_PORT=6379
MINIO_ACCESS_KEY=…
MINIO_SECRET_KEY=…
# Domain for frontend
HOST_DOMAIN=dropletdrift.com
# etc.
Make sure the container services like api
, worker
, web
, plugin-daemon
, etc., refer to these variables.
Step 4: DNS setup and reverse proxy / TLS
You’ll want your Dify frontend accessible at a domain with TLS. Suppose your domain is dify.dropletdrift.com
.
- In your DNS provider, create an
A
record:
dify.dropletdrift.com → your_droplet_ip
- On the server, either:
- Use a reverse proxy (nginx, Caddy) in front of the Docker stack to handle TLS, forwarding to internal HTTP;
- Or let one container (or a built-in proxy) handle TLS/Let’s Encrypt.
A common pattern:
- Run nginx on host or in a container listening on ports 80/443
- It proxies to
web:80
(Dify’s frontend) andapi:8000
, etc. - Use Certbot (Let’s Encrypt) or nginx plugin to auto-renew.
Example nginx config (on host):
server {
listen 80;
server_name dify.dropletdrift.com;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl http2;
server_name dify.dropletdrift.com;
ssl_certificate /etc/letsencrypt/live/dify.dropletdrift.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/dify.dropletdrift.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8000; # or web container
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /api/ {
proxy_pass http://127.0.0.1:8000/api/; # or api container
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Then run Certbot:
apt install -y certbot python3-certbot-nginx
certbot --nginx -d dify.dropletdrift.com
You may need to reload nginx and Docker so traffic flows correctly.
Step 5: Launch Docker Compose
From the Dify repo directory:
docker compose up -d
(or docker-compose up -d
depending on version)
This will spin up all services: Postgres, Redis, MinIO, API, web, worker, plugin daemon, etc. Check logs:
docker compose logs -f
Watch until all containers are healthy and “web” is serving.
You should be able to browse to https://dify.dropletdrift.com and see the login / onboarding screen.
On first launch, you’ll likely have an auto-generated admin password (exposed via environment variable or logs). Use that to log in and set up your first workspace and user.
Step 6: Externalizing the database and vector store (Optional but recommended)
For production resilience, it’s better to separate your persistent data from the app.
You can:
- Use DigitalOcean Managed Database (such as PostgreSQL)
- Use an external Redis instance
- Use separate block storage or object storage for MinIO
- Use PGVector in external Postgres for vector embeddings
Update your .env
/ config to point to those external resources, adjusting hostnames, credentials, ports, SSL/TLS settings. Then restart docker compose
.
This gives you the flexibility to upgrade or rebuild the Dify app container without risking data.
Step 7: Backups and monitoring
- Schedule nightly backups (database dumps, object storage snapshots). Use
pg_dump
,aws s3 sync
style commands, or DigitalOcean snapshots. - Monitor disk usage, memory, CPU, container liveness. Tools like Prometheus + Grafana can be integrated.
- Set up alerting on container failure, high load, and low free space.
- Test restores periodically.
Step 8: Upgrading and maintenance
When a new Dify version is released:
- Pull the latest image tags in your Docker Compose file.
- Backup your database and storage.
- Stop containers:
docker compose down
(ordown --volumes
if needed carefully). - Run
docker compose pull
, thendocker compose up -d
. - Check logs, test functionality.
Be cautious about migrations or breaking changes in newer Dify versions.
Caveats, Tips & Best Practices
- Resource constraints: If memory or CPU is insufficient, containers may crash; monitor and scale up.
- Network / firewall: Ensure internal container ports are reachable only from the proxy, not exposed publicly.
- Container restarts: Use restart policies (
restart: always
) in Compose to auto-recover. - SSL renewal: Ensure Certbot auto renewal and nginx reload is scheduled (cron or systemd timers).
- Secure secrets: Don’t store secrets in plaintext
.env
inside Git; use environment management or secret stores. - High availability: In a more mature setup, run multiple API/worker replicas, a standby PostgreSQL, Redis clustering.
- Logging and retention: Persist logs off the container, use log rotation.
- Domain & branding: Note that the self-hosted community edition may impose constraints on branding (e.g. it may not allow removing “powered by Dify”) per their licensing.
You now have a working, self-hosted Dify instance running on DigitalOcean. From here, you can:
- Configure model providers (OpenAI, local LLM inference, etc.)
- Plug in document ingestion / knowledge workflows
- Scale out or split components
- Harden security (e.g. WAF, stricter firewall rules)
- Automate deployments (CI/CD)
- Monitor and iterate