diff --git a/dev/start-podman-compose b/dev/start-podman-compose new file mode 100755 index 00000000000..b403e0f707c --- /dev/null +++ b/dev/start-podman-compose @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(dirname "$(realpath "$0")")" +ROOT="$(dirname "$SCRIPT_DIR")" + +PROJECT_NAME="${PODMAN_PROJECT_NAME:-dify}" +COMPOSE_FILE="${PODMAN_COMPOSE_FILE:-$ROOT/docker/podman-compose.middleware.yaml}" +NETWORK_NAME="${PODMAN_NETWORK_NAME:-dify}" + +cd "$ROOT/docker" + +podman compose -f "$COMPOSE_FILE" -p "$PROJECT_NAME" down -v --remove-orphans || true + +if ! podman network inspect "$NETWORK_NAME" >/dev/null 2>&1; then + podman network create "$NETWORK_NAME" +fi + +podman compose -f "$COMPOSE_FILE" --profile postgresql --profile weaviate -p "$PROJECT_NAME" up -d diff --git a/dev/start-web-image b/dev/start-web-image new file mode 100755 index 00000000000..bce13622c54 --- /dev/null +++ b/dev/start-web-image @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -euo pipefail + +BACKEND_URL="${DIFY_WEB_BACKEND_URL:-http://localhost:5001}" +IMAGE="${DIFY_WEB_IMAGE:-docker.io/langgenius/dify-web:1.13.2}" +HOST_BIND="${DIFY_WEB_HOSTNAME:-localhost}" +WEB_URL="${DIFY_WEB_FRONTEND_URL:-}" +CONTAINER_NAME="${DIFY_WEB_CONTAINER_NAME:-dify-web}" +NEXT_PUBLIC_COOKIE_DOMAIN="${DIFY_WEB_NEXT_PUBLIC_COOKIE_DOMAIN:-}" + +podman rm -f "$CONTAINER_NAME" >/dev/null 2>&1 || true + +exec podman run --rm --name "$CONTAINER_NAME" --network host \ + -e HOSTNAME="${HOST_BIND}" \ + -e CONSOLE_API_URL="${BACKEND_URL}" \ + -e APP_API_URL="${BACKEND_URL}" \ + -e SERVICE_API_URL="${BACKEND_URL}" \ + ${WEB_URL:+-e CONSOLE_WEB_URL="${WEB_URL}"} \ + ${NEXT_PUBLIC_COOKIE_DOMAIN:+-e NEXT_PUBLIC_COOKIE_DOMAIN="${NEXT_PUBLIC_COOKIE_DOMAIN}"} \ + "${IMAGE}" diff --git a/dev/stop-podman-compose b/dev/stop-podman-compose new file mode 100755 index 00000000000..ee6de3f6ca6 --- /dev/null +++ b/dev/stop-podman-compose @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(dirname "$(realpath "$0")")" +ROOT="$(dirname "$SCRIPT_DIR")" +COMPOSE_FILE="${PODMAN_COMPOSE_FILE:-$ROOT/docker/podman-compose.middleware.yaml}" +PROJECT_NAME="${PODMAN_PROJECT_NAME:-dify}" + +cd "$ROOT/docker" +podman compose -f "$COMPOSE_FILE" -p "$PROJECT_NAME" down -v diff --git a/docker/podman-compose.middleware.yaml b/docker/podman-compose.middleware.yaml new file mode 100644 index 00000000000..9a3fcb226f1 --- /dev/null +++ b/docker/podman-compose.middleware.yaml @@ -0,0 +1,267 @@ +services: + # The postgres database. + db_postgres: + image: docker.io/postgres:15-alpine + profiles: + - "" + - postgresql + restart: always + env_file: + - ./middleware.env + environment: + POSTGRES_PASSWORD: ${DB_PASSWORD:-difyai123456} + POSTGRES_DB: ${DB_DATABASE:-dify} + PGDATA: ${PGDATA:-/var/lib/postgresql/data/pgdata} + command: > + postgres -c 'max_connections=${POSTGRES_MAX_CONNECTIONS:-100}' + -c 'shared_buffers=${POSTGRES_SHARED_BUFFERS:-128MB}' + -c 'work_mem=${POSTGRES_WORK_MEM:-4MB}' + -c 'maintenance_work_mem=${POSTGRES_MAINTENANCE_WORK_MEM:-64MB}' + -c 'effective_cache_size=${POSTGRES_EFFECTIVE_CACHE_SIZE:-4096MB}' + -c 'statement_timeout=${POSTGRES_STATEMENT_TIMEOUT:-0}' + -c 'idle_in_transaction_session_timeout=${POSTGRES_IDLE_IN_TRANSACTION_SESSION_TIMEOUT:-0}' + volumes: + - ${PGDATA_HOST_VOLUME:-./volumes/db/data}:/var/lib/postgresql/data + ports: + - "${EXPOSE_POSTGRES_PORT:-5432}:5432" + healthcheck: + test: + [ + "CMD", + "pg_isready", + "-h", + "db_postgres", + "-U", + "${DB_USERNAME:-postgres}", + "-d", + "${DB_DATABASE:-dify}", + ] + interval: 1s + timeout: 3s + retries: 30 + networks: + - dify + + db_mysql: + image: docker.io/mysql:8.0 + profiles: + - mysql + restart: always + env_file: + - ./middleware.env + environment: + MYSQL_ROOT_PASSWORD: ${DB_PASSWORD:-difyai123456} + MYSQL_DATABASE: ${DB_DATABASE:-dify} + command: > + --max_connections=1000 + --innodb_buffer_pool_size=${MYSQL_INNODB_BUFFER_POOL_SIZE:-512M} + --innodb_log_file_size=${MYSQL_INNODB_LOG_FILE_SIZE:-128M} + --innodb_flush_log_at_trx_commit=${MYSQL_INNODB_FLUSH_LOG_AT_TRX_COMMIT:-2} + volumes: + - ${MYSQL_HOST_VOLUME:-./volumes/mysql/data}:/var/lib/mysql + ports: + - "${EXPOSE_MYSQL_PORT:-3306}:3306" + healthcheck: + test: + [ + "CMD", + "mysqladmin", + "ping", + "-u", + "root", + "-p${DB_PASSWORD:-difyai123456}", + ] + interval: 1s + timeout: 3s + retries: 30 + networks: + - dify + + # The redis cache. + redis: + image: docker.io/redis:6-alpine + restart: always + env_file: + - ./middleware.env + environment: + REDISCLI_AUTH: ${REDIS_PASSWORD:-difyai123456} + volumes: + # Mount the redis data directory to the container. + - ${REDIS_HOST_VOLUME:-./volumes/redis/data}:/data + # Set the redis password when startup redis server. + command: redis-server --requirepass ${REDIS_PASSWORD:-difyai123456} + ports: + - "${EXPOSE_REDIS_PORT:-6379}:6379" + healthcheck: + test: + [ + "CMD-SHELL", + "redis-cli -a ${REDIS_PASSWORD:-difyai123456} ping | grep -q PONG", + ] + networks: + - dify + + # The DifySandbox + sandbox: + image: docker.io/langgenius/dify-sandbox:0.2.12 + restart: always + env_file: + - ./middleware.env + environment: + # The DifySandbox configurations + # Make sure you are changing this key for your deployment with a strong key. + # You can generate a strong key using `openssl rand -base64 42`. + API_KEY: ${SANDBOX_API_KEY:-dify-sandbox} + GIN_MODE: ${SANDBOX_GIN_MODE:-release} + WORKER_TIMEOUT: ${SANDBOX_WORKER_TIMEOUT:-15} + ENABLE_NETWORK: ${SANDBOX_ENABLE_NETWORK:-true} + HTTP_PROXY: ${SANDBOX_HTTP_PROXY:-http://ssrf_proxy:3128} + HTTPS_PROXY: ${SANDBOX_HTTPS_PROXY:-http://ssrf_proxy:3128} + SANDBOX_PORT: ${SANDBOX_PORT:-8194} + PIP_MIRROR_URL: ${PIP_MIRROR_URL:-} + volumes: + - ./volumes/sandbox/dependencies:/dependencies + - ./volumes/sandbox/conf:/conf + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8194/health"] + networks: + - ssrf_proxy_network + + # plugin daemon + plugin_daemon: + image: docker.io/langgenius/dify-plugin-daemon:0.5.4-local + restart: always + env_file: + - ./middleware.env + environment: + # Use the shared environment variables. + LOG_OUTPUT_FORMAT: ${LOG_OUTPUT_FORMAT:-text} + DB_DATABASE: ${DB_PLUGIN_DATABASE:-dify_plugin} + REDIS_HOST: ${REDIS_HOST:-redis} + REDIS_PORT: ${REDIS_PORT:-6379} + REDIS_PASSWORD: ${REDIS_PASSWORD:-difyai123456} + SERVER_PORT: ${PLUGIN_DAEMON_PORT:-5002} + SERVER_KEY: ${PLUGIN_DAEMON_KEY:-lYkiYYT6owG+71oLerGzA7GXCgOT++6ovaezWAjpCjf+Sjc3ZtU+qUEi} + MAX_PLUGIN_PACKAGE_SIZE: ${PLUGIN_MAX_PACKAGE_SIZE:-52428800} + PPROF_ENABLED: ${PLUGIN_PPROF_ENABLED:-false} + DIFY_INNER_API_URL: ${PLUGIN_DIFY_INNER_API_URL:-http://host.containers.internal:5001} + DIFY_INNER_API_KEY: ${PLUGIN_DIFY_INNER_API_KEY:-QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1} + PLUGIN_REMOTE_INSTALLING_HOST: ${PLUGIN_DEBUGGING_HOST:-0.0.0.0} + PLUGIN_REMOTE_INSTALLING_PORT: ${PLUGIN_DEBUGGING_PORT:-5003} + PLUGIN_WORKING_PATH: ${PLUGIN_WORKING_PATH:-/app/storage/cwd} + PYTHON_ENV_INIT_TIMEOUT: ${PLUGIN_PYTHON_ENV_INIT_TIMEOUT:-120} + PLUGIN_MAX_EXECUTION_TIMEOUT: ${PLUGIN_MAX_EXECUTION_TIMEOUT:-600} + PIP_MIRROR_URL: ${PIP_MIRROR_URL:-} + PLUGIN_STORAGE_TYPE: ${PLUGIN_STORAGE_TYPE:-local} + PLUGIN_STORAGE_LOCAL_ROOT: ${PLUGIN_STORAGE_LOCAL_ROOT:-/app/storage} + PLUGIN_INSTALLED_PATH: ${PLUGIN_INSTALLED_PATH:-plugin} + PLUGIN_PACKAGE_CACHE_PATH: ${PLUGIN_PACKAGE_CACHE_PATH:-plugin_packages} + PLUGIN_MEDIA_CACHE_PATH: ${PLUGIN_MEDIA_CACHE_PATH:-assets} + PLUGIN_STORAGE_OSS_BUCKET: ${PLUGIN_STORAGE_OSS_BUCKET:-} + S3_USE_AWS: ${PLUGIN_S3_USE_AWS:-false} + S3_USE_AWS_MANAGED_IAM: ${PLUGIN_S3_USE_AWS_MANAGED_IAM:-false} + S3_ENDPOINT: ${PLUGIN_S3_ENDPOINT:-} + S3_USE_PATH_STYLE: ${PLUGIN_S3_USE_PATH_STYLE:-false} + AWS_ACCESS_KEY: ${PLUGIN_AWS_ACCESS_KEY:-} + AWS_SECRET_KEY: ${PLUGIN_AWS_SECRET_KEY:-} + AWS_REGION: ${PLUGIN_AWS_REGION:-} + AZURE_BLOB_STORAGE_CONNECTION_STRING: ${PLUGIN_AZURE_BLOB_STORAGE_CONNECTION_STRING:-} + AZURE_BLOB_STORAGE_CONTAINER_NAME: ${PLUGIN_AZURE_BLOB_STORAGE_CONTAINER_NAME:-} + TENCENT_COS_SECRET_KEY: ${PLUGIN_TENCENT_COS_SECRET_KEY:-} + TENCENT_COS_SECRET_ID: ${PLUGIN_TENCENT_COS_SECRET_ID:-} + TENCENT_COS_REGION: ${PLUGIN_TENCENT_COS_REGION:-} + ALIYUN_OSS_REGION: ${PLUGIN_ALIYUN_OSS_REGION:-} + ALIYUN_OSS_ENDPOINT: ${PLUGIN_ALIYUN_OSS_ENDPOINT:-} + ALIYUN_OSS_ACCESS_KEY_ID: ${PLUGIN_ALIYUN_OSS_ACCESS_KEY_ID:-} + ALIYUN_OSS_ACCESS_KEY_SECRET: ${PLUGIN_ALIYUN_OSS_ACCESS_KEY_SECRET:-} + ALIYUN_OSS_AUTH_VERSION: ${PLUGIN_ALIYUN_OSS_AUTH_VERSION:-v4} + ALIYUN_OSS_PATH: ${PLUGIN_ALIYUN_OSS_PATH:-} + VOLCENGINE_TOS_ENDPOINT: ${PLUGIN_VOLCENGINE_TOS_ENDPOINT:-} + VOLCENGINE_TOS_ACCESS_KEY: ${PLUGIN_VOLCENGINE_TOS_ACCESS_KEY:-} + VOLCENGINE_TOS_SECRET_KEY: ${PLUGIN_VOLCENGINE_TOS_SECRET_KEY:-} + VOLCENGINE_TOS_REGION: ${PLUGIN_VOLCENGINE_TOS_REGION:-} + THIRD_PARTY_SIGNATURE_VERIFICATION_ENABLED: true + THIRD_PARTY_SIGNATURE_VERIFICATION_PUBLIC_KEYS: /app/keys/publickey.pem + FORCE_VERIFYING_SIGNATURE: false + depends_on: + db_postgres: + condition: service_healthy + redis: + condition: service_started + ports: + - "${EXPOSE_PLUGIN_DAEMON_PORT:-5002}:${PLUGIN_DAEMON_PORT:-5002}" + - "${EXPOSE_PLUGIN_DEBUGGING_PORT:-5003}:${PLUGIN_DEBUGGING_PORT:-5003}" + volumes: + - ./volumes/plugin_daemon:/app/storage + networks: + - dify + + # ssrf_proxy server + # for more information, please refer to + # https://docs.dify.ai/learn-more/faq/install-faq#18-why-is-ssrf-proxy-needed%3F + ssrf_proxy: + image: docker.io/ubuntu/squid:latest + restart: always + volumes: + - ./ssrf_proxy/squid.conf.template:/etc/squid/squid.conf.template + - ./ssrf_proxy/docker-entrypoint.sh:/docker-entrypoint-mount.sh + entrypoint: + [ + "sh", + "-c", + "cp /docker-entrypoint-mount.sh /docker-entrypoint.sh && sed -i 's/\r$$//' /docker-entrypoint.sh && chmod +x /docker-entrypoint.sh && /docker-entrypoint.sh", + ] + env_file: + - ./middleware.env + environment: + # pls clearly modify the squid env vars to fit your network environment. + HTTP_PORT: ${SSRF_HTTP_PORT:-3128} + COREDUMP_DIR: ${SSRF_COREDUMP_DIR:-/var/spool/squid} + REVERSE_PROXY_PORT: ${SSRF_REVERSE_PROXY_PORT:-8194} + SANDBOX_HOST: ${SSRF_SANDBOX_HOST:-sandbox} + SANDBOX_PORT: ${SSRF_SANDBOX_PORT:-8194} + ports: + - "${EXPOSE_SSRF_PROXY_PORT:-3128}:${SSRF_HTTP_PORT:-3128}" + - "${EXPOSE_SANDBOX_PORT:-8194}:${SANDBOX_PORT:-8194}" + networks: + - ssrf_proxy_network + - dify + + # The Weaviate vector store. + weaviate: + image: docker.io/semitechnologies/weaviate:1.27.0 + profiles: + - "" + - weaviate + restart: always + volumes: + # Mount the Weaviate data directory to the con tainer. + - ${WEAVIATE_HOST_VOLUME:-./volumes/weaviate}:/var/lib/weaviate + env_file: + - ./middleware.env + environment: + # The Weaviate configurations + # You can refer to the [Weaviate](https://weaviate.io/developers/weaviate/config-refs/env-vars) documentation for more information. + PERSISTENCE_DATA_PATH: ${WEAVIATE_PERSISTENCE_DATA_PATH:-/var/lib/weaviate} + QUERY_DEFAULTS_LIMIT: ${WEAVIATE_QUERY_DEFAULTS_LIMIT:-25} + AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED: ${WEAVIATE_AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED:-false} + DEFAULT_VECTORIZER_MODULE: ${WEAVIATE_DEFAULT_VECTORIZER_MODULE:-none} + CLUSTER_HOSTNAME: ${WEAVIATE_CLUSTER_HOSTNAME:-node1} + AUTHENTICATION_APIKEY_ENABLED: ${WEAVIATE_AUTHENTICATION_APIKEY_ENABLED:-true} + AUTHENTICATION_APIKEY_ALLOWED_KEYS: ${WEAVIATE_AUTHENTICATION_APIKEY_ALLOWED_KEYS:-WVF5YThaHlkYwhGUSmCRgsX3tD5ngdN8pkih} + AUTHENTICATION_APIKEY_USERS: ${WEAVIATE_AUTHENTICATION_APIKEY_USERS:-hello@dify.ai} + AUTHORIZATION_ADMINLIST_ENABLED: ${WEAVIATE_AUTHORIZATION_ADMINLIST_ENABLED:-true} + AUTHORIZATION_ADMINLIST_USERS: ${WEAVIATE_AUTHORIZATION_ADMINLIST_USERS:-hello@dify.ai} + DISABLE_TELEMETRY: ${WEAVIATE_DISABLE_TELEMETRY:-false} + ports: + - "${EXPOSE_WEAVIATE_PORT:-8080}:8080" + - "${EXPOSE_WEAVIATE_GRPC_PORT:-50051}:50051" + +networks: + # create a network between sandbox, api and ssrf_proxy, and can not access outside. + ssrf_proxy_network: + driver: bridge + internal: true + dify: + name: dify + driver: bridge