Eric Guo's blog.cloud-mes.com

Hoping writing JS, Ruby & Rails and Go article, but fallback to DevOps note

Install dify.ai at Rocky Linux 9.3 From Source Code

Permalink

Although dify recommends using Docker, I found that Docker consumes hundreds of gigabytes of storage and makes it difficult to tweak the code on the fly. That’s why I decided to install dify.ai from source code.

Setup the dify User Account

adduser dify
gpasswd -a dify wheel
cd /etc/sudoers.d
# you can later change more limit like "dify ALL=(ALL) NOPASSWD:/usr/bin/systemctl"
echo "dify ALL=(ALL) NOPASSWD:ALL" > 96-dify-user
sudo su - dify
mkdir .ssh
chmod 700 .ssh
vi .ssh/authorized_keys
chmod 600 .ssh/authorized_keys

Install Local Python 3.12 for dify

sudo dnf install tar curl gcc openssl-devel bzip2-devel libffi-devel zlib-devel wget make -y
sudo dnf install python3.12
sudo dnf install python3.12-pip
sudo alternatives --install /usr/bin/python3 python3 /usr/bin/python3.12 1

Install poetry

sudo dnf install pipx
python3 -m pip install --user pipx
python3 -m pipx ensurepath
pipx install poetry

Install basic environment

Follow the official guide

cd dify/api
cp .env.example .env
openssl rand -base64 42
sed -i 's/SECRET_KEY=.*/SECRET_KEY=<your_value>/' .env
poetry install

Create postgresql db user

DB in localhost

sudo su - postgres
createuser dify
psql
ALTER ROLE dify LOGIN;
CREATE DATABASE dify_prod WITH ENCODING='UTF8' OWNER=dify;
logout
poetry run python -m flask db upgrade

Using password in different server DB

sudo su - postgres
createuser dify --pwprompt
createuser dify_plugin
psql
ALTER ROLE dify LOGIN;
CREATE DATABASE dify_prod WITH ENCODING='UTF8' OWNER=dify;
ALTER USER dify_plugin PASSWORD 'dify_plugin';
ALTER ROLE dify_plugin LOGIN;
CREATE DATABASE dify_plugin WITH ENCODING='UTF8' OWNER=dify_plugin;
logout
vi /var/lib/pgsql/16/data/pg_hba.conf
# TYPE DATABASE USER ADDRESS METHOD
host dify_prod dify 0.0.0.0/0 scram-sha-256

Reload conf without restart DB

sudo su - postgres
/usr/pgsql-16/bin/pg_ctl reload

Install ffmpeg as dify require it

following guide

sudo dnf install epel-release
sudo dnf config-manager --set-enabled crb
sudo dnf install --nogpgcheck https://mirrors.rpmfusion.org/free/el/rpmfusion-free-release-$(rpm -E %rhel).noarch.rpm -y
sudo dnf install --nogpgcheck https://mirrors.rpmfusion.org/nonfree/el/rpmfusion-nonfree-release-$(rpm -E %rhel).noarch.rpm -y
sudo dnf install ffmpeg ffmpeg-devel

Install Passenger to hosting dify-api

reason to choose passenger instead of dify original gunicorn is much user friendly to change something.

server {
listen 80;
server_name dify-api.thape.com.cn;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name dify-api.thape.com.cn;
ssl_certificate /etc/ssl/cert/STAR_thape_com_cn_integrated.crt;
ssl_certificate_key /etc/ssl/private/STAR_thape_com_cn.key;
root /home/dify/dify/api/public;
passenger_app_type wsgi;
passenger_startup_file /home/dify/dify/api/passenger_wsgi.py;
passenger_enabled on;
passenger_python /home/dify/dify/api/.venv/bin/python;
passenger_env_var VIRTUAL_ENV /home/dify/dify/api/.venv;
passenger_friendly_error_pages on;
passenger_env_var FLASK_DEBUG true;
access_log /var/www/dify/shared/log/nginx-api.access.log;
error_log /var/www/dify/shared/log/nginx-api.error.log;
}

This configuration sets up HTTP to redirect to HTTPS and configures Passenger for a WSGI application.

Hosting the web part of dify

