Installing Dify on Ubuntu 24 with Nginx


This guide provides a complete walkthrough for deploying Dify, the open-source AI application development platform, on Ubuntu 24 with Nginx as a reverse proxy. The setup includes SSL/TLS configuration, security hardening, and production-ready optimizations for 2024/2025.
Prerequisites and system requirements
Before beginning installation, ensure your Ubuntu 24.04 LTS server meets these specifications. Dify requires minimum 4 GB RAM and 2 CPU cores, though production environments should have 16 GB RAM and 4+ cores for optimal performance. Allocate at least 50 GB storage for Docker images, databases, and user data. Your server needs a stable internet connection for accessing external AI model APIs.
The complete dependency stack includes Docker Engine (version 19.03+), Docker Compose V2, Git for repository cloning, Nginx for reverse proxy functionality, UFW for firewall management, and Certbot for SSL certificates. These components form the foundation of a secure, scalable Dify deployment.
Docker installation and setup
Start by preparing your system with the latest updates and removing any unofficial Docker packages that might conflict with the official installation. Execute these commands to establish a clean environment:
sudo apt update && sudo apt upgrade -y
sudo apt install -y apt-transport-https ca-certificates curl software-properties-common gnupg lsb-release git ufw nginx
# Remove unofficial Docker packages
for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do
sudo apt-get remove $pkg;
done
Install Docker's official repository and packages using their recommended method. This ensures you receive security updates and maintain compatibility with Dify's requirements:
# Add Docker's official GPG key
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
# Add repository
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# Install Docker
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo usermod -aG docker $USER
newgrp docker
Dify installation process
Clone the official Dify repository and configure the environment variables. The platform uses Docker Compose to orchestrate multiple services including the API server, worker processes, PostgreSQL database, and Redis cache:
git clone https://github.com/langgenius/dify.git
cd dify/docker
cp .env.example .env
# Generate secure secret key
SECRET_KEY=$(openssl rand -base64 42)
sed -i "s/^SECRET_KEY=.*/SECRET_KEY=$SECRET_KEY/" .env
Edit the .env
file to configure essential settings. For production deployments with a custom domain, update these variables:
SECRET_KEY=your-generated-secret-key
INIT_PASSWORD=your-strong-password
DB_PASSWORD=your-database-password
REDIS_PASSWORD=your-redis-password
# Domain configuration
CONSOLE_API_URL=https://your-domain.com/console/api
CONSOLE_WEB_URL=https://your-domain.com
APP_API_URL=https://your-domain.com/api
APP_WEB_URL=https://your-domain.com
Launch the Dify services using Docker Compose. The initial startup may take several minutes as Docker downloads required images:
docker compose up -d
docker compose ps # Verify all services are running
Nginx reverse proxy configuration
Create a comprehensive Nginx configuration that handles both HTTP-to-HTTPS redirection and WebSocket connections, which are essential for Dify's real-time features. This configuration includes security headers and optimized proxy settings:
# /etc/nginx/sites-available/dify
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
server_name your-domain.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name your-domain.com;
# SSL configuration (will be updated by certbot)
ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
# Security headers
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# Main application
location / {
proxy_pass http://localhost:80;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $server_name;
# WebSocket support
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
# Timeouts for WebSocket connections
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
proxy_connect_timeout 3600s;
# Buffer settings
proxy_buffering off;
proxy_buffer_size 16k;
proxy_buffers 4 16k;
}
# API endpoints with increased upload limits
location /api {
proxy_pass http://localhost:80;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
client_max_body_size 100M;
}
}
Enable the configuration and reload Nginx:
sudo ln -s /etc/nginx/sites-available/dify /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
SSL/TLS certificate setup
Let's Encrypt provides free SSL certificates with automatic renewal. Install Certbot and obtain certificates for your domain:
sudo apt update
sudo apt install -y certbot python3-certbot-nginx
# Obtain certificate
sudo certbot --nginx -d your-domain.com -d www.your-domain.com
The Certbot wizard will guide you through the process. Choose the option to redirect HTTP to HTTPS for enhanced security. Verify the auto-renewal process is functioning:
sudo certbot renew --dry-run
sudo systemctl status certbot.timer
Security hardening and firewall
Configure UFW (Uncomplicated Firewall) to restrict access to essential services only. This layered security approach protects against unauthorized access:
# Reset and configure UFW
sudo ufw --force reset
sudo ufw default deny incoming
sudo ufw default allow outgoing
# Allow essential services
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable
Implement Fail2ban to protect against brute-force attacks. Create a local configuration file:
# /etc/fail2ban/jail.local
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 3
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
[nginx-http-auth]
enabled = true
filter = nginx-http-auth
logpath = /var/log/nginx/error.log
maxretry = 5
Configure Docker daemon security settings to limit log file sizes and set appropriate resource limits:
# /etc/docker/daemon.json
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
},
"default-ulimits": {
"nofile": {
"Name": "nofile",
"Hard": 64000,
"Soft": 64000
}
}
}
Domain and DNS configuration
Configure your domain's DNS records through your registrar or DNS provider. Create an A record pointing your domain to your server's IP address. If using www subdomain, add a CNAME record pointing www to your root domain. For IPv6 support, add an AAAA record with your server's IPv6 address.
Verify DNS propagation before proceeding:
nslookup your-domain.com
dig your-domain.com A
curl -I https://your-domain.com
Testing and verification procedures
Comprehensive testing ensures all components function correctly. Start by checking Docker container health:
docker compose ps
docker compose logs api
docker compose logs worker
Test WebSocket connectivity, which is crucial for Dify's real-time features:
curl -i -N -H "Connection: Upgrade" -H "Upgrade: websocket" \
-H "Sec-WebSocket-Key: SGVsbG8sIHdvcmxkIQ==" \
-H "Sec-WebSocket-Version: 13" https://your-domain.com/
Verify API endpoints respond correctly:
curl -X GET https://your-domain.com/api/version
Troubleshooting common issues
Port conflicts often occur when Apache or other services occupy port 80. Identify and stop conflicting services:
sudo lsof -i :80
sudo systemctl stop apache2
sudo systemctl disable apache2
Database connection issues may arise from network configuration. Check PostgreSQL logs and adjust access permissions if needed:
docker compose logs db
docker exec -it docker-db-1 sh -c "echo 'host all all 172.19.0.0/16 trust' >> /var/lib/postgresql/data/pgdata/pg_hba.conf"
docker compose restart db
WebSocket failures typically indicate Nginx misconfiguration. Monitor error logs and verify proxy headers:
sudo tail -f /var/log/nginx/error.log
Memory constraints can cause service crashes. Monitor resource usage and adjust Docker limits:
docker stats
free -h
Performance optimization strategies
Optimize Nginx for production workloads by adjusting worker processes and enabling compression:
# In /etc/nginx/nginx.conf http block
worker_processes auto;
worker_connections 1024;
keepalive_timeout 65;
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json;
# Rate limiting
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
limit_req zone=api burst=20 nodelay;
Configure resource limits in docker-compose.yml to prevent container resource exhaustion:
services:
api:
deploy:
resources:
limits:
cpus: '2.0'
memory: 4G
reservations:
cpus: '1.0'
memory: 2G
Backup and maintenance automation
Create a comprehensive backup script that preserves database content, Redis data, and application volumes:
#!/bin/bash
# /usr/local/bin/dify-backup.sh
BACKUP_DIR="/var/backups/dify"
DATE=$(date +%Y%m%d_%H%M%S)
mkdir -p $BACKUP_DIR
# Backup PostgreSQL
docker exec docker-db-1 pg_dumpall -c -U postgres > $BACKUP_DIR/db_backup_$DATE.sql
# Backup Redis
docker exec docker-redis-1 redis-cli SAVE
docker cp docker-redis-1:/data/dump.rdb $BACKUP_DIR/redis_backup_$DATE.rdb
# Backup application data
tar -czf $BACKUP_DIR/volumes_backup_$DATE.tar.gz -C /path/to/dify/docker volumes/
# Cleanup old backups (keep 7 days)
find $BACKUP_DIR -name "*.sql" -mtime +7 -delete
find $BACKUP_DIR -name "*.rdb" -mtime +7 -delete
find $BACKUP_DIR -name "*.tar.gz" -mtime +7 -delete
Schedule automated backups using cron:
sudo chmod +x /usr/local/bin/dify-backup.sh
sudo crontab -e
# Add: 0 2 * * * /usr/local/bin/dify-backup.sh >> /var/log/dify-backup.log 2>&1
Implement regular maintenance tasks including system updates, Docker cleanup, and certificate renewal monitoring:
#!/bin/bash
# /usr/local/bin/dify-maintenance.sh
apt update && apt upgrade -y
docker system prune -f
docker volume prune -f
journalctl --vacuum-time=30d
certbot certificates
df -h
Conclusion
This deployment creates a production-ready Dify instance with enterprise-grade security, automated backups, and optimized performance. The configuration supports high-concurrency workloads through WebSocket connections while maintaining security through SSL/TLS encryption and firewall rules. Regular maintenance scripts ensure long-term reliability, while the modular Docker architecture facilitates updates and scaling. Monitor resource usage regularly and adjust configurations based on your workload patterns to maintain optimal performance.
Subscribe to my newsletter
Read articles from Erik Chen directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
