Download Dockerfile from Severian/ai-engine: direct link, hf CLI and curl.
- Browser
- Download file 13.9 kB
-
https://huggingface.co/spaces/Severian/ai-engine/resolve/main/Dockerfile
- Command line
-
hf download hf://spaces/Severian/ai-engine/Dockerfile
-
curl -L -o Dockerfile https://huggingface.co/spaces/Severian/ai-engine/resolve/main/Dockerfile
13.9 kB
| # Base image | |
| FROM python:3.12-slim-bookworm AS base | |
| # Set shared environment variables | |
| ENV POETRY_VERSION=1.8.4 \ | |
| POETRY_NO_INTERACTION=1 \ | |
| POETRY_VIRTUALENVS_CREATE=true \ | |
| POETRY_VIRTUALENVS_IN_PROJECT=true \ | |
| POETRY_CACHE_DIR=/tmp/poetry_cache \ | |
| PYTHONDONTWRITEBYTECODE=1 \ | |
| LANG=en_US.UTF-8 \ | |
| LANGUAGE=en_US:en \ | |
| LC_ALL=en_US.UTF-8 \ | |
| PORT=7860 \ | |
| NODE_ENV=production | |
| # Create user first (HF Spaces requirement) | |
| RUN useradd -m -u 1000 user | |
| # Install system dependencies and set up locales | |
| RUN apt-get update && apt-get install -y \ | |
| curl \ | |
| git \ | |
| gcc \ | |
| python3-dev \ | |
| libgmp-dev \ | |
| libmpfr-dev \ | |
| libmpc-dev \ | |
| nodejs \ | |
| npm \ | |
| postgresql \ | |
| postgresql-contrib \ | |
| locales \ | |
| nginx \ | |
| netcat-openbsd \ | |
| net-tools \ | |
| procps \ | |
| psmisc \ | |
| && rm -rf /var/lib/apt/lists/* \ | |
| && pip install --no-cache-dir "poetry==${POETRY_VERSION}" \ | |
| && sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen \ | |
| && locale-gen | |
| # Configure nginx | |
| RUN rm /etc/nginx/sites-enabled/default || true | |
| COPY <<EOF /etc/nginx/nginx.conf | |
| user user; | |
| pid /run/nginx.pid; | |
| worker_processes auto; | |
| events { | |
| worker_connections 1024; | |
| } | |
| http { | |
| include /etc/nginx/mime.types; | |
| default_type application/octet-stream; | |
| sendfile on; | |
| keepalive_timeout 120; | |
| client_body_temp_path /var/lib/nginx/body; | |
| proxy_temp_path /var/lib/nginx/proxy; | |
| fastcgi_temp_path /var/lib/nginx/fastcgi; | |
| uwsgi_temp_path /var/lib/nginx/uwsgi; | |
| scgi_temp_path /var/lib/nginx/scgi; | |
| # Added buffer size configurations | |
| proxy_buffer_size 128k; | |
| proxy_buffers 4 256k; | |
| proxy_busy_buffers_size 256k; | |
| # Added timeout configurations | |
| proxy_connect_timeout 120s; | |
| proxy_read_timeout 120s; | |
| proxy_send_timeout 120s; | |
| upstream frontend { | |
| server 127.0.0.1:3000; | |
| } | |
| upstream backend { | |
| server 127.0.0.1:5001; | |
| } | |
| server { | |
| listen 7860; | |
| server_name _; | |
| client_max_body_size 100M; | |
| # Increased buffer sizes | |
| proxy_buffer_size 128k; | |
| proxy_buffers 4 256k; | |
| proxy_busy_buffers_size 256k; | |
| location / { | |
| proxy_pass http://frontend; | |
| proxy_http_version 1.1; | |
| proxy_set_header Upgrade "$http_upgrade"; | |
| proxy_set_header Connection "upgrade"; | |
| proxy_set_header Host "$host"; | |
| proxy_cache_bypass "$http_upgrade"; | |
| 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_read_timeout 300s; | |
| proxy_connect_timeout 120s; | |
| proxy_send_timeout 120s; | |
| } | |
| location /api { | |
| proxy_pass http://backend; | |
| proxy_http_version 1.1; | |
| proxy_set_header Upgrade "$http_upgrade"; | |
| proxy_set_header Connection "upgrade"; | |
| proxy_set_header Host "$host"; | |
| proxy_cache_bypass "$http_upgrade"; | |
| 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_read_timeout 300s; | |
| proxy_connect_timeout 120s; | |
| proxy_send_timeout 120s; | |
| } | |
| access_log /var/log/nginx/access.log; | |
| error_log /var/log/nginx/error.log debug; | |
| } | |
| } | |
| EOF | |
| # Set up directories and permissions | |
| RUN mkdir -p /var/log/nginx /var/run/postgresql /var/lib/postgresql/data /var/log/postgresql /app/api /app/web /data/storage && \ | |
| mkdir -p /var/lib/nginx/body /var/lib/nginx/proxy /var/lib/nginx/fastcgi /var/lib/nginx/uwsgi /var/lib/nginx/scgi && \ | |
| chown -R root:root /etc/nginx && \ | |
| chmod -R 755 /etc/nginx && \ | |
| touch /run/nginx.pid && \ | |
| chown -R root:root /run/nginx.pid && \ | |
| chown -R user:user /var/lib/nginx && \ | |
| chmod -R 755 /var/lib/nginx && \ | |
| chmod -R 777 /run && \ | |
| chmod 700 /var/lib/postgresql/data && \ | |
| chmod 777 /data /app && \ | |
| chown -R user:user /var/run/postgresql /var/lib/postgresql/data /var/log/postgresql /app /data /var/log/nginx | |
| # Create and configure entrypoint script | |
| COPY <<-'EOT' /app/entrypoint.sh | |
| #!/bin/bash | |
| set -e | |
| echo "===== Application Startup at $(date "+%Y-%m-%d %H:%M:%S") =====" | |
| # Function to check if a service is ready | |
| check_service() { | |
| local service=$1 | |
| local url=$2 | |
| local max_attempts=$3 | |
| local wait_time=$4 | |
| echo "Checking $service..." | |
| for i in $(seq 1 $max_attempts); do | |
| if curl -s "$url" >/dev/null 2>&1; then | |
| echo "$service is ready" | |
| return 0 | |
| fi | |
| echo "Waiting for $service (attempt $i/$max_attempts)..." | |
| sleep $wait_time | |
| done | |
| echo "$service failed to start" | |
| return 1 | |
| } | |
| # Function to check if a port is in use | |
| wait_for_port() { | |
| local port=$1 | |
| local service=$2 | |
| local max_attempts=$3 | |
| local wait_time=$4 | |
| local host=${5:-localhost} | |
| echo "Waiting for $service on $host:$port..." | |
| for i in $(seq 1 $max_attempts); do | |
| if nc -z $host $port; then | |
| echo "$service is listening on $host:$port" | |
| return 0 | |
| fi | |
| echo "Waiting for $service (attempt $i/$max_attempts)..." | |
| sleep $wait_time | |
| done | |
| # If we get here, the service failed to start | |
| echo "=== $service Startup Failure ===" | |
| echo "Service failed to bind to $host:$port after $max_attempts attempts" | |
| echo "Checking process status:" | |
| ps aux | grep -i "$service" || true | |
| echo "Checking port status:" | |
| netstat -tulpn | grep ":$port" || true | |
| echo "Checking logs:" | |
| if [ "$service" = "Frontend" ]; then | |
| tail -n 50 /app/web/output.log || true | |
| fi | |
| return 1 | |
| } | |
| # Function to start the frontend server | |
| start_frontend() { | |
| cd /app/web | |
| echo "Cleaning up any existing Node.js processes..." | |
| # Kill any existing node processes more thoroughly | |
| pkill -9 -f "node server.js" || true | |
| # Wait a moment to ensure ports are released | |
| sleep 2 | |
| # Check if port is still in use | |
| if netstat -tulpn | grep ":3000" > /dev/null; then | |
| echo "Port 3000 is still in use. Attempting to force cleanup..." | |
| # Find and kill any process using port 3000 | |
| fuser -k 3000/tcp || true | |
| sleep 2 | |
| fi | |
| # Ensure the output log directory exists | |
| touch output.log | |
| echo "Starting Next.js server at $(date)" > output.log | |
| # Configure Next.js to listen on all interfaces | |
| export HOSTNAME="0.0.0.0" | |
| export NODE_ENV=production | |
| export PORT=3000 | |
| # Start the server with proper error handling | |
| node server.js >> output.log 2>&1 & | |
| local pid=$! | |
| echo "Frontend server started with PID: $pid" | |
| # Wait a bit to ensure process is stable and check its status | |
| sleep 5 | |
| if ! kill -0 $pid 2>/dev/null; then | |
| echo "Frontend server failed to start. Last 50 lines of logs:" | |
| tail -n 50 output.log | |
| return 1 | |
| fi | |
| # Verify the port is actually being used by our process | |
| if ! netstat -tulpn | grep ":3000.*$pid" > /dev/null; then | |
| echo "Frontend server is running but not bound to port 3000. Last 50 lines of logs:" | |
| tail -n 50 output.log | |
| return 1 | |
| fi | |
| return 0 | |
| } | |
| # Function to monitor and restart services if needed | |
| monitor_services() { | |
| local restart_count=0 | |
| local max_restarts=3 | |
| while true; do | |
| if ! pgrep -f "gunicorn" > /dev/null; then | |
| echo "API server died" | |
| tail -n 100 /app/api/gunicorn.error.log || true | |
| exit 1 | |
| fi | |
| if ! pgrep -f "node server.js" > /dev/null; then | |
| echo "Frontend server died. Attempting restart..." | |
| if [ $restart_count -lt $max_restarts ]; then | |
| restart_count=$((restart_count + 1)) | |
| echo "Restart attempt $restart_count of $max_restarts" | |
| # Force cleanup before restart | |
| pkill -9 -f "node server.js" || true | |
| fuser -k 3000/tcp || true | |
| sleep 2 | |
| if start_frontend; then | |
| echo "Frontend server restarted successfully" | |
| # Reset counter on successful restart | |
| restart_count=0 | |
| else | |
| echo "Failed to restart frontend server" | |
| tail -n 100 /app/web/output.log || true | |
| exit 1 | |
| fi | |
| else | |
| echo "Maximum frontend restart attempts reached" | |
| tail -n 100 /app/web/output.log || true | |
| exit 1 | |
| fi | |
| fi | |
| if ! pgrep -f "nginx" > /dev/null; then | |
| echo "Nginx died" | |
| tail -n 100 /var/log/nginx/error.log || true | |
| exit 1 | |
| fi | |
| sleep 5 | |
| done | |
| } | |
| # Initialize PostgreSQL database if not already initialized | |
| if [ ! -f "$PGDATA/PG_VERSION" ]; then | |
| echo "Initializing PostgreSQL database..." | |
| initdb --username=user --pwfile=<(echo "$DB_PASSWORD") --auth=md5 --encoding=UTF8 | |
| # Configure PostgreSQL | |
| echo "local all all trust" > "$PGDATA/pg_hba.conf" | |
| echo "host all all 127.0.0.1/32 md5" >> "$PGDATA/pg_hba.conf" | |
| echo "host all all ::1/128 md5" >> "$PGDATA/pg_hba.conf" | |
| echo "host all all 0.0.0.0/0 md5" >> "$PGDATA/pg_hba.conf" | |
| echo "listen_addresses = '*'" >> "$PGDATA/postgresql.conf" | |
| echo "max_connections = 100" >> "$PGDATA/postgresql.conf" | |
| echo "shared_buffers = 128MB" >> "$PGDATA/postgresql.conf" | |
| echo "work_mem = 16MB" >> "$PGDATA/postgresql.conf" | |
| echo "maintenance_work_mem = 128MB" >> "$PGDATA/postgresql.conf" | |
| echo "effective_cache_size = 512MB" >> "$PGDATA/postgresql.conf" | |
| fi | |
| # Start PostgreSQL with detailed logging | |
| echo "Starting PostgreSQL server..." | |
| pg_ctl start -D "$PGDATA" -l /var/log/postgresql/postgresql.log -o "-c logging_collector=on -c log_directory='/var/log/postgresql' -c log_filename='postgresql-%Y-%m-%d_%H%M%S.log' -c log_statement='all'" -w | |
| # Wait for PostgreSQL to start and show logs if there are issues | |
| max_tries=30 | |
| count=0 | |
| echo "Checking database connection..." | |
| until pg_isready -h localhost -p 5432; do | |
| if [ $count -eq 0 ]; then | |
| echo "PostgreSQL logs:" | |
| tail -n 50 /var/log/postgresql/postgresql.log | |
| fi | |
| echo "Waiting for database connection... (${count}/${max_tries})" | |
| sleep 2 | |
| count=$((count+1)) | |
| if [ $count -gt $max_tries ]; then | |
| echo "Failed to connect to database after ${max_tries} attempts" | |
| echo "Last 100 lines of PostgreSQL logs:" | |
| tail -n 100 /var/log/postgresql/postgresql.log | |
| exit 1 | |
| fi | |
| done | |
| # Create database if it doesn't exist | |
| if ! psql -lqt | cut -d \| -f 1 | grep -qw dify; then | |
| echo "Creating database dify..." | |
| createdb -U user dify | |
| fi | |
| echo "Database connection successful" | |
| # Start application services | |
| cd /app/api && poetry run python -m flask db upgrade | |
| # Start API server | |
| echo "Starting API server..." | |
| cd /app/api && poetry run python -m gunicorn app:app \ | |
| --bind ${DIFY_BIND_ADDRESS:-127.0.0.1}:${DIFY_PORT:-5001} \ | |
| --worker-class gevent \ | |
| --workers 1 \ | |
| --timeout 300 \ | |
| --preload \ | |
| --access-logfile - \ | |
| --error-logfile - & | |
| # Wait for API to be ready | |
| echo "Waiting for API server to be ready..." | |
| wait_for_port 5001 "API" 30 2 "127.0.0.1" | |
| # Start frontend server | |
| echo "Starting frontend server..." | |
| start_frontend | |
| # Get container IP | |
| CONTAINER_IP=$(hostname -i || ip route get 1 | awk '{print $7}' || echo "127.0.0.1") | |
| echo "Container IP: $CONTAINER_IP" | |
| # Wait for frontend to be ready | |
| echo "Waiting for frontend server to be ready..." | |
| if ! wait_for_port 3000 "Frontend" 60 5 "0.0.0.0"; then | |
| echo "Frontend server failed to start. Last 50 lines of frontend logs:" | |
| tail -n 50 /app/web/output.log | |
| exit 1 | |
| fi | |
| # Start nginx with debug logging | |
| echo "Starting nginx..." | |
| nginx -g "daemon off; error_log /var/log/nginx/error.log debug;" & | |
| # Wait for nginx to be ready | |
| wait_for_port 7860 "Nginx" 30 2 "0.0.0.0" | |
| echo "All services are running. Starting monitoring..." | |
| # Start monitoring services | |
| monitor_services | |
| EOT | |
| # Set permissions for entrypoint script | |
| RUN chmod +x /app/entrypoint.sh && \ | |
| chown user:user /app/entrypoint.sh | |
| # Switch to user for remaining operations | |
| USER user | |
| # Set environment for user | |
| ENV HOME=/home/user \ | |
| PATH=/usr/lib/postgresql/15/bin:/home/user/.local/bin:$PATH \ | |
| PGDATA=/var/lib/postgresql/data | |
| # Pull official images | |
| FROM langgenius/dify-web:latest AS web | |
| FROM langgenius/dify-api:latest AS api | |
| # Final stage | |
| FROM base | |
| # Set up directory structure | |
| WORKDIR /app | |
| RUN mkdir -p api web /data/storage | |
| # Copy from official images | |
| COPY --from=web --chown=user:user /app/web /app/web/ | |
| COPY --from=api --chown=user:user /app/api /app/api/ | |
| # Install API dependencies using Poetry | |
| WORKDIR /app/api | |
| COPY --from=api --chown=user /app/api/pyproject.toml /app/api/poetry.lock /app/api/poetry.toml ./ | |
| RUN poetry install --no-root --no-dev | |
| # Create symlink for persistent storage | |
| RUN ln -s /data/storage /app/api/storage | |
| # Set environment variables | |
| ENV FLASK_APP=app.py \ | |
| EDITION=SELF_HOSTED \ | |
| DEPLOY_ENV=PRODUCTION \ | |
| MODE=api \ | |
| LOG_LEVEL=INFO \ | |
| DEBUG=false \ | |
| FLASK_DEBUG=false \ | |
| SECRET_KEY=sk-9f73s3ljTXVcMT3Blb3ljTqtsKiGHXVcMT3BlbkFJLK7U \ | |
| CONSOLE_API_URL=https://${SPACE_ID}.hf.space \ | |
| CONSOLE_WEB_URL=https://${SPACE_ID}.hf.space \ | |
| SERVICE_API_URL=https://${SPACE_ID}.hf.space \ | |
| APP_WEB_URL=https://${SPACE_ID}.hf.space \ | |
| DIFY_PORT=5001 \ | |
| DIFY_BIND_ADDRESS=127.0.0.1 \ | |
| DB_USERNAME=user \ | |
| DB_PASSWORD=difyai123456 \ | |
| DB_HOST=localhost \ | |
| DB_PORT=5432 \ | |
| DB_DATABASE=dify \ | |
| PYTHONPATH=/app/api \ | |
| STORAGE_PATH=/data/storage | |
| EXPOSE 7860 | |
| WORKDIR /app | |
| CMD ["./entrypoint.sh"] |