yarn install
yarn build
cp .env.example .env # also make modify
yarn run start # or run in background
upstream dify_web_proxy {
server 127.0.0.1:3000;
}
server {
listen 80;
server_name dify.thape.com.cn;
return 301 https://dify.thape.com.cn$request_uri;
}
server {
listen 443 ssl;
server_name dify.thape.com.cn;
ssl_certificate /etc/ssl/cert/STAR_thape_com_cn_integrated.crt;
ssl_certificate_key /etc/ssl/private/STAR_thape_com_cn.key;
client_max_body_size 10M;
location / {
proxy_pass http://dify_web_proxy;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
access_log /var/www/dify/shared/log/nginx.access.log;
error_log /var/www/dify/shared/log/nginx.error.log;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}

Configure the system auto start for web

vi /etc/systemd/system/dify_web.service
[Unit]
Description=Dify web service
After=network.target
[Service]
Type=simple
User=dify
Group=dify
LimitNOFILE=32768
WorkingDirectory=/home/dify/dify/web
ExecStart=yarn run start
[Install]
WantedBy=multi-user.target

Running weaviate

vi /etc/systemd/system/dify_weaviate.service
[Unit]
Description=Dify weaviate service
After=network.target
[Service]
Type=simple
User=dify
Group=dify
LimitNOFILE=32768
Environment=AUTHENTICATION_APIKEY_ENABLED=false
WorkingDirectory=/home/dify/weaviate
ExecStart=weaviate --host 127.0.0.1 --port 8080 --scheme http
[Install]
WantedBy=multi-user.target

Running celery

vi /etc/systemd/system/dify_celery.service
[Unit]
Description=Dify celery service
After=network.target
[Service]
Type=simple
User=dify
Group=dify
LimitNOFILE=32768
WorkingDirectory=/home/dify/dify/api
ExecStart=/home/dify/.local/bin/poetry run python -m celery -A app.celery worker -P gevent -c 1 --loglevel INFO -Q dataset,generation,mail,ops_trace,app_deletion
[Install]
WantedBy=multi-user.target

Running dify-sandbox

sudo su - # run as root
mkdir -p /etc/containers
mkdir -p /root/sandbox/dependencies
touch /etc/containers/nodocker
podman stop dify-sandbox
podman pull langgenius/dify-sandbox:0.2.10
# replace API_KEY:dify-sandbox if necessory
podman run -d --name dify-sandbox \
--replace \
--restart always \
-p 8194:8194 \
-e API_KEY=dify-sandbox \
-e GIN_MODE=release \
-e WORKER_TIMEOUT=15 \
-e ENABLE_NETWORK=true \
-e SANDBOX_PORT=8194 \
-v /root/sandbox/dependencies:/dependencies:Z \
--healthcheck-command="curl -f http://localhost:8194/health" \
docker.io/langgenius/dify-sandbox:0.2.10
curl -f http://localhost:8194/health # should be OK

Running dify-plugin-daemon

git clone https://github.com/langgenius/dify-plugin-daemon.git
cd dify-plugin-daemon
cp .env.example .env
go build \
-ldflags "\
-X 'github.com/langgenius/dify-plugin-daemon/internal/manifest.VersionX=0.0.2' \
-X 'github.com/langgenius/dify-plugin-daemon/internal/manifest.BuildTimeX=$(date -u +%Y-%m-%dT%H:%M:%S%z)'" \
-o /usr/local/bin/dify-plugin-daemon cmd/server/main.go

Update the dify to last version

sudo systemctl stop dify_celery.service
sudo systemctl stop dify_weaviate.service
sudo systemctl stop dify_web.service
git fetch --all
git reset --hard origin/pre_thape
cd api
poetry install
poetry run python -m flask db upgrade
sudo systemctl restart nginx # restart dify-api server
cd ../web
yarn install
yarn run build
sudo systemctl start dify_web.service
sudo systemctl start dify_weaviate.service
sudo systemctl start dify_celery.service

Quick restart

Only after change python part.

sudo systemctl restart nginx
sudo systemctl restart dify_celery.service

Reset password

poetry run python -m flask reset-password
poetry run python -m flask shell
from services.account_service import AccountService
AccountService.reset_login_error_rate_limit("someone@company.com")

Comments