Dify / Dockerfile
Yota-E363's picture
Create Dockerfile
ea1aa9c verified
Raw
History Blame Contribute Delete
8.65 kB
# ============================================================
# Dify 1.14.2 β€” Hugging Face Space (Docker)
# Port HF : 7860
# Mode : single container
# Base de donnΓ©es : Supabase (PostgreSQL externe)
# Redis : Upstash (TCP/TLS externe)
# Vecteurs : pgvector via Supabase (direct port 5432)
# Orchestreur : supervisord (nginx + api + worker + web + plugin_daemon)
# ============================================================
# ── Stage 1 : Build frontend Next.js ────────────────────────
FROM node:20-slim AS web-builder
RUN apt-get update && apt-get install -y --no-install-recommends \
git ca-certificates \
&& rm -rf /var/lib/apt/lists/*
RUN git clone --depth 1 --branch 1.14.2 \
https://github.com/langgenius/dify.git /tmp/dify \
&& cp -r /tmp/dify/web /app/web \
&& rm -rf /tmp/dify
WORKDIR /app/web
RUN npm install -g pnpm \
&& pnpm install --frozen-lockfile \
&& pnpm build
# ── Stage final ──────────────────────────────────────────────
FROM python:3.12-slim-bookworm
# --------------------------------------------------
# Dépendances système
# --------------------------------------------------
RUN apt-get update && apt-get install -y --no-install-recommends \
git curl ca-certificates gnupg \
nginx supervisor \
libpq-dev libmagic1 libcairo2 libglib2.0-0 \
poppler-utils tesseract-ocr \
&& curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
&& apt-get install -y nodejs \
&& rm -rf /var/lib/apt/lists/*
# --------------------------------------------------
# Cloner et installer Dify API
# --------------------------------------------------
RUN git clone --depth 1 --branch 1.14.2 \
https://github.com/langgenius/dify.git /tmp/dify \
&& cp -r /tmp/dify/api /app/api \
&& rm -rf /tmp/dify
WORKDIR /app/api
RUN pip install --no-cache-dir uv==0.6.14 \
&& uv sync --frozen --no-dev
# --------------------------------------------------
# Plugin daemon (binaire Go)
# --------------------------------------------------
RUN curl -L \
"https://github.com/langgenius/dify-plugin-daemon/releases/download/0.1.0/dify-plugin-daemon-linux-amd64" \
-o /app/plugin_daemon \
&& chmod +x /app/plugin_daemon
# --------------------------------------------------
# Frontend (depuis le stage web-builder)
# --------------------------------------------------
COPY --from=web-builder /app/web/.next/standalone /app/web
COPY --from=web-builder /app/web/.next/static /app/web/.next/static
COPY --from=web-builder /app/web/public /app/web/public
# --------------------------------------------------
# Variables non-secrètes
#
# ⚠️ NE PAS mettre ici (β†’ HF Secrets obligatoire) :
# - SECRET_KEY clΓ© de chiffrement Dify
# - DB_PASSWORD mot de passe Supabase
# - PGVECTOR_PASSWORD mΓͺme mot de passe Supabase
# - REDIS_PASSWORD token Upstash
# - CELERY_BROKER_URL URL complète Upstash avec token
# - PLUGIN_DAEMON_KEY clΓ© plugin daemon
# - INNER_API_KEY_FOR_PLUGIN clΓ© interne plugins
# - CONSOLE_API_URL URL publique du Space HF
# - APP_API_URL URL publique du Space HF
# - APP_WEB_URL URL publique du Space HF
# - SERVICE_API_URL URL publique du Space HF
#
# --------------------------------------------------
ENV \
# --- Python ---
PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
MALLOC_ARENA_MAX=2 \
\
# --- Node ---
NODE_OPTIONS="--max-old-space-size=2048" \
\
# --- Base de donnΓ©es (Supabase / pooler port 6543) ---
DB_HOST=aws-1-eu-central-1.pooler.supabase.com \
DB_PORT=6543 \
DB_USERNAME=postgres.bumhiinnvlbrpmvjpuwu \
DB_DATABASE=postgres \
\
# --- pgvector (connexion directe port 5432 β€” pooler incompatible) ---
PGVECTOR_HOST=db.bumhiinnvlbrpmvjpuwu.supabase.co \
PGVECTOR_PORT=5432 \
PGVECTOR_USER=postgres \
PGVECTOR_DATABASE=postgres \
VECTOR_STORE=pgvector \
\
# --- Redis (Upstash / TLS) ---
REDIS_HOST=fitting-wildcat-109052.upstash.io \
REDIS_PORT=6379 \
REDIS_USERNAME=default \
REDIS_USE_SSL=true \
\
# --- Workers (rΓ©duits pour Γ©conomiser RAM) ---
SERVER_WORKER_AMOUNT=1 \
CELERY_WORKER_AMOUNT=1 \
\
# --- Stockage fichiers ---
STORAGE_TYPE=local \
STORAGE_LOCAL_PATH=/app/api/storage \
\
# --- Plugin daemon ---
PLUGIN_DAEMON_URL=http://127.0.0.1:5002 \
\
# --- Sandbox dΓ©sactivΓ© (Γ©conomise 2 services) ---
CODE_EXECUTION_ENABLED=false \
\
# --- Migrations auto au dΓ©marrage ---
MIGRATION_ENABLED=true \
\
# --- Logs ---
LOG_LEVEL=INFO \
LOG_FILE=/app/logs/server.log \
\
# --- Deploy ---
DEPLOY_ENV=PRODUCTION \
FLASK_APP=app.py \
\
# --- Timezone ---
TZ=Europe/Berlin \
GENERIC_TIMEZONE=Europe/Berlin
# --------------------------------------------------
# Dossiers nΓ©cessaires
# --------------------------------------------------
RUN mkdir -p /app/api/storage /app/logs /var/log/supervisor /run/nginx
# --------------------------------------------------
# nginx.conf
# --------------------------------------------------
RUN cat > /etc/nginx/nginx.conf << 'EOF'
user www-data;
worker_processes 1;
pid /run/nginx.pid;
events { worker_connections 512; }
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
client_max_body_size 100M;
server {
listen 7860;
server_name _;
location ~ ^/(console/api|api|v1|files|explore) {
proxy_pass http://127.0.0.1:5001;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_read_timeout 300s;
proxy_buffering off;
proxy_cache off;
}
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
}
EOF
# --------------------------------------------------
# supervisord.conf
# --------------------------------------------------
RUN cat > /etc/supervisor/conf.d/dify.conf << 'EOF'
[supervisord]
nodaemon=true
logfile=/var/log/supervisor/supervisord.log
childlogdir=/var/log/supervisor
[program:nginx]
command=nginx -g "daemon off;"
autostart=true
autorestart=true
priority=10
stdout_logfile=/var/log/supervisor/nginx.log
stderr_logfile=/var/log/supervisor/nginx.err.log
[program:plugin_daemon]
command=/app/plugin_daemon
directory=/app
autostart=true
autorestart=true
priority=20
stdout_logfile=/var/log/supervisor/plugin_daemon.log
stderr_logfile=/var/log/supervisor/plugin_daemon.err.log
[program:api]
command=uv run gunicorn \
--bind 127.0.0.1:5001 \
--workers 1 \
--worker-class geventwebsocket.gunicorn.workers.GeventWebSocketWorker \
--timeout 200 \
app:app
directory=/app/api
autostart=true
autorestart=true
priority=30
stdout_logfile=/var/log/supervisor/api.log
stderr_logfile=/var/log/supervisor/api.err.log
[program:worker]
command=uv run celery \
-A app.celery worker \
--concurrency 1 \
--loglevel INFO \
-Q dataset,generation,mail,ops_trace,app_deletion
directory=/app/api
autostart=true
autorestart=true
priority=30
stdout_logfile=/var/log/supervisor/worker.log
stderr_logfile=/var/log/supervisor/worker.err.log
[program:web]
command=node server.js
directory=/app/web
autostart=true
autorestart=true
priority=40
environment=PORT="3000",HOSTNAME="127.0.0.1"
stdout_logfile=/var/log/supervisor/web.log
stderr_logfile=/var/log/supervisor/web.err.log
EOF
# --------------------------------------------------
# entrypoint.sh
# --------------------------------------------------
RUN cat > /entrypoint.sh << 'EOF'
#!/bin/bash
set -e
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo " Dify 1.14.2 β€” dΓ©marrage"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
cd /app/api
for i in 1 2 3 4 5; do
uv run flask db upgrade && break
echo "[init] Tentative $i Γ©chouΓ©e, retry dans 5s..."
sleep 5
done
echo "[init] Migrations OK"
exec supervisord -c /etc/supervisor/conf.d/dify.conf
EOF
RUN chmod +x /entrypoint.sh
EXPOSE 7860
CMD ["/entrypoint.sh"]