Compare commits

..

1 Commits

Author SHA1 Message Date
Isaac_Aracena a1e50ecfdf Enable Google OAuth for Supabase Auth 2026-05-30 15:16:45 +00:00
112 changed files with 4342 additions and 4077 deletions
+1 -19
View File
@@ -3,19 +3,12 @@ _APP_LOCALE=en
_APP_OPTIONS_ABUSE=enabled _APP_OPTIONS_ABUSE=enabled
_APP_OPTIONS_FORCE_HTTPS=disabled _APP_OPTIONS_FORCE_HTTPS=disabled
_APP_OPTIONS_FUNCTIONS_FORCE_HTTPS=disabled _APP_OPTIONS_FUNCTIONS_FORCE_HTTPS=disabled
_APP_OPTIONS_ROUTER_FORCE_HTTPS=disabled
_APP_OPTIONS_ROUTER_PROTECTION=disabled _APP_OPTIONS_ROUTER_PROTECTION=disabled
_APP_OPENSSL_KEY_V1=your-secret-key _APP_OPENSSL_KEY_V1=your-secret-key
_APP_DOMAIN=$(PRIMARY_DOMAIN) _APP_DOMAIN=localhost
_APP_CUSTOM_DOMAIN_DENY_LIST=example.com,test.com,app.example.com _APP_CUSTOM_DOMAIN_DENY_LIST=example.com,test.com,app.example.com
_APP_DOMAIN_FUNCTIONS=functions.localhost _APP_DOMAIN_FUNCTIONS=functions.localhost
_APP_DOMAIN_SITES=sites.localhost
_APP_DOMAIN_TARGET=localhost _APP_DOMAIN_TARGET=localhost
_APP_DOMAIN_TARGET_CNAME=localhost
_APP_DOMAIN_TARGET_AAAA=::1
_APP_DOMAIN_TARGET_A=127.0.0.1
_APP_DOMAIN_TARGET_CAA=
_APP_DNS=8.8.8.8
_APP_CONSOLE_WHITELIST_ROOT=enabled _APP_CONSOLE_WHITELIST_ROOT=enabled
_APP_CONSOLE_WHITELIST_EMAILS= _APP_CONSOLE_WHITELIST_EMAILS=
_APP_CONSOLE_WHITELIST_IPS= _APP_CONSOLE_WHITELIST_IPS=
@@ -86,37 +79,27 @@ _APP_STORAGE_WASABI_SECRET=
_APP_STORAGE_WASABI_REGION=eu-central-1 _APP_STORAGE_WASABI_REGION=eu-central-1
_APP_STORAGE_WASABI_BUCKET= _APP_STORAGE_WASABI_BUCKET=
_APP_FUNCTIONS_SIZE_LIMIT=30000000 _APP_FUNCTIONS_SIZE_LIMIT=30000000
_APP_COMPUTE_SIZE_LIMIT=30000000
_APP_FUNCTIONS_BUILD_SIZE_LIMIT=2000000000 _APP_FUNCTIONS_BUILD_SIZE_LIMIT=2000000000
_APP_FUNCTIONS_TIMEOUT=900 _APP_FUNCTIONS_TIMEOUT=900
_APP_FUNCTIONS_BUILD_TIMEOUT=900 _APP_FUNCTIONS_BUILD_TIMEOUT=900
_APP_COMPUTE_BUILD_TIMEOUT=900
_APP_FUNCTIONS_CONTAINERS=10 _APP_FUNCTIONS_CONTAINERS=10
_APP_FUNCTIONS_CPUS=0 _APP_FUNCTIONS_CPUS=0
_APP_COMPUTE_CPUS=0
_APP_FUNCTIONS_MEMORY=0 _APP_FUNCTIONS_MEMORY=0
_APP_COMPUTE_MEMORY=0
_APP_FUNCTIONS_MEMORY_SWAP=0 _APP_FUNCTIONS_MEMORY_SWAP=0
_APP_FUNCTIONS_RUNTIMES=node-16.0,php-8.0,python-3.9,ruby-3.0 _APP_FUNCTIONS_RUNTIMES=node-16.0,php-8.0,python-3.9,ruby-3.0
_APP_EXECUTOR_SECRET=your-secret-key _APP_EXECUTOR_SECRET=your-secret-key
_APP_EXECUTOR_HOST=http://exc1/v1 _APP_EXECUTOR_HOST=http://exc1/v1
_APP_BROWSER_HOST=http://appwrite-browser:3000/v1
_APP_EXECUTOR_RUNTIME_NETWORK=appwrite_runtimes _APP_EXECUTOR_RUNTIME_NETWORK=appwrite_runtimes
_APP_FUNCTIONS_ENVS=node-16.0,php-7.4,python-3.9,ruby-3.0 _APP_FUNCTIONS_ENVS=node-16.0,php-7.4,python-3.9,ruby-3.0
_APP_FUNCTIONS_INACTIVE_THRESHOLD=60 _APP_FUNCTIONS_INACTIVE_THRESHOLD=60
_APP_COMPUTE_INACTIVE_THRESHOLD=60
DOCKERHUB_PULL_USERNAME= DOCKERHUB_PULL_USERNAME=
DOCKERHUB_PULL_PASSWORD= DOCKERHUB_PULL_PASSWORD=
DOCKERHUB_PULL_EMAIL= DOCKERHUB_PULL_EMAIL=
OPEN_RUNTIMES_NETWORK=appwrite_runtimes OPEN_RUNTIMES_NETWORK=appwrite_runtimes
_APP_FUNCTIONS_RUNTIMES_NETWORK=runtimes _APP_FUNCTIONS_RUNTIMES_NETWORK=runtimes
_APP_COMPUTE_RUNTIMES_NETWORK=runtimes
_APP_DOCKER_HUB_USERNAME= _APP_DOCKER_HUB_USERNAME=
_APP_DOCKER_HUB_PASSWORD= _APP_DOCKER_HUB_PASSWORD=
_APP_FUNCTIONS_MAINTENANCE_INTERVAL=3600 _APP_FUNCTIONS_MAINTENANCE_INTERVAL=3600
_APP_COMPUTE_MAINTENANCE_INTERVAL=3600
_APP_SITES_TIMEOUT=900
_APP_SITES_RUNTIMES=static-1,node-22,flutter-3.29
_APP_VCS_GITHUB_APP_NAME= _APP_VCS_GITHUB_APP_NAME=
_APP_VCS_GITHUB_PRIVATE_KEY= _APP_VCS_GITHUB_PRIVATE_KEY=
_APP_VCS_GITHUB_APP_ID= _APP_VCS_GITHUB_APP_ID=
@@ -125,7 +108,6 @@ _APP_VCS_GITHUB_CLIENT_SECRET=
_APP_VCS_GITHUB_WEBHOOK_SECRET= _APP_VCS_GITHUB_WEBHOOK_SECRET=
_APP_MAINTENANCE_INTERVAL=86400 _APP_MAINTENANCE_INTERVAL=86400
_APP_MAINTENANCE_DELAY=0 _APP_MAINTENANCE_DELAY=0
_APP_MAINTENANCE_START_TIME=00:00
_APP_MAINTENANCE_RETENTION_CACHE=2592000 _APP_MAINTENANCE_RETENTION_CACHE=2592000
_APP_MAINTENANCE_RETENTION_EXECUTION=1209600 _APP_MAINTENANCE_RETENTION_EXECUTION=1209600
_APP_MAINTENANCE_RETENTION_AUDIT=1209600 _APP_MAINTENANCE_RETENTION_AUDIT=1209600
+46 -86
View File
@@ -28,7 +28,7 @@ services:
- appwrite - appwrite
appwrite: appwrite:
image: appwrite/appwrite:1.8.1 image: appwrite/appwrite:1.6.2
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
networks: networks:
@@ -49,13 +49,10 @@ services:
- traefik.http.routers.appwrite_api_https.tls=true - traefik.http.routers.appwrite_api_https.tls=true
volumes: volumes:
- appwrite-uploads:/storage/uploads:rw - appwrite-uploads:/storage/uploads:rw
- appwrite-imports:/storage/imports:rw
- appwrite-cache:/storage/cache:rw - appwrite-cache:/storage/cache:rw
- appwrite-config:/storage/config:rw - appwrite-config:/storage/config:rw
- appwrite-certificates:/storage/certificates:rw - appwrite-certificates:/storage/certificates:rw
- appwrite-functions:/storage/functions:rw - appwrite-functions:/storage/functions:rw
- appwrite-sites:/storage/sites:rw
- appwrite-builds:/storage/builds:rw
depends_on: depends_on:
- mariadb - mariadb
- redis - redis
@@ -77,14 +74,10 @@ services:
- _APP_OPTIONS_ABUSE - _APP_OPTIONS_ABUSE
- _APP_OPTIONS_ROUTER_PROTECTION - _APP_OPTIONS_ROUTER_PROTECTION
- _APP_OPTIONS_FORCE_HTTPS - _APP_OPTIONS_FORCE_HTTPS
- _APP_OPTIONS_ROUTER_FORCE_HTTPS - _APP_OPTIONS_FUNCTIONS_FORCE_HTTPS
- _APP_OPENSSL_KEY_V1 - _APP_OPENSSL_KEY_V1
- _APP_DOMAIN - _APP_DOMAIN
- _APP_DOMAIN_TARGET_CNAME - _APP_DOMAIN_TARGET
- _APP_DOMAIN_TARGET_AAAA
- _APP_DOMAIN_TARGET_A
- _APP_DOMAIN_TARGET_CAA
- _APP_DNS
- _APP_DOMAIN_FUNCTIONS - _APP_DOMAIN_FUNCTIONS
- _APP_REDIS_HOST - _APP_REDIS_HOST
- _APP_REDIS_PORT - _APP_REDIS_PORT
@@ -128,21 +121,17 @@ services:
- _APP_STORAGE_WASABI_SECRET - _APP_STORAGE_WASABI_SECRET
- _APP_STORAGE_WASABI_REGION - _APP_STORAGE_WASABI_REGION
- _APP_STORAGE_WASABI_BUCKET - _APP_STORAGE_WASABI_BUCKET
- _APP_COMPUTE_SIZE_LIMIT - _APP_FUNCTIONS_SIZE_LIMIT
- _APP_FUNCTIONS_TIMEOUT - _APP_FUNCTIONS_TIMEOUT
- _APP_SITES_TIMEOUT - _APP_FUNCTIONS_BUILD_TIMEOUT
- _APP_COMPUTE_BUILD_TIMEOUT - _APP_FUNCTIONS_CPUS
- _APP_COMPUTE_CPUS - _APP_FUNCTIONS_MEMORY
- _APP_COMPUTE_MEMORY
- _APP_FUNCTIONS_RUNTIMES - _APP_FUNCTIONS_RUNTIMES
- _APP_SITES_RUNTIMES
- _APP_DOMAIN_SITES
- _APP_EXECUTOR_SECRET - _APP_EXECUTOR_SECRET
- _APP_EXECUTOR_HOST - _APP_EXECUTOR_HOST
- _APP_LOGGING_CONFIG - _APP_LOGGING_CONFIG
- _APP_MAINTENANCE_INTERVAL - _APP_MAINTENANCE_INTERVAL
- _APP_MAINTENANCE_DELAY - _APP_MAINTENANCE_DELAY
- _APP_MAINTENANCE_START_TIME
- _APP_MAINTENANCE_RETENTION_EXECUTION - _APP_MAINTENANCE_RETENTION_EXECUTION
- _APP_MAINTENANCE_RETENTION_CACHE - _APP_MAINTENANCE_RETENTION_CACHE
- _APP_MAINTENANCE_RETENTION_ABUSE - _APP_MAINTENANCE_RETENTION_ABUSE
@@ -166,7 +155,7 @@ services:
- _APP_ASSISTANT_OPENAI_API_KEY - _APP_ASSISTANT_OPENAI_API_KEY
appwrite-console: appwrite-console:
<<: *x-logging <<: *x-logging
image: appwrite/console:7.5.7 image: appwrite/console:5.2.58
restart: unless-stopped restart: unless-stopped
networks: networks:
- appwrite - appwrite
@@ -186,7 +175,7 @@ services:
- traefik.http.routers.appwrite_console_https.tls=true - traefik.http.routers.appwrite_console_https.tls=true
appwrite-realtime: appwrite-realtime:
image: appwrite/appwrite:1.8.1 image: appwrite/appwrite:1.6.2
entrypoint: realtime entrypoint: realtime
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
@@ -228,7 +217,7 @@ services:
- _APP_LOGGING_CONFIG - _APP_LOGGING_CONFIG
appwrite-worker-audits: appwrite-worker-audits:
image: appwrite/appwrite:1.8.1 image: appwrite/appwrite:1.6.2
entrypoint: worker-audits entrypoint: worker-audits
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
@@ -253,7 +242,7 @@ services:
- _APP_LOGGING_CONFIG - _APP_LOGGING_CONFIG
appwrite-worker-webhooks: appwrite-worker-webhooks:
image: appwrite/appwrite:1.8.1 image: appwrite/appwrite:1.6.2
entrypoint: worker-webhooks entrypoint: worker-webhooks
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
@@ -280,7 +269,7 @@ services:
- _APP_LOGGING_CONFIG - _APP_LOGGING_CONFIG
appwrite-worker-deletes: appwrite-worker-deletes:
image: appwrite/appwrite:1.8.1 image: appwrite/appwrite:1.6.2
entrypoint: worker-deletes entrypoint: worker-deletes
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
@@ -293,7 +282,6 @@ services:
- appwrite-uploads:/storage/uploads:rw - appwrite-uploads:/storage/uploads:rw
- appwrite-cache:/storage/cache:rw - appwrite-cache:/storage/cache:rw
- appwrite-functions:/storage/functions:rw - appwrite-functions:/storage/functions:rw
- appwrite-sites:/storage/sites:rw
- appwrite-builds:/storage/builds:rw - appwrite-builds:/storage/builds:rw
- appwrite-certificates:/storage/certificates:rw - appwrite-certificates:/storage/certificates:rw
environment: environment:
@@ -342,7 +330,7 @@ services:
- _APP_EMAIL_CERTIFICATES - _APP_EMAIL_CERTIFICATES
appwrite-worker-databases: appwrite-worker-databases:
image: appwrite/appwrite:1.8.1 image: appwrite/appwrite:1.6.2
entrypoint: worker-databases entrypoint: worker-databases
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
@@ -367,7 +355,7 @@ services:
- _APP_LOGGING_CONFIG - _APP_LOGGING_CONFIG
appwrite-worker-builds: appwrite-worker-builds:
image: appwrite/appwrite:1.8.1 image: appwrite/appwrite:1.6.2
entrypoint: worker-builds entrypoint: worker-builds
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
@@ -378,9 +366,7 @@ services:
- mariadb - mariadb
volumes: volumes:
- appwrite-functions:/storage/functions:rw - appwrite-functions:/storage/functions:rw
- appwrite-sites:/storage/sites:rw
- appwrite-builds:/storage/builds:rw - appwrite-builds:/storage/builds:rw
- appwrite-uploads:/storage/uploads:rw
environment: environment:
- _APP_ENV - _APP_ENV
- _APP_WORKER_PER_CORE - _APP_WORKER_PER_CORE
@@ -401,13 +387,12 @@ services:
- _APP_VCS_GITHUB_PRIVATE_KEY - _APP_VCS_GITHUB_PRIVATE_KEY
- _APP_VCS_GITHUB_APP_ID - _APP_VCS_GITHUB_APP_ID
- _APP_FUNCTIONS_TIMEOUT - _APP_FUNCTIONS_TIMEOUT
- _APP_SITES_TIMEOUT - _APP_FUNCTIONS_BUILD_TIMEOUT
- _APP_COMPUTE_BUILD_TIMEOUT - _APP_FUNCTIONS_CPUS
- _APP_COMPUTE_CPUS - _APP_FUNCTIONS_MEMORY
- _APP_COMPUTE_MEMORY - _APP_FUNCTIONS_SIZE_LIMIT
- _APP_COMPUTE_SIZE_LIMIT
- _APP_OPTIONS_FORCE_HTTPS - _APP_OPTIONS_FORCE_HTTPS
- _APP_OPTIONS_ROUTER_FORCE_HTTPS - _APP_OPTIONS_FUNCTIONS_FORCE_HTTPS
- _APP_DOMAIN - _APP_DOMAIN
- _APP_STORAGE_DEVICE - _APP_STORAGE_DEVICE
- _APP_STORAGE_S3_ACCESS_KEY - _APP_STORAGE_S3_ACCESS_KEY
@@ -431,10 +416,9 @@ services:
- _APP_STORAGE_WASABI_SECRET - _APP_STORAGE_WASABI_SECRET
- _APP_STORAGE_WASABI_REGION - _APP_STORAGE_WASABI_REGION
- _APP_STORAGE_WASABI_BUCKET - _APP_STORAGE_WASABI_BUCKET
- _APP_DOMAIN_SITES
appwrite-worker-certificates: appwrite-worker-certificates:
image: appwrite/appwrite:1.8.1 image: appwrite/appwrite:1.6.2
entrypoint: worker-certificates entrypoint: worker-certificates
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
@@ -451,11 +435,7 @@ services:
- _APP_WORKER_PER_CORE - _APP_WORKER_PER_CORE
- _APP_OPENSSL_KEY_V1 - _APP_OPENSSL_KEY_V1
- _APP_DOMAIN - _APP_DOMAIN
- _APP_DOMAIN_TARGET_CNAME - _APP_DOMAIN_TARGET
- _APP_DOMAIN_TARGET_AAAA
- _APP_DOMAIN_TARGET_A
- _APP_DOMAIN_TARGET_CAA
- _APP_DNS
- _APP_DOMAIN_FUNCTIONS - _APP_DOMAIN_FUNCTIONS
- _APP_EMAIL_CERTIFICATES - _APP_EMAIL_CERTIFICATES
- _APP_REDIS_HOST - _APP_REDIS_HOST
@@ -470,7 +450,7 @@ services:
- _APP_LOGGING_CONFIG - _APP_LOGGING_CONFIG
appwrite-worker-functions: appwrite-worker-functions:
image: appwrite/appwrite:1.8.1 image: appwrite/appwrite:1.6.2
entrypoint: worker-functions entrypoint: worker-functions
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
@@ -496,10 +476,9 @@ services:
- _APP_DB_USER - _APP_DB_USER
- _APP_DB_PASS - _APP_DB_PASS
- _APP_FUNCTIONS_TIMEOUT - _APP_FUNCTIONS_TIMEOUT
- _APP_SITES_TIMEOUT - _APP_FUNCTIONS_BUILD_TIMEOUT
- _APP_COMPUTE_BUILD_TIMEOUT - _APP_FUNCTIONS_CPUS
- _APP_COMPUTE_CPUS - _APP_FUNCTIONS_MEMORY
- _APP_COMPUTE_MEMORY
- _APP_EXECUTOR_SECRET - _APP_EXECUTOR_SECRET
- _APP_EXECUTOR_HOST - _APP_EXECUTOR_HOST
- _APP_USAGE_STATS - _APP_USAGE_STATS
@@ -508,7 +487,7 @@ services:
- _APP_LOGGING_CONFIG - _APP_LOGGING_CONFIG
appwrite-worker-mails: appwrite-worker-mails:
image: appwrite/appwrite:1.8.1 image: appwrite/appwrite:1.6.2
entrypoint: worker-mails entrypoint: worker-mails
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
@@ -541,7 +520,7 @@ services:
- _APP_OPTIONS_FORCE_HTTPS - _APP_OPTIONS_FORCE_HTTPS
appwrite-worker-messaging: appwrite-worker-messaging:
image: appwrite/appwrite:1.8.1 image: appwrite/appwrite:1.6.2
entrypoint: worker-messaging entrypoint: worker-messaging
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
@@ -591,14 +570,12 @@ services:
- _APP_STORAGE_WASABI_BUCKET - _APP_STORAGE_WASABI_BUCKET
appwrite-worker-migrations: appwrite-worker-migrations:
image: appwrite/appwrite:1.8.1 image: appwrite/appwrite:1.6.2
entrypoint: worker-migrations entrypoint: worker-migrations
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
networks: networks:
- appwrite - appwrite
volumes:
- appwrite-imports:/storage/imports:rw
depends_on: depends_on:
- mariadb - mariadb
environment: environment:
@@ -606,11 +583,7 @@ services:
- _APP_WORKER_PER_CORE - _APP_WORKER_PER_CORE
- _APP_OPENSSL_KEY_V1 - _APP_OPENSSL_KEY_V1
- _APP_DOMAIN - _APP_DOMAIN
- _APP_DOMAIN_TARGET_CNAME - _APP_DOMAIN_TARGET
- _APP_DOMAIN_TARGET_AAAA
- _APP_DOMAIN_TARGET_A
- _APP_DOMAIN_TARGET_CAA
- _APP_DNS
- _APP_EMAIL_SECURITY - _APP_EMAIL_SECURITY
- _APP_REDIS_HOST - _APP_REDIS_HOST
- _APP_REDIS_PORT - _APP_REDIS_PORT
@@ -626,7 +599,7 @@ services:
- _APP_MIGRATIONS_FIREBASE_CLIENT_SECRET - _APP_MIGRATIONS_FIREBASE_CLIENT_SECRET
appwrite-task-maintenance: appwrite-task-maintenance:
image: appwrite/appwrite:1.8.1 image: appwrite/appwrite:1.6.2
entrypoint: maintenance entrypoint: maintenance
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
@@ -638,11 +611,7 @@ services:
- _APP_ENV - _APP_ENV
- _APP_WORKER_PER_CORE - _APP_WORKER_PER_CORE
- _APP_DOMAIN - _APP_DOMAIN
- _APP_DOMAIN_TARGET_CNAME - _APP_DOMAIN_TARGET
- _APP_DOMAIN_TARGET_AAAA
- _APP_DOMAIN_TARGET_A
- _APP_DOMAIN_TARGET_CAA
- _APP_DNS
- _APP_DOMAIN_FUNCTIONS - _APP_DOMAIN_FUNCTIONS
- _APP_OPENSSL_KEY_V1 - _APP_OPENSSL_KEY_V1
- _APP_REDIS_HOST - _APP_REDIS_HOST
@@ -664,12 +633,14 @@ services:
- _APP_MAINTENANCE_RETENTION_SCHEDULES - _APP_MAINTENANCE_RETENTION_SCHEDULES
appwrite-task-stats-resources: appwrite-task-stats-resources:
image: appwrite/appwrite:1.8.1 image: appwrite/appwrite:1.6.2
entrypoint: stats-resources entrypoint: stats-resources
<<: *x-logging <<: *x-logging
restart: unless-stopped
networks: networks:
- appwrite - appwrite
volumes:
- ./app:/usr/src/code/app
- ./src:/usr/src/code/src
depends_on: depends_on:
- redis - redis
- mariadb - mariadb
@@ -692,7 +663,7 @@ services:
- _APP_STATS_RESOURCES_INTERVAL - _APP_STATS_RESOURCES_INTERVAL
appwrite-worker-stats-resources: appwrite-worker-stats-resources:
image: appwrite/appwrite:1.8.1 image: appwrite/appwrite:1.6.2
entrypoint: worker-stats-resources entrypoint: worker-stats-resources
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
@@ -719,7 +690,7 @@ services:
- _APP_STATS_RESOURCES_INTERVAL - _APP_STATS_RESOURCES_INTERVAL
appwrite-worker-stats-usage: appwrite-worker-stats-usage:
image: appwrite/appwrite:1.8.1 image: appwrite/appwrite:1.6.2
entrypoint: worker-stats-usage entrypoint: worker-stats-usage
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
@@ -746,7 +717,7 @@ services:
- _APP_USAGE_AGGREGATION_INTERVAL - _APP_USAGE_AGGREGATION_INTERVAL
appwrite-task-scheduler-functions: appwrite-task-scheduler-functions:
image: appwrite/appwrite:1.8.1 image: appwrite/appwrite:1.6.2
entrypoint: schedule-functions entrypoint: schedule-functions
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
@@ -770,7 +741,7 @@ services:
- _APP_DB_PASS - _APP_DB_PASS
appwrite-task-scheduler-executions: appwrite-task-scheduler-executions:
image: appwrite/appwrite:1.8.1 image: appwrite/appwrite:1.6.2
entrypoint: schedule-executions entrypoint: schedule-executions
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
@@ -794,7 +765,7 @@ services:
- _APP_DB_PASS - _APP_DB_PASS
appwrite-task-scheduler-messages: appwrite-task-scheduler-messages:
image: appwrite/appwrite:1.8.1 image: appwrite/appwrite:1.6.2
entrypoint: schedule-messages entrypoint: schedule-messages
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
@@ -818,7 +789,7 @@ services:
- _APP_DB_PASS - _APP_DB_PASS
appwrite-assistant: appwrite-assistant:
image: appwrite/assistant:0.8.4 image: appwrite/assistant:0.4.0
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
networks: networks:
@@ -826,19 +797,12 @@ services:
environment: environment:
- _APP_ASSISTANT_OPENAI_API_KEY - _APP_ASSISTANT_OPENAI_API_KEY
appwrite-browser:
image: appwrite/browser:0.3.2
<<: *x-logging
restart: unless-stopped
networks:
- appwrite
openruntimes-executor: openruntimes-executor:
hostname: exc1 hostname: exc1
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
stop_signal: SIGINT stop_signal: SIGINT
image: openruntimes/executor:0.7.22 image: openruntimes/executor:0.6.11
networks: networks:
- appwrite - appwrite
- runtimes - runtimes
@@ -846,20 +810,18 @@ services:
- /var/run/docker.sock:/var/run/docker.sock - /var/run/docker.sock:/var/run/docker.sock
- appwrite-builds:/storage/builds:rw - appwrite-builds:/storage/builds:rw
- appwrite-functions:/storage/functions:rw - appwrite-functions:/storage/functions:rw
- appwrite-sites:/storage/sites:rw
# Host mount nessessary to share files between executor and runtimes. # Host mount nessessary to share files between executor and runtimes.
# It's not possible to share mount file between 2 containers without host mount (copying is too slow) # It's not possible to share mount file between 2 containers without host mount (copying is too slow)
- /tmp:/tmp:rw - /tmp:/tmp:rw
environment: environment:
- OPR_EXECUTOR_INACTIVE_TRESHOLD=$_APP_COMPUTE_INACTIVE_THRESHOLD - OPR_EXECUTOR_INACTIVE_TRESHOLD=$_APP_FUNCTIONS_INACTIVE_THRESHOLD
- OPR_EXECUTOR_MAINTENANCE_INTERVAL=$_APP_COMPUTE_MAINTENANCE_INTERVAL - OPR_EXECUTOR_MAINTENANCE_INTERVAL=$_APP_FUNCTIONS_MAINTENANCE_INTERVAL
- OPR_EXECUTOR_NETWORK=$_APP_COMPUTE_RUNTIMES_NETWORK - OPR_EXECUTOR_NETWORK=$_APP_FUNCTIONS_RUNTIMES_NETWORK
- OPR_EXECUTOR_DOCKER_HUB_USERNAME=$_APP_DOCKER_HUB_USERNAME - OPR_EXECUTOR_DOCKER_HUB_USERNAME=$_APP_DOCKER_HUB_USERNAME
- OPR_EXECUTOR_DOCKER_HUB_PASSWORD=$_APP_DOCKER_HUB_PASSWORD - OPR_EXECUTOR_DOCKER_HUB_PASSWORD=$_APP_DOCKER_HUB_PASSWORD
- OPR_EXECUTOR_ENV=$_APP_ENV - OPR_EXECUTOR_ENV=$_APP_ENV
- OPR_EXECUTOR_RUNTIMES=$_APP_FUNCTIONS_RUNTIMES,$_APP_SITES_RUNTIMES - OPR_EXECUTOR_RUNTIMES=$_APP_FUNCTIONS_RUNTIMES
- OPR_EXECUTOR_SECRET=$_APP_EXECUTOR_SECRET - OPR_EXECUTOR_SECRET=$_APP_EXECUTOR_SECRET
- OPR_EXECUTOR_RUNTIME_VERSIONS=v5
- OPR_EXECUTOR_LOGGING_CONFIG=$_APP_LOGGING_CONFIG - OPR_EXECUTOR_LOGGING_CONFIG=$_APP_LOGGING_CONFIG
- OPR_EXECUTOR_STORAGE_DEVICE=$_APP_STORAGE_DEVICE - OPR_EXECUTOR_STORAGE_DEVICE=$_APP_STORAGE_DEVICE
- OPR_EXECUTOR_STORAGE_S3_ACCESS_KEY=$_APP_STORAGE_S3_ACCESS_KEY - OPR_EXECUTOR_STORAGE_S3_ACCESS_KEY=$_APP_STORAGE_S3_ACCESS_KEY
@@ -933,9 +895,7 @@ volumes:
appwrite-redis: appwrite-redis:
appwrite-cache: appwrite-cache:
appwrite-uploads: appwrite-uploads:
appwrite-imports:
appwrite-certificates: appwrite-certificates:
appwrite-functions: appwrite-functions:
appwrite-sites:
appwrite-builds: appwrite-builds:
appwrite-config: appwrite-config:
-6
View File
@@ -11,9 +11,3 @@ await utils.downloadFile(
await utils.removeContainerNames("./code/docker-compose.yml"); await utils.removeContainerNames("./code/docker-compose.yml");
await utils.removePorts("./code/docker-compose.yml"); await utils.removePorts("./code/docker-compose.yml");
await utils.searchReplace(
"./code/.env.example",
"_APP_DOMAIN=localhost",
"_APP_DOMAIN=$(PRIMARY_DOMAIN)"
);
+14
View File
@@ -0,0 +1,14 @@
#!/bin/bash
if [ ! -d "./repo" ]; then
git clone --depth 1 --branch main --single-branch https://github.com/appwrite/appwrite.git repo
else
cd repo
git pull
cd ..
fi
curl -s https://appwrite.io/install/compose > ./code/docker-compose.yml
curl -s https://appwrite.io/install/env > ./code/.env.example
+5
View File
@@ -0,0 +1,5 @@
# Dify
- copied from https://github.com/langgenius/dify
- removed `container_name`
- removed `ports`
+42 -496
View File
@@ -24,11 +24,6 @@ CONSOLE_WEB_URL=
# Example: https://api.dify.ai # Example: https://api.dify.ai
SERVICE_API_URL= SERVICE_API_URL=
# Trigger external URL
# used to display trigger endpoint API Base URL to the front-end.
# Example: https://api.dify.ai
TRIGGER_URL=http://localhost
# WebApp API backend Url, # WebApp API backend Url,
# used to declare the back-end URL for the front-end API. # used to declare the back-end URL for the front-end API.
# If empty, it is the same domain. # If empty, it is the same domain.
@@ -39,7 +34,7 @@ APP_API_URL=
# used to display WebAPP API Base Url to the front-end. # used to display WebAPP API Base Url to the front-end.
# If empty, it is the same domain. # If empty, it is the same domain.
# Example: https://app.dify.ai # Example: https://app.dify.ai
APP_WEB_URL=https://$(PRIMARY_DOMAIN) APP_WEB_URL=
# File preview or download Url prefix. # File preview or download Url prefix.
# used to display File preview or download Url to the front-end or as Multi-model inputs; # used to display File preview or download Url to the front-end or as Multi-model inputs;
@@ -52,19 +47,6 @@ APP_WEB_URL=https://$(PRIMARY_DOMAIN)
# ensuring port 5001 is externally accessible (see docker-compose.yaml). # ensuring port 5001 is externally accessible (see docker-compose.yaml).
FILES_URL= FILES_URL=
# INTERNAL_FILES_URL is used for plugin daemon communication within Docker network.
# Set this to the internal Docker service URL for proper plugin file access.
# Example: INTERNAL_FILES_URL=http://api:5001
INTERNAL_FILES_URL=
# Ensure UTF-8 encoding
LANG=C.UTF-8
LC_ALL=C.UTF-8
PYTHONIOENCODING=utf-8
# Set UV cache directory to avoid permission issues with non-existent home directory
UV_CACHE_DIR=/tmp/.uv-cache
# ------------------------------ # ------------------------------
# Server Configuration # Server Configuration
# ------------------------------ # ------------------------------
@@ -72,8 +54,6 @@ UV_CACHE_DIR=/tmp/.uv-cache
# The log level for the application. # The log level for the application.
# Supported values are `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL` # Supported values are `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL`
LOG_LEVEL=INFO LOG_LEVEL=INFO
# Log output format: text or json
LOG_OUTPUT_FORMAT=text
# Log file path # Log file path
LOG_FILE=/app/logs/server.log LOG_FILE=/app/logs/server.log
# Log file max size, the unit is MB # Log file max size, the unit is MB
@@ -101,7 +81,7 @@ ENABLE_REQUEST_LOGGING=False
# A secret key that is used for securely signing the session cookie # A secret key that is used for securely signing the session cookie
# and encrypting sensitive information on the database. # and encrypting sensitive information on the database.
# You can generate a strong key using `openssl rand -base64 42`. # You can generate a strong key using `openssl rand -base64 42`.
SECRET_KEY= SECRET_KEY=sk-9f73s3ljTXVcMT3Blb3ljTqtsKiGHXVcMT3BlbkFJLK7U
# Password for admin user initialization. # Password for admin user initialization.
# If left unset, admin user will not be prompted for a password # If left unset, admin user will not be prompted for a password
@@ -138,8 +118,6 @@ ACCESS_TOKEN_EXPIRE_MINUTES=60
# Refresh token expiration time in days # Refresh token expiration time in days
REFRESH_TOKEN_EXPIRE_DAYS=30 REFRESH_TOKEN_EXPIRE_DAYS=30
# The default number of active requests for the application, where 0 means unlimited, should be a non-negative integer.
APP_DEFAULT_ACTIVE_REQUESTS=0
# The maximum number of active requests for the application, where 0 means unlimited, should be a non-negative integer. # The maximum number of active requests for the application, where 0 means unlimited, should be a non-negative integer.
APP_MAX_ACTIVE_REQUESTS=0 APP_MAX_ACTIVE_REQUESTS=0
APP_MAX_EXECUTION_TIME=1200 APP_MAX_EXECUTION_TIME=1200
@@ -161,12 +139,6 @@ DIFY_PORT=5001
SERVER_WORKER_AMOUNT=1 SERVER_WORKER_AMOUNT=1
# Defaults to gevent. If using windows, it can be switched to sync or solo. # Defaults to gevent. If using windows, it can be switched to sync or solo.
#
# Warning: Changing this parameter requires disabling patching for
# psycopg2 and gRPC (see `gunicorn.conf.py` and `celery_entrypoint.py`).
# Modifying it may also decrease throughput.
#
# It is strongly discouraged to change this parameter.
SERVER_WORKER_CLASS=gevent SERVER_WORKER_CLASS=gevent
# Default number of worker connections, the default is 10. # Default number of worker connections, the default is 10.
@@ -174,12 +146,6 @@ SERVER_WORKER_CONNECTIONS=10
# Similar to SERVER_WORKER_CLASS. # Similar to SERVER_WORKER_CLASS.
# If using windows, it can be switched to sync or solo. # If using windows, it can be switched to sync or solo.
#
# Warning: Changing this parameter requires disabling patching for
# psycopg2 and gRPC (see `gunicorn_conf.py` and `celery_entrypoint.py`).
# Modifying it may also decrease throughput.
#
# It is strongly discouraged to change this parameter.
CELERY_WORKER_CLASS= CELERY_WORKER_CLASS=
# Request handling timeout. The default is 200, # Request handling timeout. The default is 200,
@@ -225,42 +191,24 @@ ENABLE_WEBSITE_JINAREADER=true
ENABLE_WEBSITE_FIRECRAWL=true ENABLE_WEBSITE_FIRECRAWL=true
ENABLE_WEBSITE_WATERCRAWL=true ENABLE_WEBSITE_WATERCRAWL=true
# Enable inline LaTeX rendering with single dollar signs ($...$) in the web frontend
# Default is false for security reasons to prevent conflicts with regular text
NEXT_PUBLIC_ENABLE_SINGLE_DOLLAR_LATEX=false
# ------------------------------ # ------------------------------
# Database Configuration # Database Configuration
# The database uses PostgreSQL or MySQL. OceanBase and seekdb are also supported. Please use the public schema. # The database uses PostgreSQL. Please use the public schema.
# It is consistent with the configuration in the database service below. # It is consistent with the configuration in the 'db' service below.
# You can adjust the database configuration according to your needs.
# ------------------------------ # ------------------------------
# Database type, supported values are `postgresql`, `mysql`, `oceanbase`, `seekdb`
DB_TYPE=postgresql
# For MySQL, only `root` user is supported for now
DB_USERNAME=postgres DB_USERNAME=postgres
DB_PASSWORD=difyai123456 DB_PASSWORD=difyai123456
DB_HOST=db_postgres DB_HOST=db
DB_PORT=5432 DB_PORT=5432
DB_DATABASE=dify DB_DATABASE=dify
# The size of the database connection pool. # The size of the database connection pool.
# The default is 30 connections, which can be appropriately increased. # The default is 30 connections, which can be appropriately increased.
SQLALCHEMY_POOL_SIZE=30 SQLALCHEMY_POOL_SIZE=30
# The default is 10 connections, which allows temporary overflow beyond the pool size.
SQLALCHEMY_MAX_OVERFLOW=10
# Database connection pool recycling time, the default is 3600 seconds. # Database connection pool recycling time, the default is 3600 seconds.
SQLALCHEMY_POOL_RECYCLE=3600 SQLALCHEMY_POOL_RECYCLE=3600
# Whether to print SQL, default is false. # Whether to print SQL, default is false.
SQLALCHEMY_ECHO=false SQLALCHEMY_ECHO=false
# If True, will test connections for liveness upon each checkout
SQLALCHEMY_POOL_PRE_PING=false
# Whether to enable the Last in first out option or use default FIFO queue if is false
SQLALCHEMY_POOL_USE_LIFO=false
# Number of seconds to wait for a connection from the pool before raising a timeout error.
# Default is 30
SQLALCHEMY_POOL_TIMEOUT=30
# Maximum number of connections to the database # Maximum number of connections to the database
# Default is 100 # Default is 100
@@ -292,43 +240,6 @@ POSTGRES_MAINTENANCE_WORK_MEM=64MB
# Reference: https://www.postgresql.org/docs/current/runtime-config-query.html#GUC-EFFECTIVE-CACHE-SIZE # Reference: https://www.postgresql.org/docs/current/runtime-config-query.html#GUC-EFFECTIVE-CACHE-SIZE
POSTGRES_EFFECTIVE_CACHE_SIZE=4096MB POSTGRES_EFFECTIVE_CACHE_SIZE=4096MB
# Sets the maximum allowed duration of any statement before termination.
# Default is 0 (no timeout).
#
# Reference: https://www.postgresql.org/docs/current/runtime-config-client.html#GUC-STATEMENT-TIMEOUT
# A value of 0 prevents the server from timing out statements.
POSTGRES_STATEMENT_TIMEOUT=0
# Sets the maximum allowed duration of any idle in-transaction session before termination.
# Default is 0 (no timeout).
#
# Reference: https://www.postgresql.org/docs/current/runtime-config-client.html#GUC-IDLE-IN-TRANSACTION-SESSION-TIMEOUT
# A value of 0 prevents the server from terminating idle sessions.
POSTGRES_IDLE_IN_TRANSACTION_SESSION_TIMEOUT=0
# MySQL Performance Configuration
# Maximum number of connections to MySQL
#
# Default is 1000
MYSQL_MAX_CONNECTIONS=1000
# InnoDB buffer pool size
# Default is 512M
# Recommended value: 70-80% of available memory for dedicated MySQL server
# Reference: https://dev.mysql.com/doc/refman/8.0/en/innodb-parameters.html#sysvar_innodb_buffer_pool_size
MYSQL_INNODB_BUFFER_POOL_SIZE=512M
# InnoDB log file size
# Default is 128M
# Reference: https://dev.mysql.com/doc/refman/8.0/en/innodb-parameters.html#sysvar_innodb_log_file_size
MYSQL_INNODB_LOG_FILE_SIZE=128M
# InnoDB flush log at transaction commit
# Default is 2 (flush to OS cache, sync every second)
# Options: 0 (no flush), 1 (flush and sync), 2 (flush to OS cache)
# Reference: https://dev.mysql.com/doc/refman/8.0/en/innodb-parameters.html#sysvar_innodb_flush_log_at_trx_commit
MYSQL_INNODB_FLUSH_LOG_AT_TRX_COMMIT=2
# ------------------------------ # ------------------------------
# Redis Configuration # Redis Configuration
# This Redis configuration is used for caching and for pub/sub during conversation. # This Redis configuration is used for caching and for pub/sub during conversation.
@@ -339,19 +250,7 @@ REDIS_PORT=6379
REDIS_USERNAME= REDIS_USERNAME=
REDIS_PASSWORD=difyai123456 REDIS_PASSWORD=difyai123456
REDIS_USE_SSL=false REDIS_USE_SSL=false
# SSL configuration for Redis (when REDIS_USE_SSL=true)
REDIS_SSL_CERT_REQS=CERT_NONE
# Options: CERT_NONE, CERT_OPTIONAL, CERT_REQUIRED
REDIS_SSL_CA_CERTS=
# Path to CA certificate file for SSL verification
REDIS_SSL_CERTFILE=
# Path to client certificate file for SSL authentication
REDIS_SSL_KEYFILE=
# Path to client private key file for SSL authentication
REDIS_DB=0 REDIS_DB=0
# Optional: limit total Redis connections used by API/Worker (unset for default)
# Align with API's REDIS_MAX_CONNECTIONS in configs
REDIS_MAX_CONNECTIONS=
# Whether to use Redis Sentinel mode. # Whether to use Redis Sentinel mode.
# If set to true, the application will automatically discover and connect to the master node through Sentinel. # If set to true, the application will automatically discover and connect to the master node through Sentinel.
@@ -375,23 +274,18 @@ REDIS_CLUSTERS_PASSWORD=
# Celery Configuration # Celery Configuration
# ------------------------------ # ------------------------------
# Use standalone redis as the broker, and redis db 1 for celery broker. (redis_username is usually set by default as empty) # Use redis as the broker, and redis db 1 for celery broker.
# Format as follows: `redis://<redis_username>:<redis_password>@<redis_host>:<redis_port>/<redis_database>`. # Format as follows: `redis://<redis_username>:<redis_password>@<redis_host>:<redis_port>/<redis_database>`
# Example: redis://:difyai123456@redis:6379/1 # Example: redis://:difyai123456@redis:6379/1
# If use Redis Sentinel, format as follows: `sentinel://<redis_username>:<redis_password>@<sentinel_host1>:<sentinel_port>/<redis_database>` # If use Redis Sentinel, format as follows: `sentinel://<sentinel_username>:<sentinel_password>@<sentinel_host>:<sentinel_port>/<redis_database>`
# For high availability, you can configure multiple Sentinel nodes (if provided) separated by semicolons like below example: # Example: sentinel://localhost:26379/1;sentinel://localhost:26380/1;sentinel://localhost:26381/1
# Example: sentinel://:difyai123456@localhost:26379/1;sentinel://:difyai12345@localhost:26379/1;sentinel://:difyai12345@localhost:26379/1
CELERY_BROKER_URL=redis://:difyai123456@redis:6379/1 CELERY_BROKER_URL=redis://:difyai123456@redis:6379/1
CELERY_BACKEND=redis
BROKER_USE_SSL=false BROKER_USE_SSL=false
# If you are using Redis Sentinel for high availability, configure the following settings. # If you are using Redis Sentinel for high availability, configure the following settings.
CELERY_USE_SENTINEL=false CELERY_USE_SENTINEL=false
CELERY_SENTINEL_MASTER_NAME= CELERY_SENTINEL_MASTER_NAME=
CELERY_SENTINEL_PASSWORD=
CELERY_SENTINEL_SOCKET_TIMEOUT=0.1 CELERY_SENTINEL_SOCKET_TIMEOUT=0.1
# e.g. {"tasks.add": {"rate_limit": "10/s"}}
CELERY_TASK_ANNOTATIONS=null
# ------------------------------ # ------------------------------
# CORS Configuration # CORS Configuration
@@ -405,11 +299,6 @@ WEB_API_CORS_ALLOW_ORIGINS=*
# Specifies the allowed origins for cross-origin requests to the console API, # Specifies the allowed origins for cross-origin requests to the console API,
# e.g. https://cloud.dify.ai or * for all origins. # e.g. https://cloud.dify.ai or * for all origins.
CONSOLE_CORS_ALLOW_ORIGINS=* CONSOLE_CORS_ALLOW_ORIGINS=*
# When the frontend and backend run on different subdomains, set COOKIE_DOMAIN to the site's top-level domain (e.g., `example.com`). Leading dots are optional.
COOKIE_DOMAIN=
# When the frontend and backend run on different subdomains, set NEXT_PUBLIC_COOKIE_DOMAIN=1.
NEXT_PUBLIC_COOKIE_DOMAIN=
NEXT_PUBLIC_BATCH_CONCURRENCY=5
# ------------------------------ # ------------------------------
# File Storage Configuration # File Storage Configuration
@@ -427,25 +316,6 @@ OPENDAL_SCHEME=fs
# Configurations for OpenDAL Local File System. # Configurations for OpenDAL Local File System.
OPENDAL_FS_ROOT=storage OPENDAL_FS_ROOT=storage
# ClickZetta Volume Configuration (for storage backend)
# To use ClickZetta Volume as storage backend, set STORAGE_TYPE=clickzetta-volume
# Note: ClickZetta Volume will reuse the existing CLICKZETTA_* connection parameters
# Volume type selection (three types available):
# - user: Personal/small team use, simple config, user-level permissions
# - table: Enterprise multi-tenant, smart routing, table-level + user-level permissions
# - external: Data lake integration, external storage connection, volume-level + storage-level permissions
CLICKZETTA_VOLUME_TYPE=user
# External Volume name (required only when TYPE=external)
CLICKZETTA_VOLUME_NAME=
# Table Volume table prefix (used only when TYPE=table)
CLICKZETTA_VOLUME_TABLE_PREFIX=dataset_
# Dify file directory prefix (isolates from other apps, recommended to keep default)
CLICKZETTA_VOLUME_DIFY_PREFIX=dify_km
# S3 Configuration # S3 Configuration
# #
S3_ENDPOINT= S3_ENDPOINT=
@@ -457,15 +327,6 @@ S3_SECRET_KEY=
# If set to false, the access key and secret key must be provided. # If set to false, the access key and secret key must be provided.
S3_USE_AWS_MANAGED_IAM=false S3_USE_AWS_MANAGED_IAM=false
# Workflow run and Conversation archive storage (S3-compatible)
ARCHIVE_STORAGE_ENABLED=false
ARCHIVE_STORAGE_ENDPOINT=
ARCHIVE_STORAGE_ARCHIVE_BUCKET=
ARCHIVE_STORAGE_EXPORT_BUCKET=
ARCHIVE_STORAGE_ACCESS_KEY=
ARCHIVE_STORAGE_SECRET_KEY=
ARCHIVE_STORAGE_REGION=auto
# Azure Blob Configuration # Azure Blob Configuration
# #
AZURE_BLOB_ACCOUNT_NAME=difyai AZURE_BLOB_ACCOUNT_NAME=difyai
@@ -488,7 +349,6 @@ ALIYUN_OSS_REGION=ap-southeast-1
ALIYUN_OSS_AUTH_VERSION=v4 ALIYUN_OSS_AUTH_VERSION=v4
# Don't start with '/'. OSS doesn't support leading slash in object names. # Don't start with '/'. OSS doesn't support leading slash in object names.
ALIYUN_OSS_PATH=your-path ALIYUN_OSS_PATH=your-path
ALIYUN_CLOUDBOX_ID=your-cloudbox-id
# Tencent COS Configuration # Tencent COS Configuration
# #
@@ -497,7 +357,6 @@ TENCENT_COS_SECRET_KEY=your-secret-key
TENCENT_COS_SECRET_ID=your-secret-id TENCENT_COS_SECRET_ID=your-secret-id
TENCENT_COS_REGION=your-region TENCENT_COS_REGION=your-region
TENCENT_COS_SCHEME=your-scheme TENCENT_COS_SCHEME=your-scheme
TENCENT_COS_CUSTOM_DOMAIN=your-custom-domain
# Oracle Storage Configuration # Oracle Storage Configuration
# #
@@ -513,7 +372,6 @@ HUAWEI_OBS_BUCKET_NAME=your-bucket-name
HUAWEI_OBS_SECRET_KEY=your-secret-key HUAWEI_OBS_SECRET_KEY=your-secret-key
HUAWEI_OBS_ACCESS_KEY=your-access-key HUAWEI_OBS_ACCESS_KEY=your-access-key
HUAWEI_OBS_SERVER=your-server-url HUAWEI_OBS_SERVER=your-server-url
HUAWEI_OBS_PATH_STYLE=false
# Volcengine TOS Configuration # Volcengine TOS Configuration
# #
@@ -541,33 +399,12 @@ SUPABASE_URL=your-server-url
# ------------------------------ # ------------------------------
# The type of vector store to use. # The type of vector store to use.
# Supported values are `weaviate`, `oceanbase`, `seekdb`, `qdrant`, `milvus`, `myscale`, `relyt`, `pgvector`, `pgvecto-rs`, `chroma`, `opensearch`, `oracle`, `tencent`, `elasticsearch`, `elasticsearch-ja`, `analyticdb`, `couchbase`, `vikingdb`, `opengauss`, `tablestore`, `vastbase`, `tidb`, `tidb_on_qdrant`, `baidu`, `lindorm`, `huawei_cloud`, `upstash`, `matrixone`, `clickzetta`, `alibabacloud_mysql`, `iris`. # Supported values are `weaviate`, `qdrant`, `milvus`, `myscale`, `relyt`, `pgvector`, `pgvecto-rs`, `chroma`, `opensearch`, `oracle`, `tencent`, `elasticsearch`, `elasticsearch-ja`, `analyticdb`, `couchbase`, `vikingdb`, `oceanbase`, `opengauss`, `tablestore`,`vastbase`,`tidb`,`tidb_on_qdrant`,`baidu`,`lindorm`,`huawei_cloud`,`upstash`.
VECTOR_STORE=weaviate VECTOR_STORE=weaviate
# Prefix used to create collection name in vector database
VECTOR_INDEX_NAME_PREFIX=Vector_index
# The Weaviate endpoint URL. Only available when VECTOR_STORE is `weaviate`. # The Weaviate endpoint URL. Only available when VECTOR_STORE is `weaviate`.
WEAVIATE_ENDPOINT=http://weaviate:8080 WEAVIATE_ENDPOINT=http://weaviate:8080
WEAVIATE_API_KEY=WVF5YThaHlkYwhGUSmCRgsX3tD5ngdN8pkih WEAVIATE_API_KEY=WVF5YThaHlkYwhGUSmCRgsX3tD5ngdN8pkih
WEAVIATE_GRPC_ENDPOINT=grpc://weaviate:50051
WEAVIATE_TOKENIZATION=word
# For OceanBase metadata database configuration, available when `DB_TYPE` is `oceanbase`.
# For OceanBase vector database configuration, available when `VECTOR_STORE` is `oceanbase`
# If you want to use OceanBase as both vector database and metadata database, you need to set both `DB_TYPE` and `VECTOR_STORE` to `oceanbase`, and set Database Configuration is the same as the vector database.
# seekdb is the lite version of OceanBase and shares the connection configuration with OceanBase.
OCEANBASE_VECTOR_HOST=oceanbase
OCEANBASE_VECTOR_PORT=2881
OCEANBASE_VECTOR_USER=root@test
OCEANBASE_VECTOR_PASSWORD=difyai123456
OCEANBASE_VECTOR_DATABASE=test
OCEANBASE_CLUSTER_NAME=difyai
OCEANBASE_MEMORY_LIMIT=6G
OCEANBASE_ENABLE_HYBRID_SEARCH=false
# For OceanBase vector database, built-in fulltext parsers are `ngram`, `beng`, `space`, `ngram2`, `ik`
# For OceanBase vector database, external fulltext parsers (require plugin installation) are `japanese_ftparser`, `thai_ftparser`
OCEANBASE_FULLTEXT_PARSER=ik
SEEKDB_MEMORY_LIMIT=2G
# The Qdrant endpoint URL. Only available when VECTOR_STORE is `qdrant`. # The Qdrant endpoint URL. Only available when VECTOR_STORE is `qdrant`.
QDRANT_URL=http://qdrant:6333 QDRANT_URL=http://qdrant:6333
@@ -575,7 +412,6 @@ QDRANT_API_KEY=difyai123456
QDRANT_CLIENT_TIMEOUT=20 QDRANT_CLIENT_TIMEOUT=20
QDRANT_GRPC_ENABLED=false QDRANT_GRPC_ENABLED=false
QDRANT_GRPC_PORT=6334 QDRANT_GRPC_PORT=6334
QDRANT_REPLICATION_FACTOR=1
# Milvus configuration. Only available when VECTOR_STORE is `milvus`. # Milvus configuration. Only available when VECTOR_STORE is `milvus`.
# The milvus uri. # The milvus uri.
@@ -653,13 +489,6 @@ TIDB_VECTOR_USER=
TIDB_VECTOR_PASSWORD= TIDB_VECTOR_PASSWORD=
TIDB_VECTOR_DATABASE=dify TIDB_VECTOR_DATABASE=dify
# Matrixone vector configurations.
MATRIXONE_HOST=matrixone
MATRIXONE_PORT=6001
MATRIXONE_USER=dump
MATRIXONE_PASSWORD=111
MATRIXONE_DATABASE=dify
# Tidb on qdrant configuration, only available when VECTOR_STORE is `tidb_on_qdrant` # Tidb on qdrant configuration, only available when VECTOR_STORE is `tidb_on_qdrant`
TIDB_ON_QDRANT_URL=http://127.0.0.1 TIDB_ON_QDRANT_URL=http://127.0.0.1
TIDB_ON_QDRANT_API_KEY=dify TIDB_ON_QDRANT_API_KEY=dify
@@ -691,15 +520,6 @@ ORACLE_WALLET_LOCATION=/app/api/storage/wallet
ORACLE_WALLET_PASSWORD=dify ORACLE_WALLET_PASSWORD=dify
ORACLE_IS_AUTONOMOUS=false ORACLE_IS_AUTONOMOUS=false
# AlibabaCloud MySQL configuration, only available when VECTOR_STORE is `alibabcloud_mysql`
ALIBABACLOUD_MYSQL_HOST=127.0.0.1
ALIBABACLOUD_MYSQL_PORT=3306
ALIBABACLOUD_MYSQL_USER=root
ALIBABACLOUD_MYSQL_PASSWORD=difyai123456
ALIBABACLOUD_MYSQL_DATABASE=dify
ALIBABACLOUD_MYSQL_MAX_CONNECTION=5
ALIBABACLOUD_MYSQL_HNSW_M=6
# relyt configurations, only available when VECTOR_STORE is `relyt` # relyt configurations, only available when VECTOR_STORE is `relyt`
RELYT_HOST=db RELYT_HOST=db
RELYT_PORT=5432 RELYT_PORT=5432
@@ -711,7 +531,6 @@ RELYT_DATABASE=postgres
OPENSEARCH_HOST=opensearch OPENSEARCH_HOST=opensearch
OPENSEARCH_PORT=9200 OPENSEARCH_PORT=9200
OPENSEARCH_SECURE=true OPENSEARCH_SECURE=true
OPENSEARCH_VERIFY_CERTS=true
OPENSEARCH_AUTH_METHOD=basic OPENSEARCH_AUTH_METHOD=basic
OPENSEARCH_USER=admin OPENSEARCH_USER=admin
OPENSEARCH_PASSWORD=admin OPENSEARCH_PASSWORD=admin
@@ -736,17 +555,6 @@ ELASTICSEARCH_USERNAME=elastic
ELASTICSEARCH_PASSWORD=elastic ELASTICSEARCH_PASSWORD=elastic
KIBANA_PORT=5601 KIBANA_PORT=5601
# Using ElasticSearch Cloud Serverless, or not.
ELASTICSEARCH_USE_CLOUD=false
ELASTICSEARCH_CLOUD_URL=YOUR-ELASTICSEARCH_CLOUD_URL
ELASTICSEARCH_API_KEY=YOUR-ELASTICSEARCH_API_KEY
ELASTICSEARCH_VERIFY_CERTS=False
ELASTICSEARCH_CA_CERTS=
ELASTICSEARCH_REQUEST_TIMEOUT=100000
ELASTICSEARCH_RETRY_ON_TIMEOUT=True
ELASTICSEARCH_MAX_RETRIES=10
# baidu vector configurations, only available when VECTOR_STORE is `baidu` # baidu vector configurations, only available when VECTOR_STORE is `baidu`
BAIDU_VECTOR_DB_ENDPOINT=http://127.0.0.1:5287 BAIDU_VECTOR_DB_ENDPOINT=http://127.0.0.1:5287
BAIDU_VECTOR_DB_CONNECTION_TIMEOUT_MS=30000 BAIDU_VECTOR_DB_CONNECTION_TIMEOUT_MS=30000
@@ -755,8 +563,6 @@ BAIDU_VECTOR_DB_API_KEY=dify
BAIDU_VECTOR_DB_DATABASE=dify BAIDU_VECTOR_DB_DATABASE=dify
BAIDU_VECTOR_DB_SHARD=1 BAIDU_VECTOR_DB_SHARD=1
BAIDU_VECTOR_DB_REPLICAS=3 BAIDU_VECTOR_DB_REPLICAS=3
BAIDU_VECTOR_DB_INVERTED_INDEX_ANALYZER=DEFAULT_ANALYZER
BAIDU_VECTOR_DB_INVERTED_INDEX_PARSER_MODE=COARSE_MODE
# VikingDB configurations, only available when VECTOR_STORE is `vikingdb` # VikingDB configurations, only available when VECTOR_STORE is `vikingdb`
VIKINGDB_ACCESS_KEY=your-ak VIKINGDB_ACCESS_KEY=your-ak
@@ -768,12 +574,21 @@ VIKINGDB_CONNECTION_TIMEOUT=30
VIKINGDB_SOCKET_TIMEOUT=30 VIKINGDB_SOCKET_TIMEOUT=30
# Lindorm configuration, only available when VECTOR_STORE is `lindorm` # Lindorm configuration, only available when VECTOR_STORE is `lindorm`
LINDORM_URL=http://localhost:30070 LINDORM_URL=http://lindorm:30070
LINDORM_USERNAME=admin LINDORM_USERNAME=lindorm
LINDORM_PASSWORD=admin LINDORM_PASSWORD=lindorm
LINDORM_USING_UGC=True
LINDORM_QUERY_TIMEOUT=1 LINDORM_QUERY_TIMEOUT=1
# OceanBase Vector configuration, only available when VECTOR_STORE is `oceanbase`
OCEANBASE_VECTOR_HOST=oceanbase
OCEANBASE_VECTOR_PORT=2881
OCEANBASE_VECTOR_USER=root@test
OCEANBASE_VECTOR_PASSWORD=difyai123456
OCEANBASE_VECTOR_DATABASE=test
OCEANBASE_CLUSTER_NAME=difyai
OCEANBASE_MEMORY_LIMIT=6G
OCEANBASE_ENABLE_HYBRID_SEARCH=false
# opengauss configurations, only available when VECTOR_STORE is `opengauss` # opengauss configurations, only available when VECTOR_STORE is `opengauss`
OPENGAUSS_HOST=opengauss OPENGAUSS_HOST=opengauss
OPENGAUSS_PORT=6600 OPENGAUSS_PORT=6600
@@ -799,36 +614,6 @@ TABLESTORE_ENDPOINT=https://instance-name.cn-hangzhou.ots.aliyuncs.com
TABLESTORE_INSTANCE_NAME=instance-name TABLESTORE_INSTANCE_NAME=instance-name
TABLESTORE_ACCESS_KEY_ID=xxx TABLESTORE_ACCESS_KEY_ID=xxx
TABLESTORE_ACCESS_KEY_SECRET=xxx TABLESTORE_ACCESS_KEY_SECRET=xxx
TABLESTORE_NORMALIZE_FULLTEXT_BM25_SCORE=false
# Clickzetta configuration, only available when VECTOR_STORE is `clickzetta`
CLICKZETTA_USERNAME=
CLICKZETTA_PASSWORD=
CLICKZETTA_INSTANCE=
CLICKZETTA_SERVICE=api.clickzetta.com
CLICKZETTA_WORKSPACE=quick_start
CLICKZETTA_VCLUSTER=default_ap
CLICKZETTA_SCHEMA=dify
CLICKZETTA_BATCH_SIZE=100
CLICKZETTA_ENABLE_INVERTED_INDEX=true
CLICKZETTA_ANALYZER_TYPE=chinese
CLICKZETTA_ANALYZER_MODE=smart
CLICKZETTA_VECTOR_DISTANCE_FUNCTION=cosine_distance
# InterSystems IRIS configuration, only available when VECTOR_STORE is `iris`
IRIS_HOST=iris
IRIS_SUPER_SERVER_PORT=1972
IRIS_WEB_SERVER_PORT=52773
IRIS_USER=_SYSTEM
IRIS_PASSWORD=Dify@1234
IRIS_DATABASE=USER
IRIS_SCHEMA=dify
IRIS_CONNECTION_URL=
IRIS_MIN_CONNECTION=1
IRIS_MAX_CONNECTION=3
IRIS_TEXT_INDEX=true
IRIS_TEXT_INDEX_LANGUAGE=en
IRIS_TIMEZONE=UTC
# ------------------------------ # ------------------------------
# Knowledge Configuration # Knowledge Configuration
@@ -840,25 +625,6 @@ UPLOAD_FILE_SIZE_LIMIT=15
# The maximum number of files that can be uploaded at a time, default 5. # The maximum number of files that can be uploaded at a time, default 5.
UPLOAD_FILE_BATCH_LIMIT=5 UPLOAD_FILE_BATCH_LIMIT=5
# Comma-separated list of file extensions blocked from upload for security reasons.
# Extensions should be lowercase without dots (e.g., exe,bat,sh,dll).
# Empty by default to allow all file types.
# Recommended: exe,bat,cmd,com,scr,vbs,ps1,msi,dll
UPLOAD_FILE_EXTENSION_BLACKLIST=
# Maximum number of files allowed in a single chunk attachment, default 10.
SINGLE_CHUNK_ATTACHMENT_LIMIT=10
# Maximum number of files allowed in a image batch upload operation
IMAGE_FILE_BATCH_LIMIT=10
# Maximum allowed image file size for attachments in megabytes, default 2.
ATTACHMENT_IMAGE_FILE_SIZE_LIMIT=2
# Timeout for downloading image attachments in seconds, default 60.
ATTACHMENT_IMAGE_DOWNLOAD_TIMEOUT=60
# ETL type, support: `dify`, `Unstructured` # ETL type, support: `dify`, `Unstructured`
# `dify` Dify's proprietary file extraction scheme # `dify` Dify's proprietary file extraction scheme
# `Unstructured` Unstructured.io file extraction scheme # `Unstructured` Unstructured.io file extraction scheme
@@ -929,12 +695,6 @@ API_SENTRY_PROFILES_SAMPLE_RATE=1.0
# If not set, Sentry error reporting will be disabled. # If not set, Sentry error reporting will be disabled.
WEB_SENTRY_DSN= WEB_SENTRY_DSN=
# Plugin_daemon Service Sentry DSN address, default is empty, when empty,
# all monitoring information is not reported to Sentry.
# If not set, Sentry error reporting will be disabled.
PLUGIN_SENTRY_ENABLED=false
PLUGIN_SENTRY_DSN=
# ------------------------------ # ------------------------------
# Notion Integration Configuration # Notion Integration Configuration
# Variables can be obtained by applying for Notion integration: https://www.notion.so/my-integrations # Variables can be obtained by applying for Notion integration: https://www.notion.so/my-integrations
@@ -957,11 +717,10 @@ NOTION_INTERNAL_SECRET=
# Mail related configuration # Mail related configuration
# ------------------------------ # ------------------------------
# Mail type, support: resend, smtp, sendgrid # Mail type, support: resend, smtp
MAIL_TYPE=resend MAIL_TYPE=resend
# Default send from email address, if not specified # Default send from email address, if not specified
# If using SendGrid, use the 'from' field for authentication if necessary.
MAIL_DEFAULT_SEND_FROM= MAIL_DEFAULT_SEND_FROM=
# API-Key for the Resend email provider, used when MAIL_TYPE is `resend`. # API-Key for the Resend email provider, used when MAIL_TYPE is `resend`.
@@ -976,11 +735,6 @@ SMTP_USERNAME=
SMTP_PASSWORD= SMTP_PASSWORD=
SMTP_USE_TLS=true SMTP_USE_TLS=true
SMTP_OPPORTUNISTIC_TLS=false SMTP_OPPORTUNISTIC_TLS=false
# Optional: override the local hostname used for SMTP HELO/EHLO
SMTP_LOCAL_HOSTNAME=
# Sendgid configuration
SENDGRID_API_KEY=
# ------------------------------ # ------------------------------
# Others Configuration # Others Configuration
@@ -995,140 +749,42 @@ INVITE_EXPIRY_HOURS=72
# Reset password token valid time (minutes), # Reset password token valid time (minutes),
RESET_PASSWORD_TOKEN_EXPIRY_MINUTES=5 RESET_PASSWORD_TOKEN_EXPIRY_MINUTES=5
EMAIL_REGISTER_TOKEN_EXPIRY_MINUTES=5
CHANGE_EMAIL_TOKEN_EXPIRY_MINUTES=5
OWNER_TRANSFER_TOKEN_EXPIRY_MINUTES=5
# The sandbox service endpoint. # The sandbox service endpoint.
CODE_EXECUTION_ENDPOINT=http://sandbox:8194 CODE_EXECUTION_ENDPOINT=http://sandbox:8194
CODE_EXECUTION_API_KEY=dify-sandbox CODE_EXECUTION_API_KEY=dify-sandbox
CODE_EXECUTION_SSL_VERIFY=True
CODE_EXECUTION_POOL_MAX_CONNECTIONS=100
CODE_EXECUTION_POOL_MAX_KEEPALIVE_CONNECTIONS=20
CODE_EXECUTION_POOL_KEEPALIVE_EXPIRY=5.0
CODE_MAX_NUMBER=9223372036854775807 CODE_MAX_NUMBER=9223372036854775807
CODE_MIN_NUMBER=-9223372036854775808 CODE_MIN_NUMBER=-9223372036854775808
CODE_MAX_DEPTH=5 CODE_MAX_DEPTH=5
CODE_MAX_PRECISION=20 CODE_MAX_PRECISION=20
CODE_MAX_STRING_LENGTH=400000 CODE_MAX_STRING_LENGTH=80000
CODE_MAX_STRING_ARRAY_LENGTH=30 CODE_MAX_STRING_ARRAY_LENGTH=30
CODE_MAX_OBJECT_ARRAY_LENGTH=30 CODE_MAX_OBJECT_ARRAY_LENGTH=30
CODE_MAX_NUMBER_ARRAY_LENGTH=1000 CODE_MAX_NUMBER_ARRAY_LENGTH=1000
CODE_EXECUTION_CONNECT_TIMEOUT=10 CODE_EXECUTION_CONNECT_TIMEOUT=10
CODE_EXECUTION_READ_TIMEOUT=60 CODE_EXECUTION_READ_TIMEOUT=60
CODE_EXECUTION_WRITE_TIMEOUT=10 CODE_EXECUTION_WRITE_TIMEOUT=10
TEMPLATE_TRANSFORM_MAX_LENGTH=400000 TEMPLATE_TRANSFORM_MAX_LENGTH=80000
# Workflow runtime configuration # Workflow runtime configuration
WORKFLOW_MAX_EXECUTION_STEPS=500 WORKFLOW_MAX_EXECUTION_STEPS=500
WORKFLOW_MAX_EXECUTION_TIME=1200 WORKFLOW_MAX_EXECUTION_TIME=1200
WORKFLOW_CALL_MAX_DEPTH=5 WORKFLOW_CALL_MAX_DEPTH=5
MAX_VARIABLE_SIZE=204800 MAX_VARIABLE_SIZE=204800
WORKFLOW_PARALLEL_DEPTH_LIMIT=3
WORKFLOW_FILE_UPLOAD_LIMIT=10 WORKFLOW_FILE_UPLOAD_LIMIT=10
# GraphEngine Worker Pool Configuration
# Minimum number of workers per GraphEngine instance (default: 1)
GRAPH_ENGINE_MIN_WORKERS=1
# Maximum number of workers per GraphEngine instance (default: 10)
GRAPH_ENGINE_MAX_WORKERS=10
# Queue depth threshold that triggers worker scale up (default: 3)
GRAPH_ENGINE_SCALE_UP_THRESHOLD=3
# Seconds of idle time before scaling down workers (default: 5.0)
GRAPH_ENGINE_SCALE_DOWN_IDLE_TIME=5.0
# Workflow storage configuration # Workflow storage configuration
# Options: rdbms, hybrid # Options: rdbms, hybrid
# rdbms: Use only the relational database (default) # rdbms: Use only the relational database (default)
# hybrid: Save new data to object storage, read from both object storage and RDBMS # hybrid: Save new data to object storage, read from both object storage and RDBMS
WORKFLOW_NODE_EXECUTION_STORAGE=rdbms WORKFLOW_NODE_EXECUTION_STORAGE=rdbms
# Repository configuration
# Core workflow execution repository implementation
# Options:
# - core.repositories.sqlalchemy_workflow_execution_repository.SQLAlchemyWorkflowExecutionRepository (default)
# - core.repositories.celery_workflow_execution_repository.CeleryWorkflowExecutionRepository
# - extensions.logstore.repositories.logstore_workflow_execution_repository.LogstoreWorkflowExecutionRepository
CORE_WORKFLOW_EXECUTION_REPOSITORY=core.repositories.sqlalchemy_workflow_execution_repository.SQLAlchemyWorkflowExecutionRepository
# Core workflow node execution repository implementation
# Options:
# - core.repositories.sqlalchemy_workflow_node_execution_repository.SQLAlchemyWorkflowNodeExecutionRepository (default)
# - core.repositories.celery_workflow_node_execution_repository.CeleryWorkflowNodeExecutionRepository
# - extensions.logstore.repositories.logstore_workflow_node_execution_repository.LogstoreWorkflowNodeExecutionRepository
CORE_WORKFLOW_NODE_EXECUTION_REPOSITORY=core.repositories.sqlalchemy_workflow_node_execution_repository.SQLAlchemyWorkflowNodeExecutionRepository
# API workflow run repository implementation
# Options:
# - repositories.sqlalchemy_api_workflow_run_repository.DifyAPISQLAlchemyWorkflowRunRepository (default)
# - extensions.logstore.repositories.logstore_api_workflow_run_repository.LogstoreAPIWorkflowRunRepository
API_WORKFLOW_RUN_REPOSITORY=repositories.sqlalchemy_api_workflow_run_repository.DifyAPISQLAlchemyWorkflowRunRepository
# API workflow node execution repository implementation
# Options:
# - repositories.sqlalchemy_api_workflow_node_execution_repository.DifyAPISQLAlchemyWorkflowNodeExecutionRepository (default)
# - extensions.logstore.repositories.logstore_api_workflow_node_execution_repository.LogstoreAPIWorkflowNodeExecutionRepository
API_WORKFLOW_NODE_EXECUTION_REPOSITORY=repositories.sqlalchemy_api_workflow_node_execution_repository.DifyAPISQLAlchemyWorkflowNodeExecutionRepository
# Workflow log cleanup configuration
# Enable automatic cleanup of workflow run logs to manage database size
WORKFLOW_LOG_CLEANUP_ENABLED=false
# Number of days to retain workflow run logs (default: 30 days)
WORKFLOW_LOG_RETENTION_DAYS=30
# Batch size for workflow log cleanup operations (default: 100)
WORKFLOW_LOG_CLEANUP_BATCH_SIZE=100
# Comma-separated list of workflow IDs to clean logs for
WORKFLOW_LOG_CLEANUP_SPECIFIC_WORKFLOW_IDS=
# Aliyun SLS Logstore Configuration
# Aliyun Access Key ID
ALIYUN_SLS_ACCESS_KEY_ID=
# Aliyun Access Key Secret
ALIYUN_SLS_ACCESS_KEY_SECRET=
# Aliyun SLS Endpoint (e.g., cn-hangzhou.log.aliyuncs.com)
ALIYUN_SLS_ENDPOINT=
# Aliyun SLS Region (e.g., cn-hangzhou)
ALIYUN_SLS_REGION=
# Aliyun SLS Project Name
ALIYUN_SLS_PROJECT_NAME=
# Number of days to retain workflow run logs (default: 365 days, 3650 for permanent storage)
ALIYUN_SLS_LOGSTORE_TTL=365
# Enable dual-write to both SLS LogStore and SQL database (default: false)
LOGSTORE_DUAL_WRITE_ENABLED=false
# Enable dual-read fallback to SQL database when LogStore returns no results (default: true)
# Useful for migration scenarios where historical data exists only in SQL database
LOGSTORE_DUAL_READ_ENABLED=true
# Control flag for whether to write the `graph` field to LogStore.
# If LOGSTORE_ENABLE_PUT_GRAPH_FIELD is "true", write the full `graph` field;
# otherwise write an empty {} instead. Defaults to writing the `graph` field.
LOGSTORE_ENABLE_PUT_GRAPH_FIELD=true
# HTTP request node in workflow configuration # HTTP request node in workflow configuration
HTTP_REQUEST_NODE_MAX_BINARY_SIZE=10485760 HTTP_REQUEST_NODE_MAX_BINARY_SIZE=10485760
HTTP_REQUEST_NODE_MAX_TEXT_SIZE=1048576 HTTP_REQUEST_NODE_MAX_TEXT_SIZE=1048576
HTTP_REQUEST_NODE_SSL_VERIFY=True HTTP_REQUEST_NODE_SSL_VERIFY=True
# HTTP request node timeout configuration
# Maximum timeout values (in seconds) that users can set in HTTP request nodes
# - Connect timeout: Time to wait for establishing connection (default: 10s)
# - Read timeout: Time to wait for receiving response data (default: 600s, 10 minutes)
# - Write timeout: Time to wait for sending request data (default: 600s, 10 minutes)
HTTP_REQUEST_MAX_CONNECT_TIMEOUT=10
HTTP_REQUEST_MAX_READ_TIMEOUT=600
HTTP_REQUEST_MAX_WRITE_TIMEOUT=600
# Base64 encoded CA certificate data for custom certificate verification (PEM format, optional)
# HTTP_REQUEST_NODE_SSL_CERT_DATA=LS0tLS1CRUdJTi...
# Base64 encoded client certificate data for mutual TLS authentication (PEM format, optional)
# HTTP_REQUEST_NODE_SSL_CLIENT_CERT_DATA=LS0tLS1CRUdJTi...
# Base64 encoded client private key data for mutual TLS authentication (PEM format, optional)
# HTTP_REQUEST_NODE_SSL_CLIENT_KEY_DATA=LS0tLS1CRUdJTi...
# Webhook request configuration
WEBHOOK_REQUEST_BODY_MAX_SIZE=10485760
# Respect X-* headers to redirect clients
RESPECT_XFORWARD_HEADERS_ENABLED=false
# SSRF Proxy server HTTP URL # SSRF Proxy server HTTP URL
SSRF_PROXY_HTTP_URL=http://ssrf_proxy:3128 SSRF_PROXY_HTTP_URL=http://ssrf_proxy:3128
# SSRF Proxy server HTTPS URL # SSRF Proxy server HTTPS URL
@@ -1144,7 +800,7 @@ MAX_TOOLS_NUM=10
MAX_PARALLEL_LIMIT=10 MAX_PARALLEL_LIMIT=10
# The maximum number of iterations for agent setting # The maximum number of iterations for agent setting
MAX_ITERATIONS_NUM=99 MAX_ITERATIONS_NUM=5
# ------------------------------ # ------------------------------
# Environment Variables for web Service # Environment Variables for web Service
@@ -1153,21 +809,18 @@ MAX_ITERATIONS_NUM=99
# The timeout for the text generation in millisecond # The timeout for the text generation in millisecond
TEXT_GENERATION_TIMEOUT_MS=60000 TEXT_GENERATION_TIMEOUT_MS=60000
# Allow rendering unsafe URLs which have "data:" scheme.
ALLOW_UNSAFE_DATA_SCHEME=false
# Maximum number of tree depth in the workflow
MAX_TREE_DEPTH=50
# ------------------------------ # ------------------------------
# Environment Variables for database Service # Environment Variables for db Service
# ------------------------------ # ------------------------------
# Postgres data directory
PGUSER=${DB_USERNAME}
# The password for the default postgres user.
POSTGRES_PASSWORD=${DB_PASSWORD}
# The name of the default postgres database.
POSTGRES_DB=${DB_DATABASE}
# postgres data directory
PGDATA=/var/lib/postgresql/data/pgdata PGDATA=/var/lib/postgresql/data/pgdata
# MySQL Default Configuration
MYSQL_HOST_VOLUME=./volumes/mysql/data
# ------------------------------ # ------------------------------
# Environment Variables for sandbox Service # Environment Variables for sandbox Service
# ------------------------------ # ------------------------------
@@ -1201,10 +854,6 @@ WEAVIATE_AUTHENTICATION_APIKEY_ALLOWED_KEYS=WVF5YThaHlkYwhGUSmCRgsX3tD5ngdN8pkih
WEAVIATE_AUTHENTICATION_APIKEY_USERS=hello@dify.ai WEAVIATE_AUTHENTICATION_APIKEY_USERS=hello@dify.ai
WEAVIATE_AUTHORIZATION_ADMINLIST_ENABLED=true WEAVIATE_AUTHORIZATION_ADMINLIST_ENABLED=true
WEAVIATE_AUTHORIZATION_ADMINLIST_USERS=hello@dify.ai WEAVIATE_AUTHORIZATION_ADMINLIST_USERS=hello@dify.ai
WEAVIATE_DISABLE_TELEMETRY=false
WEAVIATE_ENABLE_TOKENIZER_GSE=false
WEAVIATE_ENABLE_TOKENIZER_KAGOME_JA=false
WEAVIATE_ENABLE_TOKENIZER_KAGOME_KR=false
# ------------------------------ # ------------------------------
# Environment Variables for Chroma # Environment Variables for Chroma
@@ -1287,11 +936,11 @@ NGINX_SSL_PORT=443
# and modify the env vars below accordingly. # and modify the env vars below accordingly.
NGINX_SSL_CERT_FILENAME=dify.crt NGINX_SSL_CERT_FILENAME=dify.crt
NGINX_SSL_CERT_KEY_FILENAME=dify.key NGINX_SSL_CERT_KEY_FILENAME=dify.key
NGINX_SSL_PROTOCOLS=TLSv1.2 TLSv1.3 NGINX_SSL_PROTOCOLS=TLSv1.1 TLSv1.2 TLSv1.3
# Nginx performance tuning # Nginx performance tuning
NGINX_WORKER_PROCESSES=auto NGINX_WORKER_PROCESSES=auto
NGINX_CLIENT_MAX_BODY_SIZE=100M NGINX_CLIENT_MAX_BODY_SIZE=15M
NGINX_KEEPALIVE_TIMEOUT=65 NGINX_KEEPALIVE_TIMEOUT=65
# Proxy settings # Proxy settings
@@ -1326,17 +975,14 @@ SSRF_DEFAULT_TIME_OUT=5
SSRF_DEFAULT_CONNECT_TIME_OUT=5 SSRF_DEFAULT_CONNECT_TIME_OUT=5
SSRF_DEFAULT_READ_TIME_OUT=5 SSRF_DEFAULT_READ_TIME_OUT=5
SSRF_DEFAULT_WRITE_TIME_OUT=5 SSRF_DEFAULT_WRITE_TIME_OUT=5
SSRF_POOL_MAX_CONNECTIONS=100
SSRF_POOL_MAX_KEEPALIVE_CONNECTIONS=20
SSRF_POOL_KEEPALIVE_EXPIRY=5.0
# ------------------------------ # ------------------------------
# docker env var for specifying vector db and metadata db type at startup # docker env var for specifying vector db type at startup
# (based on the vector db and metadata db type, the corresponding docker # (based on the vector db type, the corresponding docker
# compose profile will be used) # compose profile will be used)
# if you want to use unstructured, add ',unstructured' to the end # if you want to use unstructured, add ',unstructured' to the end
# ------------------------------ # ------------------------------
COMPOSE_PROFILES=${VECTOR_STORE:-weaviate},${DB_TYPE:-postgresql} COMPOSE_PROFILES=${VECTOR_STORE:-weaviate}
# ------------------------------ # ------------------------------
# Docker Compose Service Expose Host Port Configurations # Docker Compose Service Expose Host Port Configurations
@@ -1385,7 +1031,6 @@ PLUGIN_DAEMON_PORT=5002
PLUGIN_DAEMON_KEY=lYkiYYT6owG+71oLerGzA7GXCgOT++6ovaezWAjpCjf+Sjc3ZtU+qUEi PLUGIN_DAEMON_KEY=lYkiYYT6owG+71oLerGzA7GXCgOT++6ovaezWAjpCjf+Sjc3ZtU+qUEi
PLUGIN_DAEMON_URL=http://plugin_daemon:5002 PLUGIN_DAEMON_URL=http://plugin_daemon:5002
PLUGIN_MAX_PACKAGE_SIZE=52428800 PLUGIN_MAX_PACKAGE_SIZE=52428800
PLUGIN_MODEL_SCHEMA_CACHE_TTL=3600
PLUGIN_PPROF_ENABLED=false PLUGIN_PPROF_ENABLED=false
PLUGIN_DEBUGGING_HOST=0.0.0.0 PLUGIN_DEBUGGING_HOST=0.0.0.0
@@ -1403,21 +1048,14 @@ MARKETPLACE_ENABLED=true
MARKETPLACE_API_URL=https://marketplace.dify.ai MARKETPLACE_API_URL=https://marketplace.dify.ai
FORCE_VERIFYING_SIGNATURE=true FORCE_VERIFYING_SIGNATURE=true
ENFORCE_LANGGENIUS_PLUGIN_SIGNATURES=true
PLUGIN_STDIO_BUFFER_SIZE=1024
PLUGIN_STDIO_MAX_BUFFER_SIZE=5242880
PLUGIN_PYTHON_ENV_INIT_TIMEOUT=120 PLUGIN_PYTHON_ENV_INIT_TIMEOUT=120
# Plugin Daemon side timeout (configure to match the API side below)
PLUGIN_MAX_EXECUTION_TIMEOUT=600 PLUGIN_MAX_EXECUTION_TIMEOUT=600
# API side timeout (configure to match the Plugin Daemon side above)
PLUGIN_DAEMON_TIMEOUT=600.0
# PIP_MIRROR_URL=https://pypi.tuna.tsinghua.edu.cn/simple # PIP_MIRROR_URL=https://pypi.tuna.tsinghua.edu.cn/simple
PIP_MIRROR_URL= PIP_MIRROR_URL=
# https://github.com/langgenius/dify-plugin-daemon/blob/main/.env.example # https://github.com/langgenius/dify-plugin-daemon/blob/main/.env.example
# Plugin storage type, local aws_s3 tencent_cos azure_blob aliyun_oss volcengine_tos # Plugin storage type, local aws_s3 tencent_cos azure_blob aliyun_oss
PLUGIN_STORAGE_TYPE=local PLUGIN_STORAGE_TYPE=local
PLUGIN_STORAGE_LOCAL_ROOT=/app/storage PLUGIN_STORAGE_LOCAL_ROOT=/app/storage
PLUGIN_WORKING_PATH=/app/storage/cwd PLUGIN_WORKING_PATH=/app/storage/cwd
@@ -1427,7 +1065,6 @@ PLUGIN_MEDIA_CACHE_PATH=assets
# Plugin oss bucket # Plugin oss bucket
PLUGIN_STORAGE_OSS_BUCKET= PLUGIN_STORAGE_OSS_BUCKET=
# Plugin oss s3 credentials # Plugin oss s3 credentials
PLUGIN_S3_USE_AWS=false
PLUGIN_S3_USE_AWS_MANAGED_IAM=false PLUGIN_S3_USE_AWS_MANAGED_IAM=false
PLUGIN_S3_ENDPOINT= PLUGIN_S3_ENDPOINT=
PLUGIN_S3_USE_PATH_STYLE=false PLUGIN_S3_USE_PATH_STYLE=false
@@ -1448,18 +1085,11 @@ PLUGIN_ALIYUN_OSS_ACCESS_KEY_ID=
PLUGIN_ALIYUN_OSS_ACCESS_KEY_SECRET= PLUGIN_ALIYUN_OSS_ACCESS_KEY_SECRET=
PLUGIN_ALIYUN_OSS_AUTH_VERSION=v4 PLUGIN_ALIYUN_OSS_AUTH_VERSION=v4
PLUGIN_ALIYUN_OSS_PATH= PLUGIN_ALIYUN_OSS_PATH=
# Plugin oss volcengine tos
PLUGIN_VOLCENGINE_TOS_ENDPOINT=
PLUGIN_VOLCENGINE_TOS_ACCESS_KEY=
PLUGIN_VOLCENGINE_TOS_SECRET_KEY=
PLUGIN_VOLCENGINE_TOS_REGION=
# ------------------------------ # ------------------------------
# OTLP Collector Configuration # OTLP Collector Configuration
# ------------------------------ # ------------------------------
ENABLE_OTEL=false ENABLE_OTEL=false
OTLP_TRACE_ENDPOINT=
OTLP_METRIC_ENDPOINT=
OTLP_BASE_ENDPOINT=http://localhost:4318 OTLP_BASE_ENDPOINT=http://localhost:4318
OTLP_API_KEY= OTLP_API_KEY=
OTEL_EXPORTER_OTLP_PROTOCOL= OTEL_EXPORTER_OTLP_PROTOCOL=
@@ -1474,87 +1104,3 @@ OTEL_METRIC_EXPORT_TIMEOUT=30000
# Prevent Clickjacking # Prevent Clickjacking
ALLOW_EMBED=false ALLOW_EMBED=false
# Dataset queue monitor configuration
QUEUE_MONITOR_THRESHOLD=200
# You can configure multiple ones, separated by commas. eg: test1@dify.ai,test2@dify.ai
QUEUE_MONITOR_ALERT_EMAILS=
# Monitor interval in minutes, default is 30 minutes
QUEUE_MONITOR_INTERVAL=30
# Swagger UI configuration
SWAGGER_UI_ENABLED=false
SWAGGER_UI_PATH=/swagger-ui.html
# Whether to encrypt dataset IDs when exporting DSL files (default: true)
# Set to false to export dataset IDs as plain text for easier cross-environment import
DSL_EXPORT_ENCRYPT_DATASET_ID=true
# Maximum number of segments for dataset segments API (0 for unlimited)
DATASET_MAX_SEGMENTS_PER_REQUEST=0
# Celery schedule tasks configuration
ENABLE_CLEAN_EMBEDDING_CACHE_TASK=false
ENABLE_CLEAN_UNUSED_DATASETS_TASK=false
ENABLE_CREATE_TIDB_SERVERLESS_TASK=false
ENABLE_UPDATE_TIDB_SERVERLESS_STATUS_TASK=false
ENABLE_CLEAN_MESSAGES=false
ENABLE_WORKFLOW_RUN_CLEANUP_TASK=false
ENABLE_MAIL_CLEAN_DOCUMENT_NOTIFY_TASK=false
ENABLE_DATASETS_QUEUE_MONITOR=false
ENABLE_CHECK_UPGRADABLE_PLUGIN_TASK=true
ENABLE_WORKFLOW_SCHEDULE_POLLER_TASK=true
WORKFLOW_SCHEDULE_POLLER_INTERVAL=1
WORKFLOW_SCHEDULE_POLLER_BATCH_SIZE=100
WORKFLOW_SCHEDULE_MAX_DISPATCH_PER_TICK=0
# Tenant isolated task queue configuration
TENANT_ISOLATED_TASK_CONCURRENCY=1
# Maximum allowed CSV file size for annotation import in megabytes
ANNOTATION_IMPORT_FILE_SIZE_LIMIT=2
#Maximum number of annotation records allowed in a single import
ANNOTATION_IMPORT_MAX_RECORDS=10000
# Minimum number of annotation records required in a single import
ANNOTATION_IMPORT_MIN_RECORDS=1
ANNOTATION_IMPORT_RATE_LIMIT_PER_MINUTE=5
ANNOTATION_IMPORT_RATE_LIMIT_PER_HOUR=20
# Maximum number of concurrent annotation import tasks per tenant
ANNOTATION_IMPORT_MAX_CONCURRENT=5
# The API key of amplitude
AMPLITUDE_API_KEY=
# Sandbox expired records clean configuration
SANDBOX_EXPIRED_RECORDS_CLEAN_GRACEFUL_PERIOD=21
SANDBOX_EXPIRED_RECORDS_CLEAN_BATCH_SIZE=1000
SANDBOX_EXPIRED_RECORDS_CLEAN_BATCH_MAX_INTERVAL=200
SANDBOX_EXPIRED_RECORDS_RETENTION_DAYS=30
# Redis URL used for PubSub between API and
# celery worker
# defaults to url constructed from `REDIS_*`
# configurations
PUBSUB_REDIS_URL=
# Pub/sub channel type for streaming events.
# valid options are:
#
# - pubsub: for normal Pub/Sub
# - sharded: for sharded Pub/Sub
#
# It's highly recommended to use sharded Pub/Sub AND redis cluster
# for large deployments.
PUBSUB_REDIS_CHANNEL_TYPE=pubsub
# Whether to use Redis cluster mode while running
# PubSub.
# It's highly recommended to enable this for large deployments.
PUBSUB_REDIS_USE_CLUSTERS=false
# Whether to Enable human input timeout check task
ENABLE_HUMAN_INPUT_TIMEOUT_TASK=true
# Human input timeout check interval in minutes
HUMAN_INPUT_TIMEOUT_TASK_INTERVAL=1
SANDBOX_EXPIRED_RECORDS_CLEAN_TASK_LOCK_TTL=90000
+45 -103
View File
@@ -4,7 +4,7 @@ Welcome to the new `docker` directory for deploying Dify using Docker Compose. T
### What's Updated ### What's Updated
- **Certbot Container**: `docker-compose.yaml` now contains `certbot` for managing SSL certificates. This container automatically renews certificates and ensures secure HTTPS connections.\ - **Certbot Container**: `docker-compose.yaml` now contains `certbot` for managing SSL certificates. This container automatically renews certificates and ensures secure HTTPS connections.
For more information, refer `docker/certbot/README.md`. For more information, refer `docker/certbot/README.md`.
- **Persistent Environment Variables**: Environment variables are now managed through a `.env` file, ensuring that your configurations persist across deployments. - **Persistent Environment Variables**: Environment variables are now managed through a `.env` file, ensuring that your configurations persist across deployments.
@@ -13,50 +13,43 @@ Welcome to the new `docker` directory for deploying Dify using Docker Compose. T
> The `.env` file is a crucial component in Docker and Docker Compose environments, serving as a centralized configuration file where you can define environment variables that are accessible to the containers at runtime. This file simplifies the management of environment settings across different stages of development, testing, and production, providing consistency and ease of configuration to deployments. > The `.env` file is a crucial component in Docker and Docker Compose environments, serving as a centralized configuration file where you can define environment variables that are accessible to the containers at runtime. This file simplifies the management of environment settings across different stages of development, testing, and production, providing consistency and ease of configuration to deployments.
- **Unified Vector Database Services**: All vector database services are now managed from a single Docker Compose file `docker-compose.yaml`. You can switch between different vector databases by setting the `VECTOR_STORE` environment variable in your `.env` file. - **Unified Vector Database Services**: All vector database services are now managed from a single Docker Compose file `docker-compose.yaml`. You can switch between different vector databases by setting the `VECTOR_STORE` environment variable in your `.env` file.
- **Mandatory .env File**: A `.env` file is now required to run `docker compose up`. This file is crucial for configuring your deployment and for any custom settings to persist through upgrades. - **Mandatory .env File**: A `.env` file is now required to run `docker compose up`. This file is crucial for configuring your deployment and for any custom settings to persist through upgrades.
### How to Deploy Dify with `docker-compose.yaml` ### How to Deploy Dify with `docker-compose.yaml`
1. **Prerequisites**: Ensure Docker and Docker Compose are installed on your system. 1. **Prerequisites**: Ensure Docker and Docker Compose are installed on your system.
1. **Environment Setup**: 2. **Environment Setup**:
- Navigate to the `docker` directory. - Navigate to the `docker` directory.
- Copy the `.env.example` file to a new file named `.env` by running `cp .env.example .env`. - Copy the `.env.example` file to a new file named `.env` by running `cp .env.example .env`.
- Customize the `.env` file as needed. Refer to the `.env.example` file for detailed configuration options. - Customize the `.env` file as needed. Refer to the `.env.example` file for detailed configuration options.
- **Optional (Recommended for upgrades)**: 3. **Running the Services**:
You may use the environment synchronization tool to help keep your `.env` file aligned with the latest `.env.example` updates, while preserving your custom settings. - Execute `docker compose up` from the `docker` directory to start the services.
This is especially useful when upgrading Dify or managing a large, customized `.env` file. - To specify a vector database, set the `VECTOR_STORE` variable in your `.env` file to your desired vector database service, such as `milvus`, `weaviate`, or `opensearch`.
See the [Environment Variables Synchronization](#environment-variables-synchronization) section below. 4. **SSL Certificate Setup**:
1. **Running the Services**: - Refer `docker/certbot/README.md` to set up SSL certificates using Certbot.
- Execute `docker compose up` from the `docker` directory to start the services. 5. **OpenTelemetry Collector Setup**:
- To specify a vector database, set the `VECTOR_STORE` variable in your `.env` file to your desired vector database service, such as `milvus`, `weaviate`, or `opensearch`.
1. **SSL Certificate Setup**:
- Refer `docker/certbot/README.md` to set up SSL certificates using Certbot.
1. **OpenTelemetry Collector Setup**:
- Change `ENABLE_OTEL` to `true` in `.env`. - Change `ENABLE_OTEL` to `true` in `.env`.
- Configure `OTLP_BASE_ENDPOINT` properly. - Configure `OTLP_BASE_ENDPOINT` properly.
### How to Deploy Middleware for Developing Dify ### How to Deploy Middleware for Developing Dify
1. **Middleware Setup**: 1. **Middleware Setup**:
- Use the `docker-compose.middleware.yaml` for setting up essential middleware services like databases and caches. - Use the `docker-compose.middleware.yaml` for setting up essential middleware services like databases and caches.
- Navigate to the `docker` directory. - Navigate to the `docker` directory.
- Ensure the `middleware.env` file is created by running `cp middleware.env.example middleware.env` (refer to the `middleware.env.example` file). - Ensure the `middleware.env` file is created by running `cp middleware.env.example middleware.env` (refer to the `middleware.env.example` file).
1. **Running Middleware Services**: 2. **Running Middleware Services**:
- Navigate to the `docker` directory. - Navigate to the `docker` directory.
- Execute `docker compose --env-file middleware.env -f docker-compose.middleware.yaml -p dify up -d` to start PostgreSQL/MySQL (per `DB_TYPE`) plus the bundled Weaviate instance. - Execute `docker compose -f docker-compose.middleware.yaml --profile weaviate -p dify up -d` to start the middleware services. (Change the profile to other vector database if you are not using weaviate)
> Compose automatically loads `COMPOSE_PROFILES=${DB_TYPE:-postgresql},weaviate` from `middleware.env`, so no extra `--profile` flags are needed. Adjust variables in `middleware.env` if you want a different combination of services.
### Migration for Existing Users ### Migration for Existing Users
For users migrating from the `docker-legacy` setup: For users migrating from the `docker-legacy` setup:
1. **Review Changes**: Familiarize yourself with the new `.env` configuration and Docker Compose setup. 1. **Review Changes**: Familiarize yourself with the new `.env` configuration and Docker Compose setup.
1. **Transfer Customizations**: 2. **Transfer Customizations**:
- If you have customized configurations such as `docker-compose.yaml`, `ssrf_proxy/squid.conf`, or `nginx/conf.d/default.conf`, you will need to reflect these changes in the `.env` file you create. - If you have customized configurations such as `docker-compose.yaml`, `ssrf_proxy/squid.conf`, or `nginx/conf.d/default.conf`, you will need to reflect these changes in the `.env` file you create.
1. **Data Migration**: 3. **Data Migration**:
- Ensure that data from services like databases and caches is backed up and migrated appropriately to the new structure if necessary. - Ensure that data from services like databases and caches is backed up and migrated appropriately to the new structure if necessary.
### Overview of `.env` ### Overview of `.env`
@@ -71,90 +64,39 @@ For users migrating from the `docker-legacy` setup:
The `.env.example` file provided in the Docker setup is extensive and covers a wide range of configuration options. It is structured into several sections, each pertaining to different aspects of the application and its services. Here are some of the key sections and variables: The `.env.example` file provided in the Docker setup is extensive and covers a wide range of configuration options. It is structured into several sections, each pertaining to different aspects of the application and its services. Here are some of the key sections and variables:
1. **Common Variables**: 1. **Common Variables**:
- `CONSOLE_API_URL`, `SERVICE_API_URL`: URLs for different API services.
- `APP_WEB_URL`: Frontend application URL.
- `FILES_URL`: Base URL for file downloads and previews.
- `CONSOLE_API_URL`, `SERVICE_API_URL`: URLs for different API services. 2. **Server Configuration**:
- `APP_WEB_URL`: Frontend application URL. - `LOG_LEVEL`, `DEBUG`, `FLASK_DEBUG`: Logging and debug settings.
- `FILES_URL`: Base URL for file downloads and previews. - `SECRET_KEY`: A key for encrypting session cookies and other sensitive data.
1. **Server Configuration**: 3. **Database Configuration**:
- `DB_USERNAME`, `DB_PASSWORD`, `DB_HOST`, `DB_PORT`, `DB_DATABASE`: PostgreSQL database credentials and connection details.
- `LOG_LEVEL`, `DEBUG`, `FLASK_DEBUG`: Logging and debug settings. 4. **Redis Configuration**:
- `SECRET_KEY`: A key for encrypting session cookies and other sensitive data. - `REDIS_HOST`, `REDIS_PORT`, `REDIS_PASSWORD`: Redis server connection settings.
1. **Database Configuration**: 5. **Celery Configuration**:
- `CELERY_BROKER_URL`: Configuration for Celery message broker.
- `DB_USERNAME`, `DB_PASSWORD`, `DB_HOST`, `DB_PORT`, `DB_DATABASE`: PostgreSQL database credentials and connection details. 6. **Storage Configuration**:
- `STORAGE_TYPE`, `S3_BUCKET_NAME`, `AZURE_BLOB_ACCOUNT_NAME`: Settings for file storage options like local, S3, Azure Blob, etc.
1. **Redis Configuration**: 7. **Vector Database Configuration**:
- `VECTOR_STORE`: Type of vector database (e.g., `weaviate`, `milvus`).
- Specific settings for each vector store like `WEAVIATE_ENDPOINT`, `MILVUS_URI`.
- `REDIS_HOST`, `REDIS_PORT`, `REDIS_PASSWORD`: Redis server connection settings. 8. **CORS Configuration**:
- `WEB_API_CORS_ALLOW_ORIGINS`, `CONSOLE_CORS_ALLOW_ORIGINS`: Settings for cross-origin resource sharing.
1. **Celery Configuration**: 9. **OpenTelemetry Configuration**:
- `ENABLE_OTEL`: Enable OpenTelemetry collector in api.
- `OTLP_BASE_ENDPOINT`: Endpoint for your OTLP exporter.
- `CELERY_BROKER_URL`: Configuration for Celery message broker. 10. **Other Service-Specific Environment Variables**:
- Each service like `nginx`, `redis`, `db`, and vector databases have specific environment variables that are directly referenced in the `docker-compose.yaml`.
1. **Storage Configuration**:
- `STORAGE_TYPE`, `S3_BUCKET_NAME`, `AZURE_BLOB_ACCOUNT_NAME`: Settings for file storage options like local, S3, Azure Blob, etc.
1. **Vector Database Configuration**:
- `VECTOR_STORE`: Type of vector database (e.g., `weaviate`, `milvus`).
- Specific settings for each vector store like `WEAVIATE_ENDPOINT`, `MILVUS_URI`.
1. **CORS Configuration**:
- `WEB_API_CORS_ALLOW_ORIGINS`, `CONSOLE_CORS_ALLOW_ORIGINS`: Settings for cross-origin resource sharing.
1. **OpenTelemetry Configuration**:
- `ENABLE_OTEL`: Enable OpenTelemetry collector in api.
- `OTLP_BASE_ENDPOINT`: Endpoint for your OTLP exporter.
1. **Other Service-Specific Environment Variables**:
- Each service like `nginx`, `redis`, `db`, and vector databases have specific environment variables that are directly referenced in the `docker-compose.yaml`.
### Environment Variables Synchronization
When upgrading Dify or pulling the latest changes, new environment variables may be introduced in `.env.example`.
To help keep your existing `.env` file up to date **without losing your custom values**, an optional environment variables synchronization tool is provided.
> This tool performs a **one-way synchronization** from `.env.example` to `.env`.
> Existing values in `.env` are never overwritten automatically.
#### `dify-env-sync.sh` (Optional)
This script compares your current `.env` file with the latest `.env.example` template and helps safely apply new or updated environment variables.
**What it does**
- Creates a backup of the current `.env` file before making any changes
- Synchronizes newly added environment variables from `.env.example`
- Preserves all existing custom values in `.env`
- Displays differences and variables removed from `.env.example` for review
**Backup behavior**
Before synchronization, the current `.env` file is saved to the `env-backup/` directory with a timestamped filename
(e.g. `env-backup/.env.backup_20231218_143022`).
**When to use**
- After upgrading Dify to a newer version
- When `.env.example` has been updated with new environment variables
- When managing a large or heavily customized `.env` file
**Usage**
```bash
# Grant execution permission (first time only)
chmod +x dify-env-sync.sh
# Run the synchronization
./dify-env-sync.sh
```
### Additional Information ### Additional Information
+4 -4
View File
@@ -2,12 +2,12 @@
## Short description ## Short description
docker compose certbot configurations with Backward compatibility (without certbot container).\ docker compose certbot configurations with Backward compatibility (without certbot container).
Use `docker compose --profile certbot up` to use this features. Use `docker compose --profile certbot up` to use this features.
## The simplest way for launching new servers with SSL certificates ## The simplest way for launching new servers with SSL certificates
1. Get letsencrypt certs\ 1. Get letsencrypt certs
set `.env` values set `.env` values
```properties ```properties
NGINX_SSL_CERT_FILENAME=fullchain.pem NGINX_SSL_CERT_FILENAME=fullchain.pem
@@ -25,7 +25,7 @@ Use `docker compose --profile certbot up` to use this features.
```shell ```shell
docker compose exec -it certbot /bin/sh /update-cert.sh docker compose exec -it certbot /bin/sh /update-cert.sh
``` ```
1. Edit `.env` file and `docker compose --profile certbot up` again.\ 2. Edit `.env` file and `docker compose --profile certbot up` again.
set `.env` value additionally set `.env` value additionally
```properties ```properties
NGINX_HTTPS_ENABLED=true NGINX_HTTPS_ENABLED=true
@@ -34,7 +34,7 @@ Use `docker compose --profile certbot up` to use this features.
```shell ```shell
docker compose --profile certbot up -d --no-deps --force-recreate nginx docker compose --profile certbot up -d --no-deps --force-recreate nginx
``` ```
Then you can access your serve with HTTPS.\ Then you can access your serve with HTTPS.
[https://your_domain.com](https://your_domain.com) [https://your_domain.com](https://your_domain.com)
## SSL certificates renewal ## SSL certificates renewal
-465
View File
@@ -1,465 +0,0 @@
#!/bin/bash
# ================================================================
# Dify Environment Variables Synchronization Script
#
# Features:
# - Synchronize latest settings from .env.example to .env
# - Preserve custom settings in existing .env
# - Add new environment variables
# - Detect removed environment variables
# - Create backup files
# ================================================================
set -eo pipefail # Exit on error and pipe failures (safer for complex variable handling)
# Error handling function
# Arguments:
# $1 - Line number where error occurred
# $2 - Error code
handle_error() {
local line_no=$1
local error_code=$2
echo -e "\033[0;31m[ERROR]\033[0m Script error: line $line_no with error code $error_code" >&2
echo -e "\033[0;31m[ERROR]\033[0m Debug info: current working directory $(pwd)" >&2
exit $error_code
}
# Set error trap
trap 'handle_error ${LINENO} $?' ERR
# Color settings for output
readonly RED='\033[0;31m'
readonly GREEN='\033[0;32m'
readonly YELLOW='\033[1;33m'
readonly BLUE='\033[0;34m'
readonly NC='\033[0m' # No Color
# Logging functions
# Print informational message in blue
# Arguments: $1 - Message to print
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
# Print success message in green
# Arguments: $1 - Message to print
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
# Print warning message in yellow
# Arguments: $1 - Message to print
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1" >&2
}
# Print error message in red to stderr
# Arguments: $1 - Message to print
log_error() {
echo -e "${RED}[ERROR]${NC} $1" >&2
}
# Check for required files and create .env if missing
# Verifies that .env.example exists and creates .env from template if needed
check_files() {
log_info "Checking required files..."
if [[ ! -f ".env.example" ]]; then
log_error ".env.example file not found"
exit 1
fi
if [[ ! -f ".env" ]]; then
log_warning ".env file does not exist. Creating from .env.example."
cp ".env.example" ".env"
log_success ".env file created"
fi
log_success "Required files verified"
}
# Create timestamped backup of .env file
# Creates env-backup directory if needed and backs up current .env file
create_backup() {
local timestamp=$(date +"%Y%m%d_%H%M%S")
local backup_dir="env-backup"
# Create backup directory if it doesn't exist
if [[ ! -d "$backup_dir" ]]; then
mkdir -p "$backup_dir"
log_info "Created backup directory: $backup_dir"
fi
if [[ -f ".env" ]]; then
local backup_file="${backup_dir}/.env.backup_${timestamp}"
cp ".env" "$backup_file"
log_success "Backed up existing .env to $backup_file"
fi
}
# Detect differences between .env and .env.example (optimized for large files)
detect_differences() {
log_info "Detecting differences between .env and .env.example..."
# Create secure temporary directory
local temp_dir=$(mktemp -d)
local temp_diff="$temp_dir/env_diff"
# Store diff file path as global variable
declare -g DIFF_FILE="$temp_diff"
declare -g TEMP_DIR="$temp_dir"
# Initialize difference file
> "$temp_diff"
# Use awk for efficient comparison (much faster for large files)
local diff_count=$(awk -F= '
BEGIN { OFS="\x01" }
FNR==NR {
if (!/^[[:space:]]*#/ && !/^[[:space:]]*$/ && /=/) {
gsub(/^[[:space:]]+|[[:space:]]+$/, "", $1)
key = $1
value = substr($0, index($0,"=")+1)
gsub(/^[[:space:]]+|[[:space:]]+$/, "", value)
env_values[key] = value
}
next
}
{
if (!/^[[:space:]]*#/ && !/^[[:space:]]*$/ && /=/) {
gsub(/^[[:space:]]+|[[:space:]]+$/, "", $1)
key = $1
example_value = substr($0, index($0,"=")+1)
gsub(/^[[:space:]]+|[[:space:]]+$/, "", example_value)
if (key in env_values && env_values[key] != example_value) {
print key, env_values[key], example_value > "'$temp_diff'"
diff_count++
}
}
}
END { print diff_count }
' .env .env.example)
if [[ $diff_count -gt 0 ]]; then
log_success "Detected differences in $diff_count environment variables"
# Show detailed differences
show_differences_detail
else
log_info "No differences detected"
fi
}
# Parse environment variable line
# Extracts key-value pairs from .env file format lines
# Arguments:
# $1 - Line to parse
# Returns:
# 0 - Success, outputs "key|value" format
# 1 - Skip (empty line, comment, or invalid format)
parse_env_line() {
local line="$1"
local key=""
local value=""
# Skip empty lines or comment lines
[[ -z "$line" || "$line" =~ ^[[:space:]]*# ]] && return 1
# Split by =
if [[ "$line" =~ ^([^=]+)=(.*)$ ]]; then
key="${BASH_REMATCH[1]}"
value="${BASH_REMATCH[2]}"
# Remove leading and trailing whitespace
key=$(echo "$key" | sed 's/^[[:space:]]*//; s/[[:space:]]*$//')
value=$(echo "$value" | sed 's/^[[:space:]]*//; s/[[:space:]]*$//')
if [[ -n "$key" ]]; then
echo "$key|$value"
return 0
fi
fi
return 1
}
# Show detailed differences
show_differences_detail() {
log_info ""
log_info "=== Environment Variable Differences ==="
# Read differences from the already created diff file
if [[ ! -s "$DIFF_FILE" ]]; then
log_info "No differences to display"
return
fi
# Display differences
local count=1
while IFS=$'\x01' read -r key env_value example_value; do
echo ""
echo -e "${YELLOW}[$count] $key${NC}"
echo -e " ${GREEN}.env (current)${NC} : ${env_value}"
echo -e " ${BLUE}.env.example (recommended)${NC}: ${example_value}"
# Analyze value changes
analyze_value_change "$env_value" "$example_value"
((count++))
done < "$DIFF_FILE"
echo ""
log_info "=== Difference Analysis Complete ==="
log_info "Note: Consider changing to the recommended values above."
log_info "Current implementation preserves .env values."
echo ""
}
# Analyze value changes
analyze_value_change() {
local current_value="$1"
local recommended_value="$2"
# Analyze value characteristics
local analysis=""
# Empty value check
if [[ -z "$current_value" && -n "$recommended_value" ]]; then
analysis=" ${RED}→ Setting from empty to recommended value${NC}"
elif [[ -n "$current_value" && -z "$recommended_value" ]]; then
analysis=" ${RED}→ Recommended value changed to empty${NC}"
# Numeric check - using arithmetic evaluation for robust comparison
elif [[ "$current_value" =~ ^[0-9]+$ && "$recommended_value" =~ ^[0-9]+$ ]]; then
# Use arithmetic evaluation to handle leading zeros correctly
if (( 10#$current_value < 10#$recommended_value )); then
analysis=" ${BLUE}→ Numeric increase (${current_value} < ${recommended_value})${NC}"
elif (( 10#$current_value > 10#$recommended_value )); then
analysis=" ${YELLOW}→ Numeric decrease (${current_value} > ${recommended_value})${NC}"
fi
# Boolean check
elif [[ "$current_value" =~ ^(true|false)$ && "$recommended_value" =~ ^(true|false)$ ]]; then
if [[ "$current_value" != "$recommended_value" ]]; then
analysis=" ${BLUE}→ Boolean value change (${current_value}${recommended_value})${NC}"
fi
# URL/endpoint check
elif [[ "$current_value" =~ ^https?:// || "$recommended_value" =~ ^https?:// ]]; then
analysis=" ${BLUE}→ URL/endpoint change${NC}"
# File path check
elif [[ "$current_value" =~ ^/ || "$recommended_value" =~ ^/ ]]; then
analysis=" ${BLUE}→ File path change${NC}"
else
# Length comparison
local current_len=${#current_value}
local recommended_len=${#recommended_value}
if [[ $current_len -ne $recommended_len ]]; then
analysis=" ${YELLOW}→ String length change (${current_len}${recommended_len} characters)${NC}"
fi
fi
if [[ -n "$analysis" ]]; then
echo -e "$analysis"
fi
}
# Synchronize .env file with .env.example while preserving custom values
# Creates a new .env file based on .env.example structure, preserving existing custom values
# Global variables used: DIFF_FILE, TEMP_DIR
sync_env_file() {
log_info "Starting partial synchronization of .env file..."
local new_env_file=".env.new"
local preserved_count=0
local updated_count=0
# Pre-process diff file for efficient lookup
local lookup_file=""
if [[ -f "$DIFF_FILE" && -s "$DIFF_FILE" ]]; then
lookup_file="${DIFF_FILE}.lookup"
# Create sorted lookup file for fast search
sort "$DIFF_FILE" > "$lookup_file"
log_info "Created lookup file for $(wc -l < "$DIFF_FILE") preserved values"
fi
# Use AWK for efficient processing (much faster than bash loop for large files)
log_info "Processing $(wc -l < .env.example) lines with AWK..."
local preserved_keys_file="${TEMP_DIR}/preserved_keys"
local awk_preserved_count_file="${TEMP_DIR}/awk_preserved_count"
local awk_updated_count_file="${TEMP_DIR}/awk_updated_count"
awk -F'=' -v lookup_file="$lookup_file" -v preserved_file="$preserved_keys_file" \
-v preserved_count_file="$awk_preserved_count_file" -v updated_count_file="$awk_updated_count_file" '
BEGIN {
preserved_count = 0
updated_count = 0
# Load preserved values if lookup file exists
if (lookup_file != "") {
while ((getline line < lookup_file) > 0) {
split(line, parts, "\x01")
key = parts[1]
value = parts[2]
preserved_values[key] = value
}
close(lookup_file)
}
}
# Process each line
{
# Check if this is an environment variable line
if (/^[[:space:]]*[A-Za-z_][A-Za-z0-9_]*[[:space:]]*=/) {
# Extract key
key = $1
gsub(/^[[:space:]]+|[[:space:]]+$/, "", key)
# Check if key should be preserved
if (key in preserved_values) {
print key "=" preserved_values[key]
print key > preserved_file
preserved_count++
} else {
print $0
updated_count++
}
} else {
# Not an env var line, preserve as-is
print $0
}
}
END {
print preserved_count > preserved_count_file
print updated_count > updated_count_file
}
' .env.example > "$new_env_file"
# Read counters and preserved keys
if [[ -f "$awk_preserved_count_file" ]]; then
preserved_count=$(cat "$awk_preserved_count_file")
fi
if [[ -f "$awk_updated_count_file" ]]; then
updated_count=$(cat "$awk_updated_count_file")
fi
# Show what was preserved
if [[ -f "$preserved_keys_file" ]]; then
while read -r key; do
[[ -n "$key" ]] && log_info " Preserved: $key (.env value)"
done < "$preserved_keys_file"
fi
# Clean up lookup file
[[ -n "$lookup_file" ]] && rm -f "$lookup_file"
# Replace the original .env file
if mv "$new_env_file" ".env"; then
log_success "Successfully created new .env file"
else
log_error "Failed to replace .env file"
rm -f "$new_env_file"
return 1
fi
# Clean up difference file and temporary directory
if [[ -n "${TEMP_DIR:-}" ]]; then
rm -rf "${TEMP_DIR}"
unset TEMP_DIR
fi
if [[ -n "${DIFF_FILE:-}" ]]; then
unset DIFF_FILE
fi
log_success "Partial synchronization of .env file completed"
log_info " Preserved .env values: $preserved_count"
log_info " Updated to .env.example values: $updated_count"
}
# Detect removed environment variables
detect_removed_variables() {
log_info "Detecting removed environment variables..."
if [[ ! -f ".env" ]]; then
return
fi
# Use temporary files for efficient lookup
local temp_dir="${TEMP_DIR:-$(mktemp -d)}"
local temp_example_keys="$temp_dir/example_keys"
local temp_current_keys="$temp_dir/current_keys"
local cleanup_temp_dir=""
# Set flag if we created a new temp directory
if [[ -z "${TEMP_DIR:-}" ]]; then
cleanup_temp_dir="$temp_dir"
fi
# Get keys from .env.example and .env, sorted for comm
awk -F= '!/^[[:space:]]*#/ && /=/ {gsub(/^[[:space:]]+|[[:space:]]+$/, "", $1); print $1}' .env.example | sort > "$temp_example_keys"
awk -F= '!/^[[:space:]]*#/ && /=/ {gsub(/^[[:space:]]+|[[:space:]]+$/, "", $1); print $1}' .env | sort > "$temp_current_keys"
# Get keys from existing .env and check for removals
local removed_vars=()
while IFS= read -r var; do
removed_vars+=("$var")
done < <(comm -13 "$temp_example_keys" "$temp_current_keys")
# Clean up temporary files if we created a new temp directory
if [[ -n "$cleanup_temp_dir" ]]; then
rm -rf "$cleanup_temp_dir"
fi
if [[ ${#removed_vars[@]} -gt 0 ]]; then
log_warning "The following environment variables have been removed from .env.example:"
for var in "${removed_vars[@]}"; do
log_warning " - $var"
done
log_warning "Consider manually removing these variables from .env"
else
log_success "No removed environment variables found"
fi
}
# Show statistics
show_statistics() {
log_info "Synchronization statistics:"
local total_example=$(grep -c "^[^#]*=" .env.example 2>/dev/null || echo "0")
local total_env=$(grep -c "^[^#]*=" .env 2>/dev/null || echo "0")
log_info " .env.example environment variables: $total_example"
log_info " .env environment variables: $total_env"
}
# Main execution function
# Orchestrates the complete synchronization process in the correct order
main() {
log_info "=== Dify Environment Variables Synchronization Script ==="
log_info "Execution started: $(date)"
# Check prerequisites
check_files
# Create backup
create_backup
# Detect differences
detect_differences
# Detect removed variables (before sync)
detect_removed_variables
# Synchronize environment file
sync_env_file
# Show statistics
show_statistics
log_success "=== Synchronization process completed successfully ==="
log_info "Execution finished: $(date)"
}
# Execute main function only when script is run directly
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
main "$@"
fi
+69 -304
View File
@@ -1,27 +1,8 @@
x-shared-env: &shared-api-worker-env x-shared-env: &shared-api-worker-env
services: services:
# Init container to fix permissions
init_permissions:
image: busybox:latest
command:
- sh
- -c
- |
FLAG_FILE="/app/api/storage/.init_permissions"
if [ -f "$${FLAG_FILE}" ]; then
echo "Permissions already initialized. Exiting."
exit 0
fi
echo "Initializing permissions for /app/api/storage"
chown -R 1001:1001 /app/api/storage && touch "$${FLAG_FILE}"
echo "Permissions initialized. Exiting."
volumes:
- ./volumes/app/storage:/app/api/storage
restart: "no"
# API service # API service
api: api:
image: langgenius/dify-api:1.13.0 image: langgenius/dify-api:1.4.0
restart: always restart: always
environment: environment:
# Use the shared environment variables. # Use the shared environment variables.
@@ -34,23 +15,10 @@ services:
PLUGIN_REMOTE_INSTALL_HOST: ${EXPOSE_PLUGIN_DEBUGGING_HOST:-localhost} PLUGIN_REMOTE_INSTALL_HOST: ${EXPOSE_PLUGIN_DEBUGGING_HOST:-localhost}
PLUGIN_REMOTE_INSTALL_PORT: ${EXPOSE_PLUGIN_DEBUGGING_PORT:-5003} PLUGIN_REMOTE_INSTALL_PORT: ${EXPOSE_PLUGIN_DEBUGGING_PORT:-5003}
PLUGIN_MAX_PACKAGE_SIZE: ${PLUGIN_MAX_PACKAGE_SIZE:-52428800} PLUGIN_MAX_PACKAGE_SIZE: ${PLUGIN_MAX_PACKAGE_SIZE:-52428800}
PLUGIN_DAEMON_TIMEOUT: ${PLUGIN_DAEMON_TIMEOUT:-600.0}
INNER_API_KEY_FOR_PLUGIN: ${PLUGIN_DIFY_INNER_API_KEY:-QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1} INNER_API_KEY_FOR_PLUGIN: ${PLUGIN_DIFY_INNER_API_KEY:-QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1}
depends_on: depends_on:
init_permissions: db:
condition: service_completed_successfully
db_postgres:
condition: service_healthy condition: service_healthy
required: false
db_mysql:
condition: service_healthy
required: false
oceanbase:
condition: service_healthy
required: false
seekdb:
condition: service_healthy
required: false
redis: redis:
condition: service_started condition: service_started
volumes: volumes:
@@ -61,14 +29,14 @@ services:
- default - default
# worker service # worker service
# The Celery worker for processing all queues (dataset, workflow, mail, etc.) # The Celery worker for processing the queue.
worker: worker:
image: langgenius/dify-api:1.13.0 image: langgenius/dify-api:1.4.0
restart: always restart: always
environment: environment:
# Use the shared environment variables. # Use the shared environment variables.
<<: *shared-api-worker-env <<: *shared-api-worker-env
# Startup mode, 'worker' starts the Celery worker for processing all queues. # Startup mode, 'worker' starts the Celery worker for processing the queue.
MODE: worker MODE: worker
SENTRY_DSN: ${API_SENTRY_DSN:-} SENTRY_DSN: ${API_SENTRY_DSN:-}
SENTRY_TRACES_SAMPLE_RATE: ${API_SENTRY_TRACES_SAMPLE_RATE:-1.0} SENTRY_TRACES_SAMPLE_RATE: ${API_SENTRY_TRACES_SAMPLE_RATE:-1.0}
@@ -76,20 +44,8 @@ services:
PLUGIN_MAX_PACKAGE_SIZE: ${PLUGIN_MAX_PACKAGE_SIZE:-52428800} PLUGIN_MAX_PACKAGE_SIZE: ${PLUGIN_MAX_PACKAGE_SIZE:-52428800}
INNER_API_KEY_FOR_PLUGIN: ${PLUGIN_DIFY_INNER_API_KEY:-QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1} INNER_API_KEY_FOR_PLUGIN: ${PLUGIN_DIFY_INNER_API_KEY:-QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1}
depends_on: depends_on:
init_permissions: db:
condition: service_completed_successfully
db_postgres:
condition: service_healthy condition: service_healthy
required: false
db_mysql:
condition: service_healthy
required: false
oceanbase:
condition: service_healthy
required: false
seekdb:
condition: service_healthy
required: false
redis: redis:
condition: service_started condition: service_started
volumes: volumes:
@@ -99,75 +55,38 @@ services:
- ssrf_proxy_network - ssrf_proxy_network
- default - default
# worker_beat service
# Celery beat for scheduling periodic tasks.
worker_beat:
image: langgenius/dify-api:1.13.0
restart: always
environment:
# Use the shared environment variables.
<<: *shared-api-worker-env
# Startup mode, 'worker_beat' starts the Celery beat for scheduling periodic tasks.
MODE: beat
depends_on:
init_permissions:
condition: service_completed_successfully
db_postgres:
condition: service_healthy
required: false
db_mysql:
condition: service_healthy
required: false
oceanbase:
condition: service_healthy
required: false
seekdb:
condition: service_healthy
required: false
redis:
condition: service_started
networks:
- ssrf_proxy_network
- default
# Frontend web application. # Frontend web application.
web: web:
image: langgenius/dify-web:1.13.0 image: langgenius/dify-web:1.4.0
restart: always restart: always
environment: environment:
CONSOLE_API_URL: ${CONSOLE_API_URL:-} CONSOLE_API_URL: ${CONSOLE_API_URL:-}
APP_API_URL: ${APP_API_URL:-} APP_API_URL: ${APP_API_URL:-}
AMPLITUDE_API_KEY: ${AMPLITUDE_API_KEY:-}
NEXT_PUBLIC_COOKIE_DOMAIN: ${NEXT_PUBLIC_COOKIE_DOMAIN:-}
SENTRY_DSN: ${WEB_SENTRY_DSN:-} SENTRY_DSN: ${WEB_SENTRY_DSN:-}
NEXT_TELEMETRY_DISABLED: ${NEXT_TELEMETRY_DISABLED:-0} NEXT_TELEMETRY_DISABLED: ${NEXT_TELEMETRY_DISABLED:-0}
TEXT_GENERATION_TIMEOUT_MS: ${TEXT_GENERATION_TIMEOUT_MS:-60000} TEXT_GENERATION_TIMEOUT_MS: ${TEXT_GENERATION_TIMEOUT_MS:-60000}
CSP_WHITELIST: ${CSP_WHITELIST:-} CSP_WHITELIST: ${CSP_WHITELIST:-}
ALLOW_EMBED: ${ALLOW_EMBED:-false} ALLOW_EMBED: ${ALLOW_EMBED:-false}
ALLOW_UNSAFE_DATA_SCHEME: ${ALLOW_UNSAFE_DATA_SCHEME:-false}
MARKETPLACE_API_URL: ${MARKETPLACE_API_URL:-https://marketplace.dify.ai} MARKETPLACE_API_URL: ${MARKETPLACE_API_URL:-https://marketplace.dify.ai}
MARKETPLACE_URL: ${MARKETPLACE_URL:-https://marketplace.dify.ai} MARKETPLACE_URL: ${MARKETPLACE_URL:-https://marketplace.dify.ai}
TOP_K_MAX_VALUE: ${TOP_K_MAX_VALUE:-} TOP_K_MAX_VALUE: ${TOP_K_MAX_VALUE:-}
INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH: ${INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH:-} INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH: ${INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH:-}
PM2_INSTANCES: ${PM2_INSTANCES:-2}
LOOP_NODE_MAX_COUNT: ${LOOP_NODE_MAX_COUNT:-100} LOOP_NODE_MAX_COUNT: ${LOOP_NODE_MAX_COUNT:-100}
MAX_TOOLS_NUM: ${MAX_TOOLS_NUM:-10} MAX_TOOLS_NUM: ${MAX_TOOLS_NUM:-10}
MAX_PARALLEL_LIMIT: ${MAX_PARALLEL_LIMIT:-10} MAX_PARALLEL_LIMIT: ${MAX_PARALLEL_LIMIT:-10}
MAX_ITERATIONS_NUM: ${MAX_ITERATIONS_NUM:-99} MAX_ITERATIONS_NUM: ${MAX_ITERATIONS_NUM:-5}
MAX_TREE_DEPTH: ${MAX_TREE_DEPTH:-50}
ENABLE_WEBSITE_JINAREADER: ${ENABLE_WEBSITE_JINAREADER:-true} ENABLE_WEBSITE_JINAREADER: ${ENABLE_WEBSITE_JINAREADER:-true}
ENABLE_WEBSITE_FIRECRAWL: ${ENABLE_WEBSITE_FIRECRAWL:-true} ENABLE_WEBSITE_FIRECRAWL: ${ENABLE_WEBSITE_FIRECRAWL:-true}
ENABLE_WEBSITE_WATERCRAWL: ${ENABLE_WEBSITE_WATERCRAWL:-true} ENABLE_WEBSITE_WATERCRAWL: ${ENABLE_WEBSITE_WATERCRAWL:-true}
# The postgres database.
# The PostgreSQL database. db:
db_postgres:
image: postgres:15-alpine image: postgres:15-alpine
profiles:
- postgresql
restart: always restart: always
environment: environment:
POSTGRES_USER: ${DB_USERNAME:-postgres} PGUSER: ${PGUSER:-postgres}
POSTGRES_PASSWORD: ${DB_PASSWORD:-difyai123456} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-difyai123456}
POSTGRES_DB: ${DB_DATABASE:-dify} POSTGRES_DB: ${POSTGRES_DB:-dify}
PGDATA: ${PGDATA:-/var/lib/postgresql/data/pgdata} PGDATA: ${PGDATA:-/var/lib/postgresql/data/pgdata}
command: > command: >
postgres -c 'max_connections=${POSTGRES_MAX_CONNECTIONS:-100}' postgres -c 'max_connections=${POSTGRES_MAX_CONNECTIONS:-100}'
@@ -175,56 +94,14 @@ services:
-c 'work_mem=${POSTGRES_WORK_MEM:-4MB}' -c 'work_mem=${POSTGRES_WORK_MEM:-4MB}'
-c 'maintenance_work_mem=${POSTGRES_MAINTENANCE_WORK_MEM:-64MB}' -c 'maintenance_work_mem=${POSTGRES_MAINTENANCE_WORK_MEM:-64MB}'
-c 'effective_cache_size=${POSTGRES_EFFECTIVE_CACHE_SIZE:-4096MB}' -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: volumes:
- ./volumes/db/data:/var/lib/postgresql/data - ./volumes/db/data:/var/lib/postgresql/data
healthcheck: healthcheck:
test: test: [ 'CMD', 'pg_isready', '-h', 'db', '-U', '${PGUSER:-postgres}', '-d', '${POSTGRES_DB:-dify}' ]
[
"CMD",
"pg_isready",
"-h",
"db_postgres",
"-U",
"${DB_USERNAME:-postgres}",
"-d",
"${DB_DATABASE:-dify}",
]
interval: 1s interval: 1s
timeout: 3s timeout: 3s
retries: 60 retries: 60
# The mysql database.
db_mysql:
image: mysql:8.0
profiles:
- mysql
restart: always
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
healthcheck:
test:
[
"CMD",
"mysqladmin",
"ping",
"-u",
"root",
"-p${DB_PASSWORD:-difyai123456}",
]
interval: 1s
timeout: 3s
retries: 30
# The redis cache. # The redis cache.
redis: redis:
image: redis:6-alpine image: redis:6-alpine
@@ -237,11 +114,7 @@ services:
# Set the redis password when startup redis server. # Set the redis password when startup redis server.
command: redis-server --requirepass ${REDIS_PASSWORD:-difyai123456} command: redis-server --requirepass ${REDIS_PASSWORD:-difyai123456}
healthcheck: healthcheck:
test: test: [ 'CMD', 'redis-cli', 'ping' ]
[
"CMD-SHELL",
"redis-cli -a ${REDIS_PASSWORD:-difyai123456} ping | grep -q PONG",
]
# The DifySandbox # The DifySandbox
sandbox: sandbox:
@@ -263,13 +136,13 @@ services:
- ./volumes/sandbox/dependencies:/dependencies - ./volumes/sandbox/dependencies:/dependencies
- ./volumes/sandbox/conf:/conf - ./volumes/sandbox/conf:/conf
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8194/health"] test: [ 'CMD', 'curl', '-f', 'http://localhost:8194/health' ]
networks: networks:
- ssrf_proxy_network - ssrf_proxy_network
# plugin daemon # plugin daemon
plugin_daemon: plugin_daemon:
image: langgenius/dify-plugin-daemon:0.5.3-local image: langgenius/dify-plugin-daemon:0.0.10-local
restart: always restart: always
environment: environment:
# Use the shared environment variables. # Use the shared environment variables.
@@ -287,8 +160,6 @@ services:
FORCE_VERIFYING_SIGNATURE: ${FORCE_VERIFYING_SIGNATURE:-true} FORCE_VERIFYING_SIGNATURE: ${FORCE_VERIFYING_SIGNATURE:-true}
PYTHON_ENV_INIT_TIMEOUT: ${PLUGIN_PYTHON_ENV_INIT_TIMEOUT:-120} PYTHON_ENV_INIT_TIMEOUT: ${PLUGIN_PYTHON_ENV_INIT_TIMEOUT:-120}
PLUGIN_MAX_EXECUTION_TIMEOUT: ${PLUGIN_MAX_EXECUTION_TIMEOUT:-600} PLUGIN_MAX_EXECUTION_TIMEOUT: ${PLUGIN_MAX_EXECUTION_TIMEOUT:-600}
PLUGIN_STDIO_BUFFER_SIZE: ${PLUGIN_STDIO_BUFFER_SIZE:-1024}
PLUGIN_STDIO_MAX_BUFFER_SIZE: ${PLUGIN_STDIO_MAX_BUFFER_SIZE:-5242880}
PIP_MIRROR_URL: ${PIP_MIRROR_URL:-} PIP_MIRROR_URL: ${PIP_MIRROR_URL:-}
PLUGIN_STORAGE_TYPE: ${PLUGIN_STORAGE_TYPE:-local} PLUGIN_STORAGE_TYPE: ${PLUGIN_STORAGE_TYPE:-local}
PLUGIN_STORAGE_LOCAL_ROOT: ${PLUGIN_STORAGE_LOCAL_ROOT:-/app/storage} PLUGIN_STORAGE_LOCAL_ROOT: ${PLUGIN_STORAGE_LOCAL_ROOT:-/app/storage}
@@ -297,7 +168,6 @@ services:
PLUGIN_MEDIA_CACHE_PATH: ${PLUGIN_MEDIA_CACHE_PATH:-assets} PLUGIN_MEDIA_CACHE_PATH: ${PLUGIN_MEDIA_CACHE_PATH:-assets}
PLUGIN_STORAGE_OSS_BUCKET: ${PLUGIN_STORAGE_OSS_BUCKET:-} PLUGIN_STORAGE_OSS_BUCKET: ${PLUGIN_STORAGE_OSS_BUCKET:-}
S3_USE_AWS_MANAGED_IAM: ${PLUGIN_S3_USE_AWS_MANAGED_IAM:-false} S3_USE_AWS_MANAGED_IAM: ${PLUGIN_S3_USE_AWS_MANAGED_IAM:-false}
S3_USE_AWS: ${PLUGIN_S3_USE_AWS:-false}
S3_ENDPOINT: ${PLUGIN_S3_ENDPOINT:-} S3_ENDPOINT: ${PLUGIN_S3_ENDPOINT:-}
S3_USE_PATH_STYLE: ${PLUGIN_S3_USE_PATH_STYLE:-false} S3_USE_PATH_STYLE: ${PLUGIN_S3_USE_PATH_STYLE:-false}
AWS_ACCESS_KEY: ${PLUGIN_AWS_ACCESS_KEY:-} AWS_ACCESS_KEY: ${PLUGIN_AWS_ACCESS_KEY:-}
@@ -314,29 +184,13 @@ services:
ALIYUN_OSS_ACCESS_KEY_SECRET: ${PLUGIN_ALIYUN_OSS_ACCESS_KEY_SECRET:-} ALIYUN_OSS_ACCESS_KEY_SECRET: ${PLUGIN_ALIYUN_OSS_ACCESS_KEY_SECRET:-}
ALIYUN_OSS_AUTH_VERSION: ${PLUGIN_ALIYUN_OSS_AUTH_VERSION:-v4} ALIYUN_OSS_AUTH_VERSION: ${PLUGIN_ALIYUN_OSS_AUTH_VERSION:-v4}
ALIYUN_OSS_PATH: ${PLUGIN_ALIYUN_OSS_PATH:-} 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:-}
SENTRY_ENABLED: ${PLUGIN_SENTRY_ENABLED:-false}
SENTRY_DSN: ${PLUGIN_SENTRY_DSN:-}
ports: ports:
- "${EXPOSE_PLUGIN_DEBUGGING_PORT:-5003}:${PLUGIN_DEBUGGING_PORT:-5003}" - "${EXPOSE_PLUGIN_DEBUGGING_PORT:-5003}:${PLUGIN_DEBUGGING_PORT:-5003}"
volumes: volumes:
- ./volumes/plugin_daemon:/app/storage - ./volumes/plugin_daemon:/app/storage
depends_on: depends_on:
db_postgres: db:
condition: service_healthy condition: service_healthy
required: false
db_mysql:
condition: service_healthy
required: false
oceanbase:
condition: service_healthy
required: false
seekdb:
condition: service_healthy
required: false
# ssrf_proxy server # ssrf_proxy server
# for more information, please refer to # for more information, please refer to
@@ -347,12 +201,7 @@ services:
volumes: volumes:
- ./ssrf_proxy/squid.conf.template:/etc/squid/squid.conf.template - ./ssrf_proxy/squid.conf.template:/etc/squid/squid.conf.template
- ./ssrf_proxy/docker-entrypoint.sh:/docker-entrypoint-mount.sh - ./ssrf_proxy/docker-entrypoint.sh:/docker-entrypoint-mount.sh
entrypoint: 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" ]
[
"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",
]
environment: environment:
# pls clearly modify the squid env vars to fit your network environment. # pls clearly modify the squid env vars to fit your network environment.
HTTP_PORT: ${SSRF_HTTP_PORT:-3128} HTTP_PORT: ${SSRF_HTTP_PORT:-3128}
@@ -381,8 +230,8 @@ services:
- CERTBOT_EMAIL=${CERTBOT_EMAIL} - CERTBOT_EMAIL=${CERTBOT_EMAIL}
- CERTBOT_DOMAIN=${CERTBOT_DOMAIN} - CERTBOT_DOMAIN=${CERTBOT_DOMAIN}
- CERTBOT_OPTIONS=${CERTBOT_OPTIONS:-} - CERTBOT_OPTIONS=${CERTBOT_OPTIONS:-}
entrypoint: ["/docker-entrypoint.sh"] entrypoint: [ '/docker-entrypoint.sh' ]
command: ["tail", "-f", "/dev/null"] command: [ 'tail', '-f', '/dev/null' ]
# The nginx reverse proxy. # The nginx reverse proxy.
# used for reverse proxying the API service and Web service. # used for reverse proxying the API service and Web service.
@@ -399,12 +248,7 @@ services:
- ./volumes/certbot/conf/live:/etc/letsencrypt/live # cert dir (with certbot container) - ./volumes/certbot/conf/live:/etc/letsencrypt/live # cert dir (with certbot container)
- ./volumes/certbot/conf:/etc/letsencrypt - ./volumes/certbot/conf:/etc/letsencrypt
- ./volumes/certbot/www:/var/www/html - ./volumes/certbot/www:/var/www/html
entrypoint: 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" ]
[
"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",
]
environment: environment:
NGINX_SERVER_NAME: ${NGINX_SERVER_NAME:-_} NGINX_SERVER_NAME: ${NGINX_SERVER_NAME:-_}
NGINX_HTTPS_ENABLED: ${NGINX_HTTPS_ENABLED:-false} NGINX_HTTPS_ENABLED: ${NGINX_HTTPS_ENABLED:-false}
@@ -414,9 +258,9 @@ services:
# and modify the env vars below in .env if HTTPS_ENABLED is true. # and modify the env vars below in .env if HTTPS_ENABLED is true.
NGINX_SSL_CERT_FILENAME: ${NGINX_SSL_CERT_FILENAME:-dify.crt} NGINX_SSL_CERT_FILENAME: ${NGINX_SSL_CERT_FILENAME:-dify.crt}
NGINX_SSL_CERT_KEY_FILENAME: ${NGINX_SSL_CERT_KEY_FILENAME:-dify.key} NGINX_SSL_CERT_KEY_FILENAME: ${NGINX_SSL_CERT_KEY_FILENAME:-dify.key}
NGINX_SSL_PROTOCOLS: ${NGINX_SSL_PROTOCOLS:-TLSv1.2 TLSv1.3} NGINX_SSL_PROTOCOLS: ${NGINX_SSL_PROTOCOLS:-TLSv1.1 TLSv1.2 TLSv1.3}
NGINX_WORKER_PROCESSES: ${NGINX_WORKER_PROCESSES:-auto} NGINX_WORKER_PROCESSES: ${NGINX_WORKER_PROCESSES:-auto}
NGINX_CLIENT_MAX_BODY_SIZE: ${NGINX_CLIENT_MAX_BODY_SIZE:-100M} NGINX_CLIENT_MAX_BODY_SIZE: ${NGINX_CLIENT_MAX_BODY_SIZE:-15M}
NGINX_KEEPALIVE_TIMEOUT: ${NGINX_KEEPALIVE_TIMEOUT:-65} NGINX_KEEPALIVE_TIMEOUT: ${NGINX_KEEPALIVE_TIMEOUT:-65}
NGINX_PROXY_READ_TIMEOUT: ${NGINX_PROXY_READ_TIMEOUT:-3600s} NGINX_PROXY_READ_TIMEOUT: ${NGINX_PROXY_READ_TIMEOUT:-3600s}
NGINX_PROXY_SEND_TIMEOUT: ${NGINX_PROXY_SEND_TIMEOUT:-3600s} NGINX_PROXY_SEND_TIMEOUT: ${NGINX_PROXY_SEND_TIMEOUT:-3600s}
@@ -426,13 +270,14 @@ services:
- api - api
- web - web
ports: ports:
- "${EXPOSE_NGINX_PORT:-80}:${NGINX_PORT:-80}" - '${EXPOSE_NGINX_PORT:-80}:${NGINX_PORT:-80}'
- "${EXPOSE_NGINX_SSL_PORT:-443}:${NGINX_SSL_PORT:-443}" - '${EXPOSE_NGINX_SSL_PORT:-443}:${NGINX_SSL_PORT:-443}'
# The Weaviate vector store. # The Weaviate vector store.
weaviate: weaviate:
image: semitechnologies/weaviate:1.27.0 image: semitechnologies/weaviate:1.19.0
profiles: profiles:
- ''
- weaviate - weaviate
restart: always restart: always
volumes: volumes:
@@ -451,73 +296,11 @@ services:
AUTHENTICATION_APIKEY_USERS: ${WEAVIATE_AUTHENTICATION_APIKEY_USERS:-hello@dify.ai} AUTHENTICATION_APIKEY_USERS: ${WEAVIATE_AUTHENTICATION_APIKEY_USERS:-hello@dify.ai}
AUTHORIZATION_ADMINLIST_ENABLED: ${WEAVIATE_AUTHORIZATION_ADMINLIST_ENABLED:-true} AUTHORIZATION_ADMINLIST_ENABLED: ${WEAVIATE_AUTHORIZATION_ADMINLIST_ENABLED:-true}
AUTHORIZATION_ADMINLIST_USERS: ${WEAVIATE_AUTHORIZATION_ADMINLIST_USERS:-hello@dify.ai} AUTHORIZATION_ADMINLIST_USERS: ${WEAVIATE_AUTHORIZATION_ADMINLIST_USERS:-hello@dify.ai}
DISABLE_TELEMETRY: ${WEAVIATE_DISABLE_TELEMETRY:-false}
ENABLE_TOKENIZER_GSE: ${WEAVIATE_ENABLE_TOKENIZER_GSE:-false}
ENABLE_TOKENIZER_KAGOME_JA: ${WEAVIATE_ENABLE_TOKENIZER_KAGOME_JA:-false}
ENABLE_TOKENIZER_KAGOME_KR: ${WEAVIATE_ENABLE_TOKENIZER_KAGOME_KR:-false}
# OceanBase vector database
oceanbase:
image: oceanbase/oceanbase-ce:4.3.5-lts
container_name: oceanbase
profiles:
- oceanbase
restart: always
volumes:
- ./volumes/oceanbase/data:/root/ob
- ./volumes/oceanbase/conf:/root/.obd/cluster
- ./volumes/oceanbase/init.d:/root/boot/init.d
environment:
OB_MEMORY_LIMIT: ${OCEANBASE_MEMORY_LIMIT:-6G}
OB_SYS_PASSWORD: ${OCEANBASE_VECTOR_PASSWORD:-difyai123456}
OB_TENANT_PASSWORD: ${OCEANBASE_VECTOR_PASSWORD:-difyai123456}
OB_CLUSTER_NAME: ${OCEANBASE_CLUSTER_NAME:-difyai}
OB_SERVER_IP: 127.0.0.1
MODE: mini
LANG: C.UTF-8
LC_ALL: C.UTF-8
ports:
- "${OCEANBASE_VECTOR_PORT:-2881}:2881"
healthcheck:
test:
[
"CMD-SHELL",
'obclient -h127.0.0.1 -P2881 -uroot@test -p${OCEANBASE_VECTOR_PASSWORD:-difyai123456} -e "SELECT 1;"',
]
interval: 10s
retries: 30
start_period: 30s
timeout: 10s
# seekdb vector database
seekdb:
image: oceanbase/seekdb:latest
container_name: seekdb
profiles:
- seekdb
restart: always
volumes:
- ./volumes/seekdb:/var/lib/oceanbase
environment:
ROOT_PASSWORD: ${OCEANBASE_VECTOR_PASSWORD:-difyai123456}
MEMORY_LIMIT: ${SEEKDB_MEMORY_LIMIT:-2G}
REPORTER: dify-ai-seekdb
ports:
- "${OCEANBASE_VECTOR_PORT:-2881}:2881"
healthcheck:
test:
[
"CMD-SHELL",
'mysql -h127.0.0.1 -P2881 -uroot -p${OCEANBASE_VECTOR_PASSWORD:-difyai123456} -e "SELECT 1;"',
]
interval: 5s
retries: 60
timeout: 5s
# Qdrant vector store. # Qdrant vector store.
# (if used, you need to set VECTOR_STORE to qdrant in the api & worker service.) # (if used, you need to set VECTOR_STORE to qdrant in the api & worker service.)
qdrant: qdrant:
image: langgenius/qdrant:v1.8.3 image: langgenius/qdrant:v1.7.3
profiles: profiles:
- qdrant - qdrant
restart: always restart: always
@@ -547,17 +330,13 @@ services:
working_dir: /opt/couchbase working_dir: /opt/couchbase
stdin_open: true stdin_open: true
tty: true tty: true
entrypoint: [""] entrypoint: [ "" ]
command: sh -c "/opt/couchbase/init/init-cbserver.sh" command: sh -c "/opt/couchbase/init/init-cbserver.sh"
volumes: volumes:
- ./volumes/couchbase/data:/opt/couchbase/var/lib/couchbase/data - ./volumes/couchbase/data:/opt/couchbase/var/lib/couchbase/data
healthcheck: healthcheck:
# ensure bucket was created before proceeding # ensure bucket was created before proceeding
test: test: [ "CMD-SHELL", "curl -s -f -u Administrator:password http://localhost:8091/pools/default/buckets | grep -q '\\[{' || exit 1" ]
[
"CMD-SHELL",
"curl -s -f -u Administrator:password http://localhost:8091/pools/default/buckets | grep -q '\\[{' || exit 1",
]
interval: 10s interval: 10s
retries: 10 retries: 10
start_period: 30s start_period: 30s
@@ -583,9 +362,9 @@ services:
volumes: volumes:
- ./volumes/pgvector/data:/var/lib/postgresql/data - ./volumes/pgvector/data:/var/lib/postgresql/data
- ./pgvector/docker-entrypoint.sh:/docker-entrypoint.sh - ./pgvector/docker-entrypoint.sh:/docker-entrypoint.sh
entrypoint: ["/docker-entrypoint.sh"] entrypoint: [ '/docker-entrypoint.sh' ]
healthcheck: healthcheck:
test: ["CMD", "pg_isready"] test: [ 'CMD', 'pg_isready' ]
interval: 1s interval: 1s
timeout: 3s timeout: 3s
retries: 30 retries: 30
@@ -602,14 +381,14 @@ services:
- VB_USERNAME=dify - VB_USERNAME=dify
- VB_PASSWORD=Difyai123456 - VB_PASSWORD=Difyai123456
ports: ports:
- "5434:5432" - '5434:5432'
volumes: volumes:
- ./vastbase/lic:/home/vastbase/vastbase/lic - ./vastbase/lic:/home/vastbase/vastbase/lic
- ./vastbase/data:/home/vastbase/data - ./vastbase/data:/home/vastbase/data
- ./vastbase/backup:/home/vastbase/backup - ./vastbase/backup:/home/vastbase/backup
- ./vastbase/backup_log:/home/vastbase/backup_log - ./vastbase/backup_log:/home/vastbase/backup_log
healthcheck: healthcheck:
test: ["CMD", "pg_isready"] test: [ 'CMD', 'pg_isready' ]
interval: 1s interval: 1s
timeout: 3s timeout: 3s
retries: 30 retries: 30
@@ -631,7 +410,7 @@ services:
volumes: volumes:
- ./volumes/pgvecto_rs/data:/var/lib/postgresql/data - ./volumes/pgvecto_rs/data:/var/lib/postgresql/data
healthcheck: healthcheck:
test: ["CMD", "pg_isready"] test: [ 'CMD', 'pg_isready' ]
interval: 1s interval: 1s
timeout: 3s timeout: 3s
retries: 30 retries: 30
@@ -649,26 +428,25 @@ services:
CHROMA_SERVER_AUTHN_PROVIDER: ${CHROMA_SERVER_AUTHN_PROVIDER:-chromadb.auth.token_authn.TokenAuthenticationServerProvider} CHROMA_SERVER_AUTHN_PROVIDER: ${CHROMA_SERVER_AUTHN_PROVIDER:-chromadb.auth.token_authn.TokenAuthenticationServerProvider}
IS_PERSISTENT: ${CHROMA_IS_PERSISTENT:-TRUE} IS_PERSISTENT: ${CHROMA_IS_PERSISTENT:-TRUE}
# InterSystems IRIS vector database # OceanBase vector database
iris: oceanbase:
image: containers.intersystems.com/intersystems/iris-community:2025.3 image: oceanbase/oceanbase-ce:4.3.5.1-101000042025031818
container_name: oceanbase
profiles: profiles:
- iris - oceanbase
container_name: iris
restart: always restart: always
init: true
ports:
- "${IRIS_SUPER_SERVER_PORT:-1972}:1972"
- "${IRIS_WEB_SERVER_PORT:-52773}:52773"
volumes: volumes:
- ./volumes/iris:/durable - ./volumes/oceanbase/data:/root/ob
- ./iris/iris-init.script:/iris-init.script - ./volumes/oceanbase/conf:/root/.obd/cluster
- ./iris/docker-entrypoint.sh:/custom-entrypoint.sh - ./volumes/oceanbase/init.d:/root/boot/init.d
entrypoint: ["/custom-entrypoint.sh"]
tty: true
environment: environment:
TZ: ${IRIS_TIMEZONE:-UTC} OB_MEMORY_LIMIT: ${OCEANBASE_MEMORY_LIMIT:-6G}
ISC_DATA_DIRECTORY: /durable/iris OB_SYS_PASSWORD: ${OCEANBASE_VECTOR_PASSWORD:-difyai123456}
OB_TENANT_PASSWORD: ${OCEANBASE_VECTOR_PASSWORD:-difyai123456}
OB_CLUSTER_NAME: ${OCEANBASE_CLUSTER_NAME:-difyai}
MODE: MINI
ports:
- "${OCEANBASE_VECTOR_PORT:-2881}:2881"
# Oracle vector database # Oracle vector database
oracle: oracle:
@@ -700,7 +478,7 @@ services:
- ./volumes/milvus/etcd:/etcd - ./volumes/milvus/etcd:/etcd
command: etcd -advertise-client-urls=http://127.0.0.1:2379 -listen-client-urls http://0.0.0.0:2379 --data-dir /etcd command: etcd -advertise-client-urls=http://127.0.0.1:2379 -listen-client-urls http://0.0.0.0:2379 --data-dir /etcd
healthcheck: healthcheck:
test: ["CMD", "etcdctl", "endpoint", "health"] test: [ 'CMD', 'etcdctl', 'endpoint', 'health' ]
interval: 30s interval: 30s
timeout: 20s timeout: 20s
retries: 3 retries: 3
@@ -719,7 +497,7 @@ services:
- ./volumes/milvus/minio:/minio_data - ./volumes/milvus/minio:/minio_data
command: minio server /minio_data --console-address ":9001" command: minio server /minio_data --console-address ":9001"
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] test: [ 'CMD', 'curl', '-f', 'http://localhost:9000/minio/health/live' ]
interval: 30s interval: 30s
timeout: 20s timeout: 20s
retries: 3 retries: 3
@@ -728,10 +506,10 @@ services:
milvus-standalone: milvus-standalone:
container_name: milvus-standalone container_name: milvus-standalone
image: milvusdb/milvus:v2.6.3 image: milvusdb/milvus:v2.5.0-beta
profiles: profiles:
- milvus - milvus
command: ["milvus", "run", "standalone"] command: [ 'milvus', 'run', 'standalone' ]
environment: environment:
ETCD_ENDPOINTS: ${ETCD_ENDPOINTS:-etcd:2379} ETCD_ENDPOINTS: ${ETCD_ENDPOINTS:-etcd:2379}
MINIO_ADDRESS: ${MINIO_ADDRESS:-minio:9000} MINIO_ADDRESS: ${MINIO_ADDRESS:-minio:9000}
@@ -739,7 +517,7 @@ services:
volumes: volumes:
- ./volumes/milvus/milvus:/var/lib/milvus - ./volumes/milvus/milvus:/var/lib/milvus
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9091/healthz"] test: [ 'CMD', 'curl', '-f', 'http://localhost:9091/healthz' ]
interval: 30s interval: 30s
start_period: 90s start_period: 90s
timeout: 20s timeout: 20s
@@ -805,7 +583,7 @@ services:
volumes: volumes:
- ./volumes/opengauss/data:/var/lib/opengauss/data - ./volumes/opengauss/data:/var/lib/opengauss/data
healthcheck: healthcheck:
test: ["CMD-SHELL", "netstat -lntp | grep tcp6 > /dev/null 2>&1"] test: [ "CMD-SHELL", "netstat -lntp | grep tcp6 > /dev/null 2>&1" ]
interval: 10s interval: 10s
timeout: 10s timeout: 10s
retries: 10 retries: 10
@@ -827,18 +605,6 @@ services:
ports: ports:
- ${MYSCALE_PORT:-8123}:${MYSCALE_PORT:-8123} - ${MYSCALE_PORT:-8123}:${MYSCALE_PORT:-8123}
# Matrixone vector store.
matrixone:
hostname: matrixone
image: matrixorigin/matrixone:2.1.1
profiles:
- matrixone
restart: always
volumes:
- ./volumes/matrixone/data:/mo-data
ports:
- ${MATRIXONE_PORT:-6001}:${MATRIXONE_PORT:-6001}
# https://www.elastic.co/guide/en/elasticsearch/reference/current/settings.html # https://www.elastic.co/guide/en/elasticsearch/reference/current/settings.html
# https://www.elastic.co/guide/en/elasticsearch/reference/current/docker.html#docker-prod-prerequisites # https://www.elastic.co/guide/en/elasticsearch/reference/current/docker.html#docker-prod-prerequisites
elasticsearch: elasticsearch:
@@ -858,19 +624,18 @@ services:
node.name: dify-es0 node.name: dify-es0
discovery.type: single-node discovery.type: single-node
xpack.license.self_generated.type: basic xpack.license.self_generated.type: basic
xpack.security.enabled: "true" xpack.security.enabled: 'true'
xpack.security.enrollment.enabled: "false" xpack.security.enrollment.enabled: 'false'
xpack.security.http.ssl.enabled: "false" xpack.security.http.ssl.enabled: 'false'
ports: ports:
- ${ELASTICSEARCH_PORT:-9200}:9200 - ${ELASTICSEARCH_PORT:-9200}:9200
deploy: deploy:
resources: resources:
limits: limits:
memory: 2g memory: 2g
entrypoint: ["sh", "-c", "sh /docker-entrypoint-mount.sh"] entrypoint: [ 'sh', '-c', "sh /docker-entrypoint-mount.sh" ]
healthcheck: healthcheck:
test: test: [ 'CMD', 'curl', '-s', 'http://localhost:9200/_cluster/health?pretty' ]
["CMD", "curl", "-s", "http://localhost:9200/_cluster/health?pretty"]
interval: 30s interval: 30s
timeout: 10s timeout: 10s
retries: 50 retries: 50
@@ -888,17 +653,17 @@ services:
environment: environment:
XPACK_ENCRYPTEDSAVEDOBJECTS_ENCRYPTIONKEY: d1a66dfd-c4d3-4a0a-8290-2abcb83ab3aa XPACK_ENCRYPTEDSAVEDOBJECTS_ENCRYPTIONKEY: d1a66dfd-c4d3-4a0a-8290-2abcb83ab3aa
NO_PROXY: localhost,127.0.0.1,elasticsearch,kibana NO_PROXY: localhost,127.0.0.1,elasticsearch,kibana
XPACK_SECURITY_ENABLED: "true" XPACK_SECURITY_ENABLED: 'true'
XPACK_SECURITY_ENROLLMENT_ENABLED: "false" XPACK_SECURITY_ENROLLMENT_ENABLED: 'false'
XPACK_SECURITY_HTTP_SSL_ENABLED: "false" XPACK_SECURITY_HTTP_SSL_ENABLED: 'false'
XPACK_FLEET_ISAIRGAPPED: "true" XPACK_FLEET_ISAIRGAPPED: 'true'
I18N_LOCALE: zh-CN I18N_LOCALE: zh-CN
SERVER_PORT: "5601" SERVER_PORT: '5601'
ELASTICSEARCH_HOSTS: http://elasticsearch:9200 ELASTICSEARCH_HOSTS: http://elasticsearch:9200
ports: ports:
- ${KIBANA_PORT:-5601}:5601 - ${KIBANA_PORT:-5601}:5601
healthcheck: healthcheck:
test: ["CMD-SHELL", "curl -s http://localhost:5601 >/dev/null || exit 1"] test: [ 'CMD-SHELL', 'curl -s http://localhost:5601 >/dev/null || exit 1' ]
interval: 30s interval: 30s
timeout: 10s timeout: 10s
retries: 3 retries: 3
+14 -77
View File
@@ -1,16 +1,13 @@
services: services:
# The postgres database. # The postgres database.
db_postgres: db:
image: postgres:15-alpine image: postgres:15-alpine
profiles:
- ""
- postgresql
restart: always restart: always
env_file: env_file:
- ./middleware.env - ./middleware.env
environment: environment:
POSTGRES_PASSWORD: ${DB_PASSWORD:-difyai123456} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-difyai123456}
POSTGRES_DB: ${DB_DATABASE:-dify} POSTGRES_DB: ${POSTGRES_DB:-dify}
PGDATA: ${PGDATA:-/var/lib/postgresql/data/pgdata} PGDATA: ${PGDATA:-/var/lib/postgresql/data/pgdata}
command: > command: >
postgres -c 'max_connections=${POSTGRES_MAX_CONNECTIONS:-100}' postgres -c 'max_connections=${POSTGRES_MAX_CONNECTIONS:-100}'
@@ -18,57 +15,12 @@ services:
-c 'work_mem=${POSTGRES_WORK_MEM:-4MB}' -c 'work_mem=${POSTGRES_WORK_MEM:-4MB}'
-c 'maintenance_work_mem=${POSTGRES_MAINTENANCE_WORK_MEM:-64MB}' -c 'maintenance_work_mem=${POSTGRES_MAINTENANCE_WORK_MEM:-64MB}'
-c 'effective_cache_size=${POSTGRES_EFFECTIVE_CACHE_SIZE:-4096MB}' -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: volumes:
- ${PGDATA_HOST_VOLUME:-./volumes/db/data}:/var/lib/postgresql/data - ${PGDATA_HOST_VOLUME:-./volumes/db/data}:/var/lib/postgresql/data
ports: ports:
- "${EXPOSE_POSTGRES_PORT:-5432}:5432" - "${EXPOSE_POSTGRES_PORT:-5432}:5432"
healthcheck: healthcheck:
test: test: [ "CMD", "pg_isready" ]
[
"CMD",
"pg_isready",
"-h",
"db_postgres",
"-U",
"${DB_USERNAME:-postgres}",
"-d",
"${DB_DATABASE:-dify}",
]
interval: 1s
timeout: 3s
retries: 30
db_mysql:
image: 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 interval: 1s
timeout: 3s timeout: 3s
retries: 30 retries: 30
@@ -89,11 +41,7 @@ services:
ports: ports:
- "${EXPOSE_REDIS_PORT:-6379}:6379" - "${EXPOSE_REDIS_PORT:-6379}:6379"
healthcheck: healthcheck:
test: test: [ "CMD", "redis-cli", "ping" ]
[
"CMD-SHELL",
"redis-cli -a ${REDIS_PASSWORD:-difyai123456} ping | grep -q PONG",
]
# The DifySandbox # The DifySandbox
sandbox: sandbox:
@@ -117,19 +65,22 @@ services:
- ./volumes/sandbox/dependencies:/dependencies - ./volumes/sandbox/dependencies:/dependencies
- ./volumes/sandbox/conf:/conf - ./volumes/sandbox/conf:/conf
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8194/health"] test: [ "CMD", "curl", "-f", "http://localhost:8194/health" ]
networks: networks:
- ssrf_proxy_network - ssrf_proxy_network
# plugin daemon # plugin daemon
plugin_daemon: plugin_daemon:
image: langgenius/dify-plugin-daemon:0.5.3-local image: langgenius/dify-plugin-daemon:0.0.10-local
restart: always restart: always
env_file: env_file:
- ./middleware.env - ./middleware.env
environment: environment:
# Use the shared environment variables. # Use the shared environment variables.
LOG_OUTPUT_FORMAT: ${LOG_OUTPUT_FORMAT:-text} DB_HOST: ${DB_HOST:-db}
DB_PORT: ${DB_PORT:-5432}
DB_USERNAME: ${DB_USER:-postgres}
DB_PASSWORD: ${DB_PASSWORD:-difyai123456}
DB_DATABASE: ${DB_PLUGIN_DATABASE:-dify_plugin} DB_DATABASE: ${DB_PLUGIN_DATABASE:-dify_plugin}
REDIS_HOST: ${REDIS_HOST:-redis} REDIS_HOST: ${REDIS_HOST:-redis}
REDIS_PORT: ${REDIS_PORT:-6379} REDIS_PORT: ${REDIS_PORT:-6379}
@@ -143,6 +94,7 @@ services:
PLUGIN_REMOTE_INSTALLING_HOST: ${PLUGIN_DEBUGGING_HOST:-0.0.0.0} PLUGIN_REMOTE_INSTALLING_HOST: ${PLUGIN_DEBUGGING_HOST:-0.0.0.0}
PLUGIN_REMOTE_INSTALLING_PORT: ${PLUGIN_DEBUGGING_PORT:-5003} PLUGIN_REMOTE_INSTALLING_PORT: ${PLUGIN_DEBUGGING_PORT:-5003}
PLUGIN_WORKING_PATH: ${PLUGIN_WORKING_PATH:-/app/storage/cwd} PLUGIN_WORKING_PATH: ${PLUGIN_WORKING_PATH:-/app/storage/cwd}
FORCE_VERIFYING_SIGNATURE: ${FORCE_VERIFYING_SIGNATURE:-true}
PYTHON_ENV_INIT_TIMEOUT: ${PLUGIN_PYTHON_ENV_INIT_TIMEOUT:-120} PYTHON_ENV_INIT_TIMEOUT: ${PLUGIN_PYTHON_ENV_INIT_TIMEOUT:-120}
PLUGIN_MAX_EXECUTION_TIMEOUT: ${PLUGIN_MAX_EXECUTION_TIMEOUT:-600} PLUGIN_MAX_EXECUTION_TIMEOUT: ${PLUGIN_MAX_EXECUTION_TIMEOUT:-600}
PIP_MIRROR_URL: ${PIP_MIRROR_URL:-} PIP_MIRROR_URL: ${PIP_MIRROR_URL:-}
@@ -152,7 +104,6 @@ services:
PLUGIN_PACKAGE_CACHE_PATH: ${PLUGIN_PACKAGE_CACHE_PATH:-plugin_packages} PLUGIN_PACKAGE_CACHE_PATH: ${PLUGIN_PACKAGE_CACHE_PATH:-plugin_packages}
PLUGIN_MEDIA_CACHE_PATH: ${PLUGIN_MEDIA_CACHE_PATH:-assets} PLUGIN_MEDIA_CACHE_PATH: ${PLUGIN_MEDIA_CACHE_PATH:-assets}
PLUGIN_STORAGE_OSS_BUCKET: ${PLUGIN_STORAGE_OSS_BUCKET:-} 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_USE_AWS_MANAGED_IAM: ${PLUGIN_S3_USE_AWS_MANAGED_IAM:-false}
S3_ENDPOINT: ${PLUGIN_S3_ENDPOINT:-} S3_ENDPOINT: ${PLUGIN_S3_ENDPOINT:-}
S3_USE_PATH_STYLE: ${PLUGIN_S3_USE_PATH_STYLE:-false} S3_USE_PATH_STYLE: ${PLUGIN_S3_USE_PATH_STYLE:-false}
@@ -170,13 +121,6 @@ services:
ALIYUN_OSS_ACCESS_KEY_SECRET: ${PLUGIN_ALIYUN_OSS_ACCESS_KEY_SECRET:-} ALIYUN_OSS_ACCESS_KEY_SECRET: ${PLUGIN_ALIYUN_OSS_ACCESS_KEY_SECRET:-}
ALIYUN_OSS_AUTH_VERSION: ${PLUGIN_ALIYUN_OSS_AUTH_VERSION:-v4} ALIYUN_OSS_AUTH_VERSION: ${PLUGIN_ALIYUN_OSS_AUTH_VERSION:-v4}
ALIYUN_OSS_PATH: ${PLUGIN_ALIYUN_OSS_PATH:-} 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
ports: ports:
- "${EXPOSE_PLUGIN_DAEMON_PORT:-5002}:${PLUGIN_DAEMON_PORT:-5002}" - "${EXPOSE_PLUGIN_DAEMON_PORT:-5002}:${PLUGIN_DAEMON_PORT:-5002}"
- "${EXPOSE_PLUGIN_DEBUGGING_PORT:-5003}:${PLUGIN_DEBUGGING_PORT:-5003}" - "${EXPOSE_PLUGIN_DEBUGGING_PORT:-5003}:${PLUGIN_DEBUGGING_PORT:-5003}"
@@ -192,12 +136,7 @@ services:
volumes: volumes:
- ./ssrf_proxy/squid.conf.template:/etc/squid/squid.conf.template - ./ssrf_proxy/squid.conf.template:/etc/squid/squid.conf.template
- ./ssrf_proxy/docker-entrypoint.sh:/docker-entrypoint-mount.sh - ./ssrf_proxy/docker-entrypoint.sh:/docker-entrypoint-mount.sh
entrypoint: 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" ]
[
"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: env_file:
- ./middleware.env - ./middleware.env
environment: environment:
@@ -216,7 +155,7 @@ services:
# The Weaviate vector store. # The Weaviate vector store.
weaviate: weaviate:
image: semitechnologies/weaviate:1.27.0 image: semitechnologies/weaviate:1.19.0
profiles: profiles:
- "" - ""
- weaviate - weaviate
@@ -239,10 +178,8 @@ services:
AUTHENTICATION_APIKEY_USERS: ${WEAVIATE_AUTHENTICATION_APIKEY_USERS:-hello@dify.ai} AUTHENTICATION_APIKEY_USERS: ${WEAVIATE_AUTHENTICATION_APIKEY_USERS:-hello@dify.ai}
AUTHORIZATION_ADMINLIST_ENABLED: ${WEAVIATE_AUTHORIZATION_ADMINLIST_ENABLED:-true} AUTHORIZATION_ADMINLIST_ENABLED: ${WEAVIATE_AUTHORIZATION_ADMINLIST_ENABLED:-true}
AUTHORIZATION_ADMINLIST_USERS: ${WEAVIATE_AUTHORIZATION_ADMINLIST_USERS:-hello@dify.ai} AUTHORIZATION_ADMINLIST_USERS: ${WEAVIATE_AUTHORIZATION_ADMINLIST_USERS:-hello@dify.ai}
DISABLE_TELEMETRY: ${WEAVIATE_DISABLE_TELEMETRY:-false}
ports: ports:
- "${EXPOSE_WEAVIATE_PORT:-8080}:8080" - "${EXPOSE_WEAVIATE_PORT:-8080}:8080"
- "${EXPOSE_WEAVIATE_GRPC_PORT:-50051}:50051"
networks: networks:
# create a network between sandbox, api and ssrf_proxy, and can not access outside. # create a network between sandbox, api and ssrf_proxy, and can not access outside.
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -9,7 +9,7 @@ def parse_env_example(file_path):
Parses the .env.example file and returns a dictionary with variable names as keys and default values as values. Parses the .env.example file and returns a dictionary with variable names as keys and default values as values.
""" """
env_vars = {} env_vars = {}
with open(file_path, "r", encoding="utf-8") as f: with open(file_path, "r") as f:
for line_number, line in enumerate(f, 1): for line_number, line in enumerate(f, 1):
line = line.strip() line = line.strip()
# Ignore empty lines and comments # Ignore empty lines and comments
@@ -55,7 +55,7 @@ def insert_shared_env(template_path, output_path, shared_env_block, header_comme
Inserts the shared environment variables block and header comments into the template file, Inserts the shared environment variables block and header comments into the template file,
removing any existing x-shared-env anchors, and generates the final docker-compose.yaml file. removing any existing x-shared-env anchors, and generates the final docker-compose.yaml file.
""" """
with open(template_path, "r", encoding="utf-8") as f: with open(template_path, "r") as f:
template_content = f.read() template_content = f.read()
# Remove existing x-shared-env: &shared-api-worker-env lines # Remove existing x-shared-env: &shared-api-worker-env lines
@@ -69,7 +69,7 @@ def insert_shared_env(template_path, output_path, shared_env_block, header_comme
# Prepare the final content with header comments and shared env block # Prepare the final content with header comments and shared env block
final_content = f"{header_comments}\n{shared_env_block}\n\n{template_content}" final_content = f"{header_comments}\n{shared_env_block}\n\n{template_content}"
with open(output_path, "w", encoding="utf-8") as f: with open(output_path, "w") as f:
f.write(final_content) f.write(final_content)
print(f"Generated {output_path}") print(f"Generated {output_path}")
-56
View File
@@ -1,56 +0,0 @@
#!/bin/bash
set -e
# IRIS configuration flag file (stored in durable directory to persist with data)
IRIS_CONFIG_DONE="/durable/.iris-configured"
# Function to wait for IRIS to be ready
wait_for_iris() {
echo "Waiting for IRIS to be ready..."
local max_attempts=30
local attempt=1
while [ "$attempt" -le "$max_attempts" ]; do
if iris qlist IRIS 2>/dev/null | grep -q "running"; then
echo "IRIS is ready."
return 0
fi
echo "Attempt $attempt/$max_attempts: IRIS not ready yet, waiting..."
sleep 2
attempt=$((attempt + 1))
done
echo "ERROR: IRIS failed to start within expected time." >&2
return 1
}
# Function to configure IRIS
configure_iris() {
echo "Configuring IRIS for first-time setup..."
# Wait for IRIS to be fully started
wait_for_iris
# Execute the initialization script
iris session IRIS < /iris-init.script
# Mark configuration as done
touch "$IRIS_CONFIG_DONE"
echo "IRIS configuration completed."
}
# Start IRIS in background for initial configuration if not already configured
if [ ! -f "$IRIS_CONFIG_DONE" ]; then
echo "First-time IRIS setup detected. Starting IRIS for configuration..."
# Start IRIS
iris start IRIS
# Configure IRIS
configure_iris
# Stop IRIS
iris stop IRIS quietly
fi
# Run the original IRIS entrypoint
exec /iris-main "$@"
-11
View File
@@ -1,11 +0,0 @@
// Switch to the %SYS namespace to modify system settings
set $namespace="%SYS"
// Set predefined user passwords to never expire (default password: SYS)
Do ##class(Security.Users).UnExpireUserPasswords("*")
// Change the default password 
Do $SYSTEM.Security.ChangePassword("_SYSTEM","Dify@1234")
// Install the Japanese locale (default is English since the container is Ubuntu-based)
// Do ##class(Config.NLS.Locales).Install("jpuw")
+6 -95
View File
@@ -1,17 +1,11 @@
# ------------------------------ # ------------------------------
# Environment Variables for db Service # Environment Variables for db Service
# ------------------------------ # ------------------------------
# Database Configuration PGUSER=postgres
# Database type, supported values are `postgresql` and `mysql` # The password for the default postgres user.
DB_TYPE=postgresql POSTGRES_PASSWORD=difyai123456
# For MySQL, only `root` user is supported for now # The name of the default postgres database.
DB_USERNAME=postgres POSTGRES_DB=dify
DB_PASSWORD=difyai123456
DB_HOST=db_postgres
DB_PORT=5432
DB_DATABASE=dify
# PostgreSQL Configuration
# postgres data directory # postgres data directory
PGDATA=/var/lib/postgresql/data/pgdata PGDATA=/var/lib/postgresql/data/pgdata
PGDATA_HOST_VOLUME=./volumes/db/data PGDATA_HOST_VOLUME=./volumes/db/data
@@ -46,54 +40,11 @@ POSTGRES_MAINTENANCE_WORK_MEM=64MB
# Reference: https://www.postgresql.org/docs/current/runtime-config-query.html#GUC-EFFECTIVE-CACHE-SIZE # Reference: https://www.postgresql.org/docs/current/runtime-config-query.html#GUC-EFFECTIVE-CACHE-SIZE
POSTGRES_EFFECTIVE_CACHE_SIZE=4096MB POSTGRES_EFFECTIVE_CACHE_SIZE=4096MB
# Sets the maximum allowed duration of any statement before termination.
# Default is 0 (no timeout).
#
# Reference: https://www.postgresql.org/docs/current/runtime-config-client.html#GUC-STATEMENT-TIMEOUT
# A value of 0 prevents the server from timing out statements.
POSTGRES_STATEMENT_TIMEOUT=0
# Sets the maximum allowed duration of any idle in-transaction session before termination.
# Default is 0 (no timeout).
#
# Reference: https://www.postgresql.org/docs/current/runtime-config-client.html#GUC-IDLE-IN-TRANSACTION-SESSION-TIMEOUT
# A value of 0 prevents the server from terminating idle sessions.
POSTGRES_IDLE_IN_TRANSACTION_SESSION_TIMEOUT=0
# MySQL Configuration
# MySQL data directory host volume
MYSQL_HOST_VOLUME=./volumes/mysql/data
# MySQL Performance Configuration
# Maximum number of connections to MySQL
# Default is 1000
MYSQL_MAX_CONNECTIONS=1000
# InnoDB buffer pool size
# Default is 512M
# Recommended value: 70-80% of available memory for dedicated MySQL server
# Reference: https://dev.mysql.com/doc/refman/8.0/en/innodb-parameters.html#sysvar_innodb_buffer_pool_size
MYSQL_INNODB_BUFFER_POOL_SIZE=512M
# InnoDB log file size
# Default is 128M
# Reference: https://dev.mysql.com/doc/refman/8.0/en/innodb-parameters.html#sysvar_innodb_log_file_size
MYSQL_INNODB_LOG_FILE_SIZE=128M
# InnoDB flush log at transaction commit
# Default is 2 (flush to OS cache, sync every second)
# Options: 0 (no flush), 1 (flush and sync), 2 (flush to OS cache)
# Reference: https://dev.mysql.com/doc/refman/8.0/en/innodb-parameters.html#sysvar_innodb_flush_log_at_trx_commit
MYSQL_INNODB_FLUSH_LOG_AT_TRX_COMMIT=2
# ----------------------------- # -----------------------------
# Environment Variables for redis Service # Environment Variables for redis Service
# ----------------------------- # -----------------------------
REDIS_HOST_VOLUME=./volumes/redis/data REDIS_HOST_VOLUME=./volumes/redis/data
REDIS_PASSWORD=difyai123456 REDIS_PASSWORD=difyai123456
# Optional: limit total Redis connections used by API/Worker (unset for default)
# Align with API's REDIS_MAX_CONNECTIONS in configs
REDIS_MAX_CONNECTIONS=
# ------------------------------ # ------------------------------
# Environment Variables for sandbox Service # Environment Variables for sandbox Service
@@ -126,21 +77,12 @@ WEAVIATE_AUTHENTICATION_APIKEY_ALLOWED_KEYS=WVF5YThaHlkYwhGUSmCRgsX3tD5ngdN8pkih
WEAVIATE_AUTHENTICATION_APIKEY_USERS=hello@dify.ai WEAVIATE_AUTHENTICATION_APIKEY_USERS=hello@dify.ai
WEAVIATE_AUTHORIZATION_ADMINLIST_ENABLED=true WEAVIATE_AUTHORIZATION_ADMINLIST_ENABLED=true
WEAVIATE_AUTHORIZATION_ADMINLIST_USERS=hello@dify.ai WEAVIATE_AUTHORIZATION_ADMINLIST_USERS=hello@dify.ai
WEAVIATE_DISABLE_TELEMETRY=false
WEAVIATE_HOST_VOLUME=./volumes/weaviate WEAVIATE_HOST_VOLUME=./volumes/weaviate
# ------------------------------
# Docker Compose profile configuration
# ------------------------------
# Loaded automatically when running `docker compose --env-file middleware.env ...`.
# Controls which DB/vector services start, so no extra `--profile` flag is needed.
COMPOSE_PROFILES=${DB_TYPE:-postgresql},weaviate
# ------------------------------ # ------------------------------
# Docker Compose Service Expose Host Port Configurations # Docker Compose Service Expose Host Port Configurations
# ------------------------------ # ------------------------------
EXPOSE_POSTGRES_PORT=5432 EXPOSE_POSTGRES_PORT=5432
EXPOSE_MYSQL_PORT=3306
EXPOSE_REDIS_PORT=6379 EXPOSE_REDIS_PORT=6379
EXPOSE_SANDBOX_PORT=8194 EXPOSE_SANDBOX_PORT=8194
EXPOSE_SSRF_PROXY_PORT=3128 EXPOSE_SSRF_PROXY_PORT=3128
@@ -167,7 +109,7 @@ EXPOSE_PLUGIN_DEBUGGING_HOST=localhost
EXPOSE_PLUGIN_DEBUGGING_PORT=5003 EXPOSE_PLUGIN_DEBUGGING_PORT=5003
PLUGIN_DIFY_INNER_API_KEY=QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1 PLUGIN_DIFY_INNER_API_KEY=QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1
PLUGIN_DIFY_INNER_API_URL=http://host.docker.internal:5001 PLUGIN_DIFY_INNER_API_URL=http://api:5001
MARKETPLACE_ENABLED=true MARKETPLACE_ENABLED=true
MARKETPLACE_API_URL=https://marketplace.dify.ai MARKETPLACE_API_URL=https://marketplace.dify.ai
@@ -191,7 +133,6 @@ PLUGIN_MEDIA_CACHE_PATH=assets
PLUGIN_STORAGE_OSS_BUCKET= PLUGIN_STORAGE_OSS_BUCKET=
# Plugin oss s3 credentials # Plugin oss s3 credentials
PLUGIN_S3_USE_AWS_MANAGED_IAM=false PLUGIN_S3_USE_AWS_MANAGED_IAM=false
PLUGIN_S3_USE_AWS=false
PLUGIN_S3_ENDPOINT= PLUGIN_S3_ENDPOINT=
PLUGIN_S3_USE_PATH_STYLE=false PLUGIN_S3_USE_PATH_STYLE=false
PLUGIN_AWS_ACCESS_KEY= PLUGIN_AWS_ACCESS_KEY=
@@ -211,33 +152,3 @@ PLUGIN_ALIYUN_OSS_ACCESS_KEY_ID=
PLUGIN_ALIYUN_OSS_ACCESS_KEY_SECRET= PLUGIN_ALIYUN_OSS_ACCESS_KEY_SECRET=
PLUGIN_ALIYUN_OSS_AUTH_VERSION=v4 PLUGIN_ALIYUN_OSS_AUTH_VERSION=v4
PLUGIN_ALIYUN_OSS_PATH= PLUGIN_ALIYUN_OSS_PATH=
# Plugin oss volcengine tos
PLUGIN_VOLCENGINE_TOS_ENDPOINT=
PLUGIN_VOLCENGINE_TOS_ACCESS_KEY=
PLUGIN_VOLCENGINE_TOS_SECRET_KEY=
PLUGIN_VOLCENGINE_TOS_REGION=
# ------------------------------
# Environment Variables for Aliyun SLS (Simple Log Service)
# ------------------------------
# Aliyun SLS Access Key ID
ALIYUN_SLS_ACCESS_KEY_ID=
# Aliyun SLS Access Key Secret
ALIYUN_SLS_ACCESS_KEY_SECRET=
# Aliyun SLS Endpoint (e.g., cn-hangzhou.log.aliyuncs.com)
ALIYUN_SLS_ENDPOINT=
# Aliyun SLS Region (e.g., cn-hangzhou)
ALIYUN_SLS_REGION=
# Aliyun SLS Project Name
ALIYUN_SLS_PROJECT_NAME=
# Aliyun SLS Logstore TTL (default: 365 days 3650 for permanent storage)
ALIYUN_SLS_LOGSTORE_TTL=365
# Enable dual-write to both LogStore and SQL database (default: true)
LOGSTORE_DUAL_WRITE_ENABLED=true
# Enable dual-read fallback to SQL database when LogStore returns no results (default: true)
# Useful for migration scenarios where historical data exists only in SQL database
LOGSTORE_DUAL_READ_ENABLED=true
# Control flag for whether to write the `graph` field to LogStore.
# If LOGSTORE_ENABLE_PUT_GRAPH_FIELD is "true", write the full `graph` field;
# otherwise write an empty {} instead. Defaults to writing the `graph` field.
LOGSTORE_ENABLE_PUT_GRAPH_FIELD=true
@@ -40,16 +40,6 @@ server {
include proxy.conf; include proxy.conf;
} }
location /mcp {
proxy_pass http://api:5001;
include proxy.conf;
}
location /triggers {
proxy_pass http://api:5001;
include proxy.conf;
}
# placeholder for acme challenge location # placeholder for acme challenge location
${ACME_CHALLENGE_LOCATION} ${ACME_CHALLENGE_LOCATION}
-49
View File
@@ -54,52 +54,3 @@ http_access allow src_all
# Unless the option's size is increased, an error will occur when uploading more than two files. # Unless the option's size is increased, an error will occur when uploading more than two files.
client_request_buffer_max_size 100 MB client_request_buffer_max_size 100 MB
################################## Performance & Concurrency ###############################
# Increase file descriptor limit for high concurrency
max_filedescriptors 65536
# Timeout configurations for image requests
connect_timeout 30 seconds
request_timeout 2 minutes
read_timeout 2 minutes
client_lifetime 5 minutes
shutdown_lifetime 30 seconds
# Persistent connections - improve performance for multiple requests
server_persistent_connections on
client_persistent_connections on
persistent_request_timeout 30 seconds
pconn_timeout 1 minute
# Connection pool and concurrency limits
client_db on
server_idle_pconn_timeout 2 minutes
client_idle_pconn_timeout 2 minutes
# Quick abort settings - don't abort requests that are mostly done
quick_abort_min 16 KB
quick_abort_max 16 MB
quick_abort_pct 95
# Memory and cache optimization
memory_cache_mode disk
cache_mem 256 MB
maximum_object_size_in_memory 512 KB
# DNS resolver settings for better performance
dns_timeout 30 seconds
dns_retransmit_interval 5 seconds
# By default, Squid uses the system's configured DNS resolvers.
# If you need to override them, set dns_nameservers to appropriate servers
# for your environment (for example, internal/corporate DNS). The following
# is an example using public DNS and SHOULD be customized before use:
# dns_nameservers 8.8.8.8 8.8.4.4
# Logging format for better debugging
logformat dify_log %ts.%03tu %6tr %>a %Ss/%03>Hs %<st %rm %ru %[un %Sh/%<a %mt
access_log daemon:/var/log/squid/access.log dify_log
# Access log to track concurrent requests and timeouts
logfile_rotate 10
+1 -2
View File
@@ -55,8 +55,7 @@ services:
- ./volumes/data:/data - ./volumes/data:/data
- ./volumes/logs:/logs - ./volumes/logs:/logs
command: command:
- server - --config=/tiflash.toml
- --config-file=/tiflash.toml
depends_on: depends_on:
- "tikv" - "tikv"
- "tidb" - "tidb"
-12
View File
@@ -4,15 +4,3 @@ await utils.cloneOrPullRepo({ repo: "https://github.com/langgenius/dify.git" });
await utils.copyDir("./repo/docker", "./code"); await utils.copyDir("./repo/docker", "./code");
await utils.removeContainerNames("./code/docker-compose.yaml"); await utils.removeContainerNames("./code/docker-compose.yaml");
await utils.removePorts("./code/docker-compose.yaml"); await utils.removePorts("./code/docker-compose.yaml");
await utils.searchReplace(
"./code/.env.example",
"APP_WEB_URL=",
"APP_WEB_URL=https://$(PRIMARY_DOMAIN)"
);
await utils.searchReplace(
"./code/.env.example",
"SECRET_KEY=sk-9f73s3ljTXVcMT3Blb3ljTqtsKiGHXVcMT3BlbkFJLK7U",
"SECRET_KEY="
);
+13
View File
@@ -0,0 +1,13 @@
#!/bin/bash
if [ ! -d "./repo" ]; then
git clone --depth 1 --branch main --single-branch https://github.com/langgenius/dify.git repo
else
cd repo
git pull
cd ..
fi
cp -r ./repo/docker/. ./code
+3 -41
View File
@@ -1,42 +1,4 @@
# Plane - Project Management Script # Plane
This directory contains the Plane project management tool deployment for Easypanel. - copied from https://github.com/makeplane/plane
- removed `ports`
## Update Process
To update Plane to the latest version, follow these steps in order:
### Step 1: Run the Setup Script for Upgrade
First, run the `setup.sh` script and choose the upgrade option:
```
./setup.sh
```
When prompted, select option **5** for "Upgrade". This will:
* Check for the latest available release
* Download the latest stable version
### Step 2: Run the Update Script
After the setup script completes successfully, run the `update.js` script:
```
node update.js
```
This script will:
* Removes the existing code directory and changes the name for the newly fetched directory to code. 
* Rename `plane.env` to `.env.example`
* Rename `docker-compose.yaml` to `docker-compose.yml`
* Remove container names and ports from docker-compose.yml
* Update environment variables to use Easypanel's `PRIMARY_DOMAIN` variable
## Important Notes
* **Always run setup.sh first** - This ensures you get the latest official Plane release
* **Then run update.js** - This applies Easypanel-specific customizations
* The update process will preserve your existing data and configuration
+5 -27
View File
@@ -1,5 +1,5 @@
APP_DOMAIN=$(PRIMARY_DOMAIN) APP_DOMAIN=localhost
APP_RELEASE=v1.2.3 APP_RELEASE=stable
WEB_REPLICAS=1 WEB_REPLICAS=1
SPACE_REPLICAS=1 SPACE_REPLICAS=1
@@ -9,12 +9,10 @@ WORKER_REPLICAS=1
BEAT_WORKER_REPLICAS=1 BEAT_WORKER_REPLICAS=1
LIVE_REPLICAS=1 LIVE_REPLICAS=1
LISTEN_HTTP_PORT=80 NGINX_PORT=80
LISTEN_HTTPS_PORT=443 WEB_URL=http://${APP_DOMAIN}
WEB_URL=https://$(PRIMARY_DOMAIN)
DEBUG=0 DEBUG=0
CORS_ALLOWED_ORIGINS=https://$(PRIMARY_DOMAIN) CORS_ALLOWED_ORIGINS=http://${APP_DOMAIN}
API_BASE_URL=http://api:8000 API_BASE_URL=http://api:8000
#DB SETTINGS #DB SETTINGS
@@ -40,19 +38,6 @@ RABBITMQ_PASSWORD=plane
RABBITMQ_VHOST=plane RABBITMQ_VHOST=plane
AMQP_URL= AMQP_URL=
# If SSL Cert to be generated, set CERT_EMAIl="email <EMAIL_ADDRESS>"
CERT_ACME_CA=https://acme-v02.api.letsencrypt.org/directory
TRUSTED_PROXIES=0.0.0.0/0
SITE_ADDRESS=:80
CERT_EMAIL=
# For DNS Challenge based certificate generation, set the CERT_ACME_DNS, CERT_EMAIL
# CERT_ACME_DNS="acme_dns <CERT_DNS_PROVIDER> <CERT_DNS_PROVIDER_API_KEY>"
CERT_ACME_DNS=
# Secret Key # Secret Key
SECRET_KEY=60gp0byfz2dvffa45cxl20p1scy9xbpf6d8c5y0geejgkyp1b5 SECRET_KEY=60gp0byfz2dvffa45cxl20p1scy9xbpf6d8c5y0geejgkyp1b5
@@ -76,10 +61,3 @@ MINIO_ENDPOINT_SSL=0
# API key rate limit # API key rate limit
API_KEY_RATE_LIMIT=60/minute API_KEY_RATE_LIMIT=60/minute
# Live server environment variables
# WARNING: You must set a secure value for LIVE_SERVER_SECRET_KEY in production environments.
LIVE_SERVER_SECRET_KEY=
DOCKERHUB_USER=artifacts.plane.so/makeplane
PULL_POLICY=if_not_present
CUSTOM_BUILD=false
+605
View File
@@ -0,0 +1,605 @@
# Self Hosting
In this guide, we will walk you through the process of setting up a self-hosted environment. Self-hosting allows you to have full control over your applications and data. It's a great way to ensure privacy, control, and customization.
We will cover two main options for setting up your self-hosted environment: using a cloud server or using your desktop. For the cloud server, we will use an AWS EC2 instance. For the desktop, we will use Docker to create a local environment.
Let's get started!
## Setting up Docker Environment
<details>
<summary>Option 1 - Using Cloud Server</summary>
<p>Best way to start is to create EC2 machine on AWS. It must have minimum of 2vCPU and 4GB RAM.</p>
<p>Run the below command to install docker engine.</p>
`curl -fsSL https://get.docker.com | sh -`
</details>
---
<details>
<summary>Option 2 - Using Desktop</summary>
#### For Mac
<ol>
<li> Download Docker Desktop for Mac from the <a href="https://hub.docker.com/editions/community/docker-ce-desktop-mac/" target="_blank">Docker Hub</a>. </li>
<li> Double-click the downloaded `.dmg` file and drag the Docker app icon to the Applications folder. </li>
<li>Open Docker Desktop from the Applications folder. You might be asked to provide your system password to install additional software.</li>
</ol>
#### For Windows:
<ol>
<li>Download Docker Desktop for Windows from the <a href="https://hub.docker.com/editions/community/docker-ce-desktop-windows/" target="_blank">Docker Hub</a>.</li>
<li>Run the installer and follow the instructions. You might be asked to enable Hyper-V and "Containers" Windows features.</li>
<li>Open Docker Desktop. You might be asked to log out and log back in, or restart your machine, for changes to take effect.</li>
</ol>
After installation, you can verify the installation by opening a terminal (Command Prompt on Windows, Terminal app on Mac) and running the command `docker --version`. This should display the installed version of Docker.
</details>
---
## Installing Plane
Installing plane is a very easy and minimal step process.
### Prerequisite
- Docker installed and running
- OS with bash scripting enabled (Ubuntu, Linux AMI, macos). Windows systems need to have [gitbash](https://git-scm.com/download/win)
- User context used must have access to docker services. In most cases, use sudo su to switch as root user
- Use the terminal (or gitbash) window to run all the future steps
### Downloading Latest Release
```
mkdir plane-selfhost
cd plane-selfhost
```
#### For *Docker Compose* based setup
```
curl -fsSL -o setup.sh https://github.com/makeplane/plane/releases/latest/download/setup.sh
chmod +x setup.sh
```
#### For *Docker Swarm* based setup
```
curl -fsSL -o setup.sh https://github.com/makeplane/plane/releases/latest/download/swarm.sh
chmod +x setup.sh
```
---
### Proceed with setup
Above steps will set you ready to install and start plane services.
Lets get started by running the `./setup.sh` command.
This will prompt you with the below options.
#### Docker Compose
```bash
Select an Action you want to perform:
1) Install (x86_64)
2) Start
3) Stop
4) Restart
5) Upgrade
6) View Logs
7) Backup Data
8) Exit
Action [2]: 1
```
For the 1st time setup, type "1" as action input.
This will create a folder `plane-app` and will download 2 files inside that
- `docker-compose.yaml`
- `plane.env`
Again the `options [1-8]` will be popped up, and this time hit `8` to exit.
#### Docker Swarm
```bash
Select an Action you want to perform:
1) Deploy Stack
2) Remove Stack
3) View Stack Status
4) Redeploy Stack
5) Upgrade
6) View Logs
7) Exit
Action [3]: 1
```
For the 1st time setup, type "1" as action input.
This will create a create a folder `plane-app` and will download 2 files inside that
- `docker-compose.yaml`
- `plane.env`
Again the `options [1-7]` will be popped up, and this time hit `7` to exit.
---
### Continue with setup - Environment Settings
Before proceeding, we suggest used to review `.env` file and set the values.
Below are the most import keys you must refer to. _<span style="color: #fcba03">You can use any text editor to edit this file</span>_.
> `NGINX_PORT` - This is default set to `80`. Make sure the port you choose to use is not preoccupied. (e.g `NGINX_PORT=8080`)
> `WEB_URL` - This is default set to `http://localhost`. Change this to the FQDN you plan to use along with NGINX_PORT (eg. `https://plane.example.com:8080` or `http://[IP-ADDRESS]:8080`)
> `CORS_ALLOWED_ORIGINS` - This is default set to `http://localhost`. Change this to the FQDN you plan to use along with NGINX_PORT (eg. `https://plane.example.com:8080` or `http://[IP-ADDRESS]:8080`)
There are many other settings you can play with, but we suggest you configure `EMAIL SETTINGS` as it will enable you to invite your teammates onto the platform.
---
### Continue with setup - Start Server (Docker Compose)
Lets again run the `./setup.sh` command. You will again be prompted with the below options. This time select `2` to start the sevices
```bash
Select a Action you want to perform:
1) Install (x86_64)
2) Start
3) Stop
4) Restart
5) Upgrade
6) View Logs
7) Backup Data
8) Exit
Action [2]: 2
```
Expect something like this.
![Downloading docker images](images/download.png)
Be patient as it might take sometime based on download speed and system configuration. If all goes well, you must see something like this
![Downloading completed](images/started.png)
This is the confirmation that all images were downloaded and the services are up & running.
You have successfully self hosted `Plane` instance. Access the application by going to IP or domain you have configured it (e.g `https://plane.example.com:8080` or `http://[IP-ADDRESS]:8080`)
---
### Stopping the Server / Remove Stack
In case you want to make changes to `plane.env` variables, we suggest you to stop the services before doing that.
#### Docker Compose
Lets again run the `./setup.sh` command. You will again be prompted with the below options. This time select `3` to stop the sevices
```bash
Select a Action you want to perform:
1) Install (x86_64)
2) Start
3) Stop
4) Restart
5) Upgrade
6) View Logs
7) Backup Data
8) Exit
Action [2]: 3
```
If all goes well, you must see something like this
![Stop Services](images/stopped.png)
#### Docker Swarm
Lets again run the `./setup.sh` command. You will again be prompted with the below options. This time select `2` to stop the sevices
```bash
Select an Action you want to perform:
1) Deploy Stack
2) Remove Stack
3) View Stack Status
4) Redeploy Stack
5) Upgrade
6) View Logs
7) Exit
Action [3]: 2
```
If all goes well, you will see the confirmation from docker cli
---
### Restarting the Server / Redeploy Stack
In case you want to make changes to `plane.env` variables, without stopping the server or you noticed some abnormalies in services, you can restart the services with `RESTART` / `REDEPLOY` option.
Lets again run the `./setup.sh` command. You will again be prompted with the below options. This time select `4` to restart the sevices
#### Docker Compose
```bash
Select a Action you want to perform:
1) Install (x86_64)
2) Start
3) Stop
4) Restart
5) Upgrade
6) View Logs
7) Backup Data
8) Exit
Action [2]: 4
```
If all goes well, you must see something like this
![Restart Services](images/restart.png)
#### Docker Swarm
```bash
1) Deploy Stack
2) Remove Stack
3) View Stack Status
4) Redeploy Stack
5) Upgrade
6) View Logs
7) Exit
Action [3]: 4
```
If all goes well, you will see the confirmation from docker cli
---
### Upgrading Plane Version
It is always advised to keep Plane up to date with the latest release.
Lets again run the `./setup.sh` command. You will again be prompted with the below options. This time select `5` to upgrade the release.
#### Docker Compose
```bash
Select a Action you want to perform:
1) Install (x86_64)
2) Start
3) Stop
4) Restart
5) Upgrade
6) View Logs
7) Backup Data
8) Exit
Action [2]: 5
```
By choosing this, it will stop the services and then will download the latest `docker-compose.yaml` and `plane.env`.
You must expect the below message
![Alt text](images/upgrade.png)
Once done, choose `8` to exit from prompt.
> It is very important for you to validate the `plane.env` for the new changes.
Once done with making changes in `plane.env` file, jump on to `Start Server`
#### Docker Swarm
Lets again run the `./setup.sh` command. You will again be prompted with the below options. This time select `5` to upgrade the release.
```bash
1) Deploy Stack
2) Remove Stack
3) View Stack Status
4) Redeploy Stack
5) Upgrade
6) View Logs
7) Exit
Action [3]: 5
```
By choosing this, it will stop the services and then will download the latest `docker-compose.yaml` and `plane.env`.
Once done, choose `7` to exit from prompt.
> It is very important for you to validate the `plane.env` for the new changes.
Once done with making changes in `plane.env` file, jump on to `Redeploy Stack`
---
### View Logs
There would a time when you might want to check what is happening inside the API, Worker or any other container.
Lets again run the `./setup.sh` command. You will again be prompted with the below options.
This time select `6` to view logs.
#### Docker Compose
```bash
Select a Action you want to perform:
1) Install (x86_64)
2) Start
3) Stop
4) Restart
5) Upgrade
6) View Logs
7) Backup Data
8) Exit
Action [2]: 6
```
#### Docker Swarm
```bash
1) Deploy Stack
2) Remove Stack
3) View Stack Status
4) Redeploy Stack
5) Upgrade
6) View Logs
7) Exit
Action [3]: 6
```
#### Service Menu Options for Logs
This will further open sub-menu with list of services
```bash
Select a Service you want to view the logs for:
1) Web
2) Space
3) API
4) Worker
5) Beat-Worker
6) Migrator
7) Proxy
8) Redis
9) Postgres
10) Minio
11) RabbitMQ
0) Back to Main Menu
Service: 3
```
Select any of the service to view the logs e.g. `3`. Expect something similar to this
```bash
api-1 | Waiting for database...
api-1 | Database available!
api-1 | Waiting for database migrations to complete...
api-1 | Waiting for database migrations to complete...
api-1 | Waiting for database migrations to complete...
api-1 | Waiting for database migrations to complete...
api-1 | Waiting for database migrations to complete...
api-1 | Waiting for database migrations to complete...
api-1 | Waiting for database migrations to complete...
api-1 | No migrations Pending. Starting processes ...
api-1 | Instance registered
api-1 | ENABLE_SIGNUP loaded with value from environment variable.
api-1 | ENABLE_EMAIL_PASSWORD loaded with value from environment variable.
api-1 | ENABLE_MAGIC_LINK_LOGIN loaded with value from environment variable.
api-1 | GOOGLE_CLIENT_ID loaded with value from environment variable.
api-1 | GITHUB_CLIENT_ID loaded with value from environment variable.
api-1 | GITHUB_CLIENT_SECRET loaded with value from environment variable.
api-1 | EMAIL_HOST loaded with value from environment variable.
api-1 | EMAIL_HOST_USER loaded with value from environment variable.
api-1 | EMAIL_HOST_PASSWORD loaded with value from environment variable.
api-1 | EMAIL_PORT loaded with value from environment variable.
api-1 | EMAIL_FROM loaded with value from environment variable.
api-1 | EMAIL_USE_TLS loaded with value from environment variable.
api-1 | EMAIL_USE_SSL loaded with value from environment variable.
api-1 | OPENAI_API_KEY loaded with value from environment variable.
api-1 | GPT_ENGINE loaded with value from environment variable.
api-1 | UNSPLASH_ACCESS_KEY loaded with value from environment variable.
api-1 | Checking bucket...
api-1 | Bucket 'uploads' does not exist. Creating bucket...
api-1 | Bucket 'uploads' created successfully.
api-1 | Public read access policy set for bucket 'uploads'.
api-1 | Cache Cleared
api-1 | [2024-05-02 03:56:01 +0000] [1] [INFO] Starting gunicorn 21.2.0
api-1 | [2024-05-02 03:56:01 +0000] [1] [INFO] Listening at: http://0.0.0.0:8000 (1)
api-1 | [2024-05-02 03:56:01 +0000] [1] [INFO] Using worker: uvicorn.workers.UvicornWorker
api-1 | [2024-05-02 03:56:01 +0000] [25] [INFO] Booting worker with pid: 25
api-1 | [2024-05-02 03:56:03 +0000] [25] [INFO] Started server process [25]
api-1 | [2024-05-02 03:56:03 +0000] [25] [INFO] Waiting for application startup.
api-1 | [2024-05-02 03:56:03 +0000] [25] [INFO] ASGI 'lifespan' protocol appears unsupported.
api-1 | [2024-05-02 03:56:03 +0000] [25] [INFO] Application startup complete.
```
To exit this, use `CTRL+C` and then you will land on to the main-menu with the list of actions.
Similarly, you can view the logs of other services.
---
### Backup Data (Docker Compose)
There would a time when you might want to backup your data from docker volumes to external storage like S3 or drives.
Lets again run the `./setup.sh` command. You will again be prompted with the below options. This time select `7` to Backup the data.
```bash
Select a Action you want to perform:
1) Install (x86_64)
2) Start
3) Stop
4) Restart
5) Upgrade
6) View Logs
7) Backup Data
8) Exit
Action [2]: 7
```
In response, you can find the backup folder
```bash
Backing Up plane-app_pgdata
Backing Up plane-app_redisdata
Backing Up plane-app_uploads
Backup completed successfully. Backup files are stored in /....../plane-app/backup/20240502-1120
```
---
### Restore Data (Docker Compose)
When you want to restore the previously backed-up data, follow the instructions below.
1. Make sure that Plane-CE is installed, started, and then stopped. This ensures that the Docker volumes are created.
1. Download the restore script using the command below. We suggest downloading it in the same folder as `setup.sh`.
```bash
curl -fsSL -o restore.sh https://raw.githubusercontent.com/makeplane/plane/master/deploy/selfhost/restore.sh
chmod +x restore.sh
```
1. Execute the command below to restore your data.
```bash
./restore.sh <path to backup folder containing *.tar.gz files>
```
As an example, for a backup folder `/opt/plane-selfhost/plane-app/backup/20240722-0914`, expect the response below:
```bash
--------------------------------------------
____ _ /////////
| _ \| | __ _ _ __ ___ /////////
| |_) | |/ _` | '_ \ / _ \ ///// /////
| __/| | (_| | | | | __/ ///// /////
|_| |_|\__,_|_| |_|\___| ////
////
--------------------------------------------
Project management tool from the future
--------------------------------------------
Found /opt/plane-selfhost/plane-app/backup/20240722-0914/pgdata.tar.gz
.....Restoring plane-app_pgdata
.....Successfully restored volume plane-app_pgdata from pgdata.tar.gz
Found /opt/plane-selfhost/plane-app/backup/20240722-0914/redisdata.tar.gz
.....Restoring plane-app_redisdata
.....Successfully restored volume plane-app_redisdata from redisdata.tar.gz
Found /opt/plane-selfhost/plane-app/backup/20240722-0914/uploads.tar.gz
.....Restoring plane-app_uploads
.....Successfully restored volume plane-app_uploads from uploads.tar.gz
Restore completed successfully.
```
1. Start the Plane instance using `./setup.sh start`.
---
<details>
<summary><h2>Upgrading from v0.13.2 to v0.14.x</h2></summary>
This is one time activity for users who are upgrading from v0.13.2 to v0.14.0
As there has been significant changes to Self Hosting process, this step mainly covers the data migration from current (v0.13.2) docker volumes from newly created volumes
> Before we begin with migration, make sure your v0.14.0 was started and then stopped. This is required to know the newly created docker volume names.
Begin with downloading the migration script using below command
```
curl -fsSL -o migrate.sh https://raw.githubusercontent.com/makeplane/plane/master/deploy/selfhost/migration-0.13-0.14.sh
chmod +x migrate.sh
```
Now run the `./migrate.sh` command and expect the instructions as below
```
******************************************************************
This script is solely for the migration purpose only.
This is a 1 time migration of volume data from v0.13.2 => v0.14.x
Assumption:
1. Postgres data volume name ends with _pgdata
2. Minio data volume name ends with _uploads
3. Redis data volume name ends with _redisdata
Any changes to this script can break the migration.
Before you proceed, make sure you run the below command
to know the docker volumes
docker volume ls -q | grep -i "_pgdata"
docker volume ls -q | grep -i "_uploads"
docker volume ls -q | grep -i "_redisdata"
*******************************************************
Given below list of REDIS volumes, identify the prefix of source and destination volumes leaving "_redisdata"
---------------------
plane-app_redisdata
v0132_redisdata
Provide the Source Volume Prefix :
```
**Open another terminal window**, and run the mentioned 3 command. This may be different for users who have changed the volume names in their previous setup (v0.13.2)
For every command you must see 2 records something like shown in above example of `redisdata`
To move forward, you would need PREFIX of old setup and new setup. As per above example, `v0132` is the prefix of v0.13.2 and `plane-app` is the prefix of v0.14.0 setup
**Back to original terminal window**, _Provide the Source Volume Prefix_ and hit ENTER.
Now you will be prompted to _Provide Destination Volume Prefix_. Provide the value and hit ENTER
```
Provide the Source Volume Prefix : v0132
Provide the Destination Volume Prefix : plane-app
```
In case the suffixes are wrong or the mentioned volumes are not found, you will receive the error shown below. The image below displays an error for source volumes.
![Migrate Error](images/migrate-error.png)
In case of successful migration, it will be a silent exit without error.
Now its time to restart v0.14.0 setup.
</details>
+30
View File
@@ -0,0 +1,30 @@
services:
web:
image: ${DOCKERHUB_USER:-local}/plane-frontend:${APP_RELEASE:-latest}
build:
context: .
dockerfile: ./web/Dockerfile.web
space:
image: ${DOCKERHUB_USER:-local}/plane-space:${APP_RELEASE:-latest}
build:
context: ./
dockerfile: ./space/Dockerfile.space
admin:
image: ${DOCKERHUB_USER:-local}/plane-admin:${APP_RELEASE:-latest}
build:
context: ./
dockerfile: ./admin/Dockerfile.admin
api:
image: ${DOCKERHUB_USER:-local}/plane-backend:${APP_RELEASE:-latest}
build:
context: ./apiserver
dockerfile: ./Dockerfile.api
proxy:
image: ${DOCKERHUB_USER:-local}/plane-proxy:${APP_RELEASE:-latest}
build:
context: ./nginx
dockerfile: ./Dockerfile
+31 -42
View File
@@ -24,15 +24,9 @@ x-aws-s3-env: &aws-s3-env
AWS_S3_BUCKET_NAME: ${AWS_S3_BUCKET_NAME:-uploads} AWS_S3_BUCKET_NAME: ${AWS_S3_BUCKET_NAME:-uploads}
x-proxy-env: &proxy-env x-proxy-env: &proxy-env
APP_DOMAIN: ${APP_DOMAIN:-localhost} NGINX_PORT: ${NGINX_PORT:-80}
FILE_SIZE_LIMIT: ${FILE_SIZE_LIMIT:-5242880}
CERT_EMAIL: ${CERT_EMAIL}
CERT_ACME_CA: ${CERT_ACME_CA}
CERT_ACME_DNS: ${CERT_ACME_DNS}
LISTEN_HTTP_PORT: ${LISTEN_HTTP_PORT:-80}
LISTEN_HTTPS_PORT: ${LISTEN_HTTPS_PORT:-443}
BUCKET_NAME: ${AWS_S3_BUCKET_NAME:-uploads} BUCKET_NAME: ${AWS_S3_BUCKET_NAME:-uploads}
SITE_ADDRESS: ${SITE_ADDRESS:-:80} FILE_SIZE_LIMIT: ${FILE_SIZE_LIMIT:-5242880}
x-mq-env: x-mq-env:
# RabbitMQ Settings # RabbitMQ Settings
@@ -46,7 +40,6 @@ x-mq-env:
x-live-env: &live-env x-live-env: &live-env
API_BASE_URL: ${API_BASE_URL:-http://api:8000} API_BASE_URL: ${API_BASE_URL:-http://api:8000}
LIVE_SERVER_SECRET_KEY: ${LIVE_SERVER_SECRET_KEY:-2FiJk1U2aiVPEQtzLehYGlTSnTnrs7LW}
x-app-env: &app-env x-app-env: &app-env
WEB_URL: ${WEB_URL:-http://localhost} WEB_URL: ${WEB_URL:-http://localhost}
@@ -59,59 +52,62 @@ x-app-env: &app-env
AMQP_URL: ${AMQP_URL:-amqp://plane:plane@plane-mq:5672/plane} AMQP_URL: ${AMQP_URL:-amqp://plane:plane@plane-mq:5672/plane}
API_KEY_RATE_LIMIT: ${API_KEY_RATE_LIMIT:-60/minute} API_KEY_RATE_LIMIT: ${API_KEY_RATE_LIMIT:-60/minute}
MINIO_ENDPOINT_SSL: ${MINIO_ENDPOINT_SSL:-0} MINIO_ENDPOINT_SSL: ${MINIO_ENDPOINT_SSL:-0}
LIVE_SERVER_SECRET_KEY: ${LIVE_SERVER_SECRET_KEY:-2FiJk1U2aiVPEQtzLehYGlTSnTnrs7LW}
services: services:
web: web:
image: artifacts.plane.so/makeplane/plane-frontend:${APP_RELEASE:-v1.2.3} image: artifacts.plane.so/makeplane/plane-frontend:${APP_RELEASE:-stable}
command: node web/server.js web
deploy: deploy:
replicas: ${WEB_REPLICAS:-1} replicas: ${WEB_REPLICAS:-1}
restart_policy: restart_policy:
condition: any condition: on-failure
depends_on: depends_on:
- api - api
- worker - worker
space: space:
image: artifacts.plane.so/makeplane/plane-space:${APP_RELEASE:-v1.2.3} image: artifacts.plane.so/makeplane/plane-space:${APP_RELEASE:-stable}
command: node space/server.js space
deploy: deploy:
replicas: ${SPACE_REPLICAS:-1} replicas: ${SPACE_REPLICAS:-1}
restart_policy: restart_policy:
condition: any condition: on-failure
depends_on: depends_on:
- api - api
- worker - worker
- web - web
admin: admin:
image: artifacts.plane.so/makeplane/plane-admin:${APP_RELEASE:-v1.2.3} image: artifacts.plane.so/makeplane/plane-admin:${APP_RELEASE:-stable}
command: node admin/server.js admin
deploy: deploy:
replicas: ${ADMIN_REPLICAS:-1} replicas: ${ADMIN_REPLICAS:-1}
restart_policy: restart_policy:
condition: any condition: on-failure
depends_on: depends_on:
- api - api
- web - web
live: live:
image: artifacts.plane.so/makeplane/plane-live:${APP_RELEASE:-v1.2.3} image: artifacts.plane.so/makeplane/plane-live:${APP_RELEASE:-stable}
command: node live/dist/server.js live
environment: environment:
<<: [ *live-env, *redis-env ] <<: [ *live-env ]
deploy: deploy:
replicas: ${LIVE_REPLICAS:-1} replicas: ${LIVE_REPLICAS:-1}
restart_policy: restart_policy:
condition: any condition: on-failure
depends_on: depends_on:
- api - api
- web - web
api: api:
image: artifacts.plane.so/makeplane/plane-backend:${APP_RELEASE:-v1.2.3} image: artifacts.plane.so/makeplane/plane-backend:${APP_RELEASE:-stable}
command: ./bin/docker-entrypoint-api.sh command: ./bin/docker-entrypoint-api.sh
deploy: deploy:
replicas: ${API_REPLICAS:-1} replicas: ${API_REPLICAS:-1}
restart_policy: restart_policy:
condition: any condition: on-failure
volumes: volumes:
- logs_api:/code/plane/logs - logs_api:/code/plane/logs
environment: environment:
@@ -122,12 +118,12 @@ services:
- plane-mq - plane-mq
worker: worker:
image: artifacts.plane.so/makeplane/plane-backend:${APP_RELEASE:-v1.2.3} image: artifacts.plane.so/makeplane/plane-backend:${APP_RELEASE:-stable}
command: ./bin/docker-entrypoint-worker.sh command: ./bin/docker-entrypoint-worker.sh
deploy: deploy:
replicas: ${WORKER_REPLICAS:-1} replicas: ${WORKER_REPLICAS:-1}
restart_policy: restart_policy:
condition: any condition: on-failure
volumes: volumes:
- logs_worker:/code/plane/logs - logs_worker:/code/plane/logs
environment: environment:
@@ -139,12 +135,12 @@ services:
- plane-mq - plane-mq
beat-worker: beat-worker:
image: artifacts.plane.so/makeplane/plane-backend:${APP_RELEASE:-v1.2.3} image: artifacts.plane.so/makeplane/plane-backend:${APP_RELEASE:-stable}
command: ./bin/docker-entrypoint-beat.sh command: ./bin/docker-entrypoint-beat.sh
deploy: deploy:
replicas: ${BEAT_WORKER_REPLICAS:-1} replicas: ${BEAT_WORKER_REPLICAS:-1}
restart_policy: restart_policy:
condition: any condition: on-failure
volumes: volumes:
- logs_beat-worker:/code/plane/logs - logs_beat-worker:/code/plane/logs
environment: environment:
@@ -156,7 +152,7 @@ services:
- plane-mq - plane-mq
migrator: migrator:
image: artifacts.plane.so/makeplane/plane-backend:${APP_RELEASE:-v1.2.3} image: artifacts.plane.so/makeplane/plane-backend:${APP_RELEASE:-stable}
command: ./bin/docker-entrypoint-migrator.sh command: ./bin/docker-entrypoint-migrator.sh
deploy: deploy:
replicas: 1 replicas: 1
@@ -177,18 +173,18 @@ services:
deploy: deploy:
replicas: 1 replicas: 1
restart_policy: restart_policy:
condition: any condition: on-failure
environment: environment:
<<: *db-env <<: *db-env
volumes: volumes:
- pgdata:/var/lib/postgresql/data - pgdata:/var/lib/postgresql/data
plane-redis: plane-redis:
image: valkey/valkey:7.2.11-alpine image: valkey/valkey:7.2.5-alpine
deploy: deploy:
replicas: 1 replicas: 1
restart_policy: restart_policy:
condition: any condition: on-failure
volumes: volumes:
- redisdata:/data - redisdata:/data
@@ -197,7 +193,7 @@ services:
deploy: deploy:
replicas: 1 replicas: 1
restart_policy: restart_policy:
condition: any condition: on-failure
environment: environment:
<<: *mq-env <<: *mq-env
volumes: volumes:
@@ -210,7 +206,7 @@ services:
deploy: deploy:
replicas: 1 replicas: 1
restart_policy: restart_policy:
condition: any condition: on-failure
environment: environment:
<<: *minio-env <<: *minio-env
volumes: volumes:
@@ -218,22 +214,17 @@ services:
# Comment this if you already have a reverse proxy running # Comment this if you already have a reverse proxy running
proxy: proxy:
image: artifacts.plane.so/makeplane/plane-proxy:${APP_RELEASE:-v1.2.3} image: artifacts.plane.so/makeplane/plane-proxy:${APP_RELEASE:-stable}
environment:
<<: *proxy-env
deploy: deploy:
replicas: 1 replicas: 1
restart_policy: restart_policy:
condition: any condition: on-failure
environment:
<<: *proxy-env
volumes:
- proxy_config:/config
- proxy_data:/data
depends_on: depends_on:
- web - web
- api - api
- space - space
- admin
- live
volumes: volumes:
pgdata: pgdata:
@@ -244,5 +235,3 @@ volumes:
logs_beat-worker: logs_beat-worker:
logs_migrator: logs_migrator:
rabbitmq_data: rabbitmq_data:
proxy_config:
proxy_data:
Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

+8 -8
View File
@@ -2,14 +2,14 @@
BRANCH=${BRANCH:-master} BRANCH=${BRANCH:-master}
SCRIPT_DIR=$PWD SCRIPT_DIR=$PWD
SERVICE_FOLDER=plane-code SERVICE_FOLDER=plane-app
PLANE_INSTALL_DIR=$PWD/$SERVICE_FOLDER PLANE_INSTALL_DIR=$PWD/$SERVICE_FOLDER
export APP_RELEASE=stable export APP_RELEASE=stable
export DOCKERHUB_USER=artifacts.plane.so/makeplane export DOCKERHUB_USER=artifacts.plane.so/makeplane
export PULL_POLICY=${PULL_POLICY:-if_not_present} export PULL_POLICY=${PULL_POLICY:-if_not_present}
export GH_REPO=makeplane/plane export GH_REPO=makeplane/plane
export RELEASE_DOWNLOAD_URL="https://github.com/$GH_REPO/releases/download" export RELEASE_DOWNLOAD_URL="https://github.com/$GH_REPO/releases/download"
export FALLBACK_DOWNLOAD_URL="https://raw.githubusercontent.com/$GH_REPO/$BRANCH/deployments/cli/community" export FALLBACK_DOWNLOAD_URL="https://raw.githubusercontent.com/$GH_REPO/$BRANCH/deploy/selfhost"
CPU_ARCH=$(uname -m) CPU_ARCH=$(uname -m)
OS_NAME=$(uname) OS_NAME=$(uname)
@@ -57,7 +57,7 @@ function spinner() {
function checkLatestRelease(){ function checkLatestRelease(){
echo "Checking for the latest release..." >&2 echo "Checking for the latest release..." >&2
local latest_release=$(curl -fsSL https://api.github.com/repos/$GH_REPO/releases/latest | grep -o '"tag_name": "[^"]*"' | sed 's/"tag_name": "//;s/"//g') local latest_release=$(curl -s https://api.github.com/repos/$GH_REPO/releases/latest | grep -o '"tag_name": "[^"]*"' | sed 's/"tag_name": "//;s/"//g')
if [ -z "$latest_release" ]; then if [ -z "$latest_release" ]; then
echo "Failed to check for the latest release. Exiting..." >&2 echo "Failed to check for the latest release. Exiting..." >&2
exit 1 exit 1
@@ -196,7 +196,7 @@ function buildYourOwnImage(){
REPO=https://github.com/$GH_REPO.git REPO=https://github.com/$GH_REPO.git
git clone "$REPO" "$PLANE_TEMP_CODE_DIR" --branch "$BRANCH" --single-branch --depth 1 git clone "$REPO" "$PLANE_TEMP_CODE_DIR" --branch "$BRANCH" --single-branch --depth 1
cp "$PLANE_TEMP_CODE_DIR/deployments/cli/community/build.yml" "$PLANE_TEMP_CODE_DIR/build.yml" cp "$PLANE_TEMP_CODE_DIR/deploy/selfhost/build.yml" "$PLANE_TEMP_CODE_DIR/build.yml"
cd "$PLANE_TEMP_CODE_DIR" || exit cd "$PLANE_TEMP_CODE_DIR" || exit
@@ -247,7 +247,7 @@ function download() {
mv $PLANE_INSTALL_DIR/docker-compose.yaml $PLANE_INSTALL_DIR/archive/$TS.docker-compose.yaml mv $PLANE_INSTALL_DIR/docker-compose.yaml $PLANE_INSTALL_DIR/archive/$TS.docker-compose.yaml
fi fi
RESPONSE=$(curl -fsSL -H 'Cache-Control: no-cache, no-store' -s -w "HTTPSTATUS:%{http_code}" "$RELEASE_DOWNLOAD_URL/$APP_RELEASE/docker-compose.yml?$(date +%s)") RESPONSE=$(curl -H 'Cache-Control: no-cache, no-store' -s -w "HTTPSTATUS:%{http_code}" "$RELEASE_DOWNLOAD_URL/$APP_RELEASE/docker-compose.yml?$(date +%s)")
BODY=$(echo "$RESPONSE" | sed -e 's/HTTPSTATUS\:.*//g') BODY=$(echo "$RESPONSE" | sed -e 's/HTTPSTATUS\:.*//g')
STATUS=$(echo "$RESPONSE" | tr -d '\n' | sed -e 's/.*HTTPSTATUS://') STATUS=$(echo "$RESPONSE" | tr -d '\n' | sed -e 's/.*HTTPSTATUS://')
@@ -255,7 +255,7 @@ function download() {
echo "$BODY" > $PLANE_INSTALL_DIR/docker-compose.yaml echo "$BODY" > $PLANE_INSTALL_DIR/docker-compose.yaml
else else
# Fallback to download from the raw github url # Fallback to download from the raw github url
RESPONSE=$(curl -fsSL -H 'Cache-Control: no-cache, no-store' -s -w "HTTPSTATUS:%{http_code}" "$FALLBACK_DOWNLOAD_URL/docker-compose.yml?$(date +%s)") RESPONSE=$(curl -H 'Cache-Control: no-cache, no-store' -s -w "HTTPSTATUS:%{http_code}" "$FALLBACK_DOWNLOAD_URL/docker-compose.yml?$(date +%s)")
BODY=$(echo "$RESPONSE" | sed -e 's/HTTPSTATUS\:.*//g') BODY=$(echo "$RESPONSE" | sed -e 's/HTTPSTATUS\:.*//g')
STATUS=$(echo "$RESPONSE" | tr -d '\n' | sed -e 's/.*HTTPSTATUS://') STATUS=$(echo "$RESPONSE" | tr -d '\n' | sed -e 's/.*HTTPSTATUS://')
@@ -269,7 +269,7 @@ function download() {
fi fi
fi fi
RESPONSE=$(curl -fsSL -H 'Cache-Control: no-cache, no-store' -s -w "HTTPSTATUS:%{http_code}" "$RELEASE_DOWNLOAD_URL/$APP_RELEASE/variables.env?$(date +%s)") RESPONSE=$(curl -H 'Cache-Control: no-cache, no-store' -s -w "HTTPSTATUS:%{http_code}" "$RELEASE_DOWNLOAD_URL/$APP_RELEASE/variables.env?$(date +%s)")
BODY=$(echo "$RESPONSE" | sed -e 's/HTTPSTATUS\:.*//g') BODY=$(echo "$RESPONSE" | sed -e 's/HTTPSTATUS\:.*//g')
STATUS=$(echo "$RESPONSE" | tr -d '\n' | sed -e 's/.*HTTPSTATUS://') STATUS=$(echo "$RESPONSE" | tr -d '\n' | sed -e 's/.*HTTPSTATUS://')
@@ -277,7 +277,7 @@ function download() {
echo "$BODY" > $PLANE_INSTALL_DIR/variables-upgrade.env echo "$BODY" > $PLANE_INSTALL_DIR/variables-upgrade.env
else else
# Fallback to download from the raw github url # Fallback to download from the raw github url
RESPONSE=$(curl -fsSL -H 'Cache-Control: no-cache, no-store' -s -w "HTTPSTATUS:%{http_code}" "$FALLBACK_DOWNLOAD_URL/variables.env?$(date +%s)") RESPONSE=$(curl -H 'Cache-Control: no-cache, no-store' -s -w "HTTPSTATUS:%{http_code}" "$FALLBACK_DOWNLOAD_URL/variables.env?$(date +%s)")
BODY=$(echo "$RESPONSE" | sed -e 's/HTTPSTATUS\:.*//g') BODY=$(echo "$RESPONSE" | sed -e 's/HTTPSTATUS\:.*//g')
STATUS=$(echo "$RESPONSE" | tr -d '\n' | sed -e 's/.*HTTPSTATUS://') STATUS=$(echo "$RESPONSE" | tr -d '\n' | sed -e 's/.*HTTPSTATUS://')
+118
View File
@@ -0,0 +1,118 @@
#!/bin/bash
echo '
******************************************************************
This script is solely for the migration purpose only.
This is a 1 time migration of volume data from v0.13.2 => v0.14.x
Assumption:
1. Postgres data volume name ends with _pgdata
2. Minio data volume name ends with _uploads
3. Redis data volume name ends with _redisdata
Any changes to this script can break the migration.
Before you proceed, make sure you run the below command
to know the docker volumes
docker volume ls -q | grep -i "_pgdata"
docker volume ls -q | grep -i "_uploads"
docker volume ls -q | grep -i "_redisdata"
*******************************************************
'
DOWNLOAD_FOL=./download
rm -rf ${DOWNLOAD_FOL}
mkdir -p ${DOWNLOAD_FOL}
function volumeExists {
if [ "$(docker volume ls -f name=$1 | awk '{print $NF}' | grep -E '^'$1'$')" ]; then
return 0
else
return 1
fi
}
function readPrefixes(){
echo ''
echo 'Given below list of REDIS volumes, identify the prefix of source and destination volumes leaving "_redisdata" '
echo '---------------------'
docker volume ls -q | grep -i "_redisdata"
echo ''
read -p "Provide the Source Volume Prefix : " SRC_VOL_PREFIX
until [ "$SRC_VOL_PREFIX" ]; do
read -p "Provide the Source Volume Prefix : " SRC_VOL_PREFIX
done
read -p "Provide the Destination Volume Prefix : " DEST_VOL_PREFIX
until [ "$DEST_VOL_PREFIX" ]; do
read -p "Provide the Source Volume Prefix : " DEST_VOL_PREFIX
done
echo ''
echo 'Prefix Provided '
echo " Source : ${SRC_VOL_PREFIX}"
echo " Destination : ${DEST_VOL_PREFIX}"
echo '---------------------------------------'
}
function migrate(){
SRC_VOLUME=${SRC_VOL_PREFIX}_${VOL_NAME_SUFFIX}
DEST_VOLUME=${DEST_VOL_PREFIX}_${VOL_NAME_SUFFIX}
if volumeExists $SRC_VOLUME; then
if volumeExists $DEST_VOLUME; then
GOOD_TO_GO=1
else
echo "Destination Volume '$DEST_VOLUME' does not exist"
echo ''
fi
else
echo "Source Volume '$SRC_VOLUME' does not exist"
echo ''
fi
if [ $GOOD_TO_GO = 1 ]; then
echo "MIGRATING ${VOL_NAME_SUFFIX} FROM ${SRC_VOLUME} => ${DEST_VOLUME}"
TEMP_CONTAINER=$(docker run -d -v $SRC_VOLUME:$CONTAINER_VOL_FOLDER busybox true)
docker cp -q $TEMP_CONTAINER:$CONTAINER_VOL_FOLDER ${DOWNLOAD_FOL}/${VOL_NAME_SUFFIX}
docker rm $TEMP_CONTAINER &> /dev/null
TEMP_CONTAINER=$(docker run -d -v $DEST_VOLUME:$CONTAINER_VOL_FOLDER busybox true)
if [ "$VOL_NAME_SUFFIX" = "pgdata" ]; then
docker cp -q ${DOWNLOAD_FOL}/${VOL_NAME_SUFFIX} $TEMP_CONTAINER:$CONTAINER_VOL_FOLDER/_temp
docker run --rm -v $DEST_VOLUME:$CONTAINER_VOL_FOLDER \
-e DATA_FOLDER="${CONTAINER_VOL_FOLDER}" \
busybox /bin/sh -c 'cp -Rf $DATA_FOLDER/_temp/* $DATA_FOLDER '
else
docker cp -q ${DOWNLOAD_FOL}/${VOL_NAME_SUFFIX} $TEMP_CONTAINER:$CONTAINER_VOL_FOLDER
fi
docker rm $TEMP_CONTAINER &> /dev/null
echo ''
fi
}
readPrefixes
# MIGRATE DB
CONTAINER_VOL_FOLDER=/var/lib/postgresql/data
VOL_NAME_SUFFIX=pgdata
migrate
# MIGRATE REDIS
CONTAINER_VOL_FOLDER=/data
VOL_NAME_SUFFIX=redisdata
migrate
# MIGRATE MINIO
CONTAINER_VOL_FOLDER=/export
VOL_NAME_SUFFIX=uploads
migrate
+123
View File
@@ -0,0 +1,123 @@
#!/bin/bash
function print_header() {
clear
cat <<"EOF"
--------------------------------------------
____ _ /////////
| _ \| | __ _ _ __ ___ /////////
| |_) | |/ _` | '_ \ / _ \ ///// /////
| __/| | (_| | | | | __/ ///// /////
|_| |_|\__,_|_| |_|\___| ////
////
--------------------------------------------
Project management tool from the future
--------------------------------------------
EOF
}
function restoreSingleVolume() {
selectedVolume=$1
backupFolder=$2
restoreFile=$3
docker volume rm "$selectedVolume" > /dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Error: Failed to remove volume $selectedVolume"
echo ""
return 1
fi
docker volume create "$selectedVolume" > /dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Error: Failed to create volume $selectedVolume"
echo ""
return 1
fi
docker run --rm \
-e TAR_NAME="$restoreFile" \
-v "$selectedVolume":"/vol" \
-v "$backupFolder":/backup \
busybox sh -c 'mkdir -p /restore && tar -xzf "/backup/${TAR_NAME}.tar.gz" -C /restore && mv /restore/${TAR_NAME}/* /vol'
if [ $? -ne 0 ]; then
echo "Error: Failed to restore volume ${selectedVolume} from ${restoreFile}.tar.gz"
echo ""
return 1
fi
echo ".....Successfully restored volume $selectedVolume from ${restoreFile}.tar.gz"
echo ""
}
function restoreData() {
print_header
local BACKUP_FOLDER=${1:-$PWD}
local dockerServiceStatus
dockerServiceStatus=$($COMPOSE_CMD ls --filter name=plane-app --format=json | jq -r .[0].Status)
local dockerServicePrefix
dockerServicePrefix="running"
if [[ $dockerServiceStatus == $dockerServicePrefix* ]]; then
echo "Plane App is running. Please STOP the Plane App before restoring data."
exit 1
fi
local volume_suffix
volume_suffix="_pgdata|_redisdata|_uploads|_rabbitmq_data"
local volumes
volumes=$(docker volume ls -f "name=plane-app" --format "{{.Name}}" | grep -E "$volume_suffix")
# Check if there are any matching volumes
if [ -z "$volumes" ]; then
echo ".....No volumes found starting with 'plane-app'"
exit 1
fi
for BACKUP_FILE in $BACKUP_FOLDER/*.tar.gz; do
if [ -e "$BACKUP_FILE" ]; then
local restoreFileName
restoreFileName=$(basename "$BACKUP_FILE")
restoreFileName="${restoreFileName%.tar.gz}"
local restoreVolName
restoreVolName="plane-app_${restoreFileName}"
echo "Found $BACKUP_FILE"
local docVol
docVol=$(docker volume ls -f "name=$restoreVolName" --format "{{.Name}}" | grep -E "$volume_suffix")
if [ -z "$docVol" ]; then
echo "Skipping: No volume found with name $restoreVolName"
else
echo ".....Restoring $docVol"
restoreSingleVolume "$docVol" "$BACKUP_FOLDER" "$restoreFileName"
fi
else
echo "No .tar.gz files found in the current directory."
echo ""
echo "Please provide the path to the backup file."
echo ""
echo "Usage: ./restore.sh /path/to/backup"
exit 1
fi
done
echo ""
echo "Restore completed successfully."
echo ""
}
# if docker-compose is installed
if command -v docker-compose &> /dev/null
then
COMPOSE_CMD="docker-compose"
else
COMPOSE_CMD="docker compose"
fi
restoreData "$@"
+612
View File
@@ -0,0 +1,612 @@
#!/bin/bash
BRANCH=${BRANCH:-master}
SERVICE_FOLDER=plane-app
SCRIPT_DIR=$PWD
PLANE_INSTALL_DIR=$PWD/$SERVICE_FOLDER
export APP_RELEASE="stable"
export DOCKERHUB_USER=artifacts.plane.so/makeplane
export GH_REPO=makeplane/plane
export RELEASE_DOWNLOAD_URL="https://github.com/$GH_REPO/releases/download"
export FALLBACK_DOWNLOAD_URL="https://raw.githubusercontent.com/$GH_REPO/$BRANCH/deploy/selfhost"
OS_NAME=$(uname)
# Create necessary directories
mkdir -p $PLANE_INSTALL_DIR/archive
DOCKER_FILE_PATH=$PLANE_INSTALL_DIR/docker-compose.yml
DOCKER_ENV_PATH=$PLANE_INSTALL_DIR/plane.env
function print_header() {
clear
cat <<"EOF"
--------------------------------------------
____ _ /////////
| _ \| | __ _ _ __ ___ /////////
| |_) | |/ _` | '_ \ / _ \ ///// /////
| __/| | (_| | | | | __/ ///// /////
|_| |_|\__,_|_| |_|\___| ////
////
--------------------------------------------
Project management tool from the future
--------------------------------------------
EOF
}
function checkLatestRelease(){
echo "Checking for the latest release..." >&2
local latest_release=$(curl -s https://api.github.com/repos/$GH_REPO/releases/latest | grep -o '"tag_name": "[^"]*"' | sed 's/"tag_name": "//;s/"//g')
if [ -z "$latest_release" ]; then
echo "Failed to check for the latest release. Exiting..." >&2
exit 1
fi
echo $latest_release
}
# Function to read stack name from env file
function readStackName() {
if [ -f "$DOCKER_ENV_PATH" ]; then
local saved_stack_name=$(grep "^STACK_NAME=" "$DOCKER_ENV_PATH" | cut -d'=' -f2)
if [ -n "$saved_stack_name" ]; then
stack_name=$saved_stack_name
return 1
fi
fi
return 0
}
# Function to get stack name (either from env or user input)
function getStackName() {
read -p "Enter stack name [plane]: " input_stack_name
if [ -z "$input_stack_name" ]; then
input_stack_name="plane"
fi
stack_name=$input_stack_name
updateEnvFile "STACK_NAME" "$stack_name" "$DOCKER_ENV_PATH"
echo "Using stack name: $stack_name"
}
function syncEnvFile(){
echo "Syncing environment variables..." >&2
if [ -f "$PLANE_INSTALL_DIR/plane.env.bak" ]; then
# READ keys of plane.env and update the values from plane.env.bak
while IFS= read -r line
do
# ignore if the line is empty or starts with #
if [ -z "$line" ] || [[ $line == \#* ]]; then
continue
fi
key=$(echo "$line" | cut -d'=' -f1)
value=$(getEnvValue "$key" "$PLANE_INSTALL_DIR/plane.env.bak")
if [ -n "$value" ]; then
updateEnvFile "$key" "$value" "$DOCKER_ENV_PATH"
fi
done < "$DOCKER_ENV_PATH"
value=$(getEnvValue "STACK_NAME" "$PLANE_INSTALL_DIR/plane.env.bak")
if [ -n "$value" ]; then
updateEnvFile "STACK_NAME" "$value" "$DOCKER_ENV_PATH"
fi
fi
echo "Environment variables synced successfully" >&2
rm -f $PLANE_INSTALL_DIR/plane.env.bak
}
function getEnvValue() {
local key=$1
local file=$2
if [ -z "$key" ] || [ -z "$file" ]; then
echo "Invalid arguments supplied"
exit 1
fi
if [ -f "$file" ]; then
grep -q "^$key=" "$file"
if [ $? -eq 0 ]; then
local value
value=$(grep "^$key=" "$file" | cut -d'=' -f2)
echo "$value"
else
echo ""
fi
fi
}
function updateEnvFile() {
local key=$1
local value=$2
local file=$3
if [ -z "$key" ] || [ -z "$value" ] || [ -z "$file" ]; then
echo "Invalid arguments supplied"
exit 1
fi
if [ -f "$file" ]; then
# check if key exists in the file
grep -q "^$key=" "$file"
if [ $? -ne 0 ]; then
echo "$key=$value" >> "$file"
return
else
if [ "$OS_NAME" == "Darwin" ]; then
value=$(echo "$value" | sed 's/|/\\|/g')
sed -i '' "s|^$key=.*|$key=$value|g" "$file"
else
sed -i "s/^$key=.*/$key=$value/g" "$file"
fi
fi
else
echo "File not found: $file"
exit 1
fi
}
function download() {
cd $SCRIPT_DIR || exit 1
TS=$(date +%s)
if [ -f "$PLANE_INSTALL_DIR/docker-compose.yml" ]
then
mv $PLANE_INSTALL_DIR/docker-compose.yml $PLANE_INSTALL_DIR/archive/$TS.docker-compose.yml
fi
echo $RELEASE_DOWNLOAD_URL
echo $FALLBACK_DOWNLOAD_URL
echo $APP_RELEASE
RESPONSE=$(curl -H 'Cache-Control: no-cache, no-store' -s -w "HTTPSTATUS:%{http_code}" "$RELEASE_DOWNLOAD_URL/$APP_RELEASE/docker-compose.yml?$(date +%s)")
BODY=$(echo "$RESPONSE" | sed -e 's/HTTPSTATUS\:.*//g')
STATUS=$(echo "$RESPONSE" | tr -d '\n' | sed -e 's/.*HTTPSTATUS://')
if [ "$STATUS" -eq 200 ]; then
echo "$BODY" > $PLANE_INSTALL_DIR/docker-compose.yml
else
# Fallback to download from the raw github url
RESPONSE=$(curl -H 'Cache-Control: no-cache, no-store' -s -w "HTTPSTATUS:%{http_code}" "$FALLBACK_DOWNLOAD_URL/docker-compose.yml?$(date +%s)")
BODY=$(echo "$RESPONSE" | sed -e 's/HTTPSTATUS\:.*//g')
STATUS=$(echo "$RESPONSE" | tr -d '\n' | sed -e 's/.*HTTPSTATUS://')
if [ "$STATUS" -eq 200 ]; then
echo "$BODY" > $PLANE_INSTALL_DIR/docker-compose.yml
else
echo "Failed to download docker-compose.yml. HTTP Status: $STATUS"
echo "URL: $RELEASE_DOWNLOAD_URL/$APP_RELEASE/docker-compose.yml"
mv $PLANE_INSTALL_DIR/archive/$TS.docker-compose.yml $PLANE_INSTALL_DIR/docker-compose.yml
exit 1
fi
fi
RESPONSE=$(curl -H 'Cache-Control: no-cache, no-store' -s -w "HTTPSTATUS:%{http_code}" "$RELEASE_DOWNLOAD_URL/$APP_RELEASE/variables.env?$(date +%s)")
BODY=$(echo "$RESPONSE" | sed -e 's/HTTPSTATUS\:.*//g')
STATUS=$(echo "$RESPONSE" | tr -d '\n' | sed -e 's/.*HTTPSTATUS://')
if [ "$STATUS" -eq 200 ]; then
echo "$BODY" > $PLANE_INSTALL_DIR/variables-upgrade.env
else
# Fallback to download from the raw github url
RESPONSE=$(curl -H 'Cache-Control: no-cache, no-store' -s -w "HTTPSTATUS:%{http_code}" "$FALLBACK_DOWNLOAD_URL/variables.env?$(date +%s)")
BODY=$(echo "$RESPONSE" | sed -e 's/HTTPSTATUS\:.*//g')
STATUS=$(echo "$RESPONSE" | tr -d '\n' | sed -e 's/.*HTTPSTATUS://')
if [ "$STATUS" -eq 200 ]; then
echo "$BODY" > $PLANE_INSTALL_DIR/variables-upgrade.env
else
echo "Failed to download variables.env. HTTP Status: $STATUS"
echo "URL: $RELEASE_DOWNLOAD_URL/$APP_RELEASE/variables.env"
mv $PLANE_INSTALL_DIR/archive/$TS.docker-compose.yml $PLANE_INSTALL_DIR/docker-compose.yml
exit 1
fi
fi
if [ -f "$DOCKER_ENV_PATH" ];
then
cp "$DOCKER_ENV_PATH" "$PLANE_INSTALL_DIR/archive/$TS.env"
cp "$DOCKER_ENV_PATH" "$PLANE_INSTALL_DIR/plane.env.bak"
fi
mv $PLANE_INSTALL_DIR/variables-upgrade.env $DOCKER_ENV_PATH
syncEnvFile
updateEnvFile "APP_RELEASE" "$APP_RELEASE" "$DOCKER_ENV_PATH"
}
function deployStack() {
# Check if docker compose file and env file exist
if [ ! -f "$DOCKER_FILE_PATH" ] || [ ! -f "$DOCKER_ENV_PATH" ]; then
echo "Configuration files not found"
echo "Downloading it now......"
APP_RELEASE=$(checkLatestRelease)
download
fi
if [ -z "$stack_name" ]; then
getStackName
fi
echo "Starting ${stack_name} stack..."
# Pull envs
if [ -f "$DOCKER_ENV_PATH" ]; then
set -o allexport; source $DOCKER_ENV_PATH; set +o allexport;
else
echo "Environment file not found: $DOCKER_ENV_PATH"
exit 1
fi
# Deploy the stack
docker stack deploy -c $DOCKER_FILE_PATH $stack_name
echo "Waiting for services to be deployed..."
sleep 10
# Check migrator service
local migrator_service=$(docker service ls --filter name=${stack_name}_migrator -q)
if [ -n "$migrator_service" ]; then
echo ">> Waiting for Data Migration to finish"
while docker service ls --filter name=${stack_name}_migrator | grep -q "running"; do
echo -n "."
sleep 1
done
echo ""
# Get the most recent container for the migrator service
local migrator_container=$(docker ps -a --filter name=${stack_name}_migrator --latest -q)
if [ -n "$migrator_container" ]; then
# Get the exit code of the container
local exit_code=$(docker inspect --format='{{.State.ExitCode}}' $migrator_container)
if [ "$exit_code" != "0" ]; then
echo "Server failed to start ❌"
echo "Migration failed with exit code: $exit_code"
echo "Please check the logs for the 'migrator' service and resolve the issue(s)."
echo "Stop the services by running the command: ./swarm.sh stop"
exit 1
else
echo " Data Migration completed successfully ✅"
fi
else
echo "Warning: Could not find migrator container to check exit status"
fi
fi
# Check API service
local api_service=$(docker service ls --filter name=${stack_name}_api -q)
while docker service ls --filter name=${stack_name}_api | grep -q "running"; do
local running_container=$(docker ps --filter "name=${stack_name}_api" --filter "status=running" -q)
if [ -n "$running_container" ]; then
if docker container logs $running_container 2>/dev/null | grep -q "Application Startup Complete"; then
break
fi
fi
sleep 2
done
if [ -z "$api_service" ]; then
echo "Plane Server failed to start ❌"
echo "Please check the logs for the 'api' service and resolve the issue(s)."
echo "Stop the services by running the command: ./swarm.sh stop"
exit 1
fi
echo " Plane Server started successfully ✅"
echo ""
echo " You can access the application at $WEB_URL"
echo ""
}
function removeStack() {
if [ -z "$stack_name" ]; then
echo "Stack name not found"
exit 1
fi
echo "Removing ${stack_name} stack..."
docker stack rm "$stack_name"
echo "Waiting for services to be removed..."
while docker stack ls | grep -q "$stack_name"; do
sleep 1
done
sleep 20
echo "Services stopped successfully ✅"
}
function viewStatus() {
echo "Checking status of ${stack_name} stack..."
if [ -z "$stack_name" ]; then
echo "Stack name not found"
exit 1
fi
docker stack ps "$stack_name"
}
function redeployStack() {
removeStack
echo "ReDeploying ${stack_name} stack..."
deployStack
}
function upgrade() {
echo "Checking status of ${stack_name} stack..."
if [ -z "$stack_name" ]; then
echo "Stack name not found"
exit 1
fi
local latest_release=$(checkLatestRelease)
echo ""
echo "Current release: $APP_RELEASE"
if [ "$latest_release" == "$APP_RELEASE" ]; then
echo ""
echo "You are already using the latest release"
exit 0
fi
echo "Latest release: $latest_release"
echo ""
# Check for confirmation to upgrade
echo "Do you want to upgrade to the latest release ($latest_release)?"
read -p "Continue? [y/N]: " confirm
if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
echo "Exiting..."
exit 0
fi
export APP_RELEASE=$latest_release
# check if stack exists
echo "Upgrading ${stack_name} stack..."
# check env file and take backup
if [ -f "$DOCKER_ENV_PATH" ]; then
cp "$DOCKER_ENV_PATH" "${DOCKER_ENV_PATH}.bak"
fi
download
redeployStack
}
function viewSpecificLogs() {
local service=$1
# Input validation
if [ -z "$service" ]; then
echo "Error: Please specify a service name"
return 1
fi
# Main loop for service logs
while true; do
# Get all running containers for the service
local running_containers=$(docker ps --filter "name=${stack_name}_${service}" --filter "status=running" -q)
# If no running containers found, try service logs
if [ -z "$running_containers" ]; then
echo "No running containers found for ${stack_name}_${service}, checking service logs..."
if docker service inspect ${stack_name}_${service} >/dev/null 2>&1; then
echo "Press Ctrl+C or 'q' to exit logs"
docker service logs ${stack_name}_${service} -f
break
else
echo "Error: No running containers or services found for ${stack_name}_${service}"
return 1
fi
return
fi
# If multiple containers are running, let user choose
if [ $(echo "$running_containers" | grep -v '^$' | wc -l) -gt 1 ]; then
clear
echo "Multiple containers found for ${stack_name}_${service}:"
local i=1
# Use regular arrays instead of associative arrays
container_ids=()
container_names=()
while read -r container_id; do
if [ -n "$container_id" ]; then
local container_name=$(docker inspect --format '{{.Name}}' "$container_id" | sed 's/\///')
container_ids[$i]=$container_id
container_names[$i]=$container_name
echo "[$i] ${container_names[$i]} (${container_ids[$i]})"
i=$((i+1))
fi
done <<< "$running_containers"
echo -e "\nPlease select a container number:"
read -r selection
if [[ "$selection" =~ ^[0-9]+$ ]] && [ -n "${container_ids[$selection]}" ]; then
local selected_container=${container_ids[$selection]}
clear
echo "Showing logs for container: ${container_names[$selection]}"
echo "Press Ctrl+C or 'q' to return to container selection"
# Start watching logs in the background
docker container logs -f "$selected_container" &
local log_pid=$!
while true; do
read -r -n 1 input
if [[ $input == "q" ]]; then
kill $log_pid 2>/dev/null
wait $log_pid 2>/dev/null
break
fi
done
clear
else
echo "Error: Invalid selection"
sleep 2
fi
else
# Single container case
local container_name=$(docker inspect --format '{{.Name}}' "$running_containers" | sed 's/\///')
echo "Showing logs for container: $container_name"
echo "Press Ctrl+C or 'q' to exit logs"
docker container logs -f "$running_containers" &
local log_pid=$!
while true; do
read -r -n 1 input
if [[ $input == "q" ]]; then
kill $log_pid 2>/dev/null
wait $log_pid 2>/dev/null
break
fi
done
break
fi
done
}
function viewLogs(){
ARG_SERVICE_NAME=$2
if [ -z "$ARG_SERVICE_NAME" ];
then
echo
echo "Select a Service you want to view the logs for:"
echo " 1) Web"
echo " 2) Space"
echo " 3) API"
echo " 4) Worker"
echo " 5) Beat-Worker"
echo " 6) Migrator"
echo " 7) Proxy"
echo " 8) Redis"
echo " 9) Postgres"
echo " 10) Minio"
echo " 11) RabbitMQ"
echo " 0) Back to Main Menu"
echo
read -p "Service: " DOCKER_SERVICE_NAME
until (( DOCKER_SERVICE_NAME >= 0 && DOCKER_SERVICE_NAME <= 11 )); do
echo "Invalid selection. Please enter a number between 0 and 11."
read -p "Service: " DOCKER_SERVICE_NAME
done
if [ -z "$DOCKER_SERVICE_NAME" ];
then
echo "INVALID SERVICE NAME SUPPLIED"
else
case $DOCKER_SERVICE_NAME in
1) viewSpecificLogs "web";;
2) viewSpecificLogs "space";;
3) viewSpecificLogs "api";;
4) viewSpecificLogs "worker";;
5) viewSpecificLogs "beat-worker";;
6) viewSpecificLogs "migrator";;
7) viewSpecificLogs "proxy";;
8) viewSpecificLogs "plane-redis";;
9) viewSpecificLogs "plane-db";;
10) viewSpecificLogs "plane-minio";;
11) viewSpecificLogs "plane-mq";;
0) askForAction;;
*) echo "INVALID SERVICE NAME SUPPLIED";;
esac
fi
elif [ -n "$ARG_SERVICE_NAME" ];
then
ARG_SERVICE_NAME=$(echo "$ARG_SERVICE_NAME" | tr '[:upper:]' '[:lower:]')
case $ARG_SERVICE_NAME in
web) viewSpecificLogs "web";;
space) viewSpecificLogs "space";;
api) viewSpecificLogs "api";;
worker) viewSpecificLogs "worker";;
beat-worker) viewSpecificLogs "beat-worker";;
migrator) viewSpecificLogs "migrator";;
proxy) viewSpecificLogs "proxy";;
redis) viewSpecificLogs "plane-redis";;
postgres) viewSpecificLogs "plane-db";;
minio) viewSpecificLogs "plane-minio";;
rabbitmq) viewSpecificLogs "plane-mq";;
*) echo "INVALID SERVICE NAME SUPPLIED";;
esac
else
echo "INVALID SERVICE NAME SUPPLIED"
fi
}
function askForAction() {
# Rest of askForAction remains the same but use $stack_name instead of $STACK_NAME
local DEFAULT_ACTION=$1
if [ -z "$DEFAULT_ACTION" ]; then
echo
echo "Select an Action you want to perform:"
echo " 1) Deploy Stack"
echo " 2) Remove Stack"
echo " 3) View Stack Status"
echo " 4) Redeploy Stack"
echo " 5) Upgrade"
echo " 6) View Logs"
echo " 7) Exit"
echo
read -p "Action [3]: " ACTION
until [[ -z "$ACTION" || "$ACTION" =~ ^[1-6]$ ]]; do
echo "$ACTION: invalid selection."
read -p "Action [3]: " ACTION
done
if [ -z "$ACTION" ]; then
ACTION=3
fi
echo
fi
if [ "$ACTION" == "1" ] || [ "$DEFAULT_ACTION" == "deploy" ]; then
deployStack
elif [ "$ACTION" == "2" ] || [ "$DEFAULT_ACTION" == "remove" ]; then
removeStack
elif [ "$ACTION" == "3" ] || [ "$DEFAULT_ACTION" == "status" ]; then
viewStatus
elif [ "$ACTION" == "4" ] || [ "$DEFAULT_ACTION" == "redeploy" ]; then
redeployStack
elif [ "$ACTION" == "5" ] || [ "$DEFAULT_ACTION" == "upgrade" ]; then
upgrade
elif [ "$ACTION" == "6" ] || [ "$DEFAULT_ACTION" == "logs" ]; then
viewLogs "$@"
elif [ "$ACTION" == "7" ] || [ "$DEFAULT_ACTION" == "exit" ]; then
exit 0
else
echo "INVALID ACTION SUPPLIED"
fi
}
# Initialize stack name at script start
if [ -z "$stack_name" ]; then
readStackName
fi
# Sync environment variables
if [ -f "$DOCKER_ENV_PATH" ]; then
DOCKERHUB_USER=$(getEnvValue "DOCKERHUB_USER" "$DOCKER_ENV_PATH")
APP_RELEASE=$(getEnvValue "APP_RELEASE" "$DOCKER_ENV_PATH")
if [ -z "$DOCKERHUB_USER" ]; then
DOCKERHUB_USER=artifacts.plane.so/makeplane
updateEnvFile "DOCKERHUB_USER" "$DOCKERHUB_USER" "$DOCKER_ENV_PATH"
fi
if [ -z "$APP_RELEASE" ]; then
APP_RELEASE=stable
updateEnvFile "APP_RELEASE" "$APP_RELEASE" "$DOCKER_ENV_PATH"
fi
fi
# Main execution
print_header
askForAction "$@"
Executable → Regular
+8 -23
View File
@@ -1,28 +1,13 @@
import utils from "../utils.js"; import utils from "../utils.js";
await utils.removeDir("./code"); await utils.cloneOrPullRepo({
await utils.renameDir("./plane-code", "./code"); repo: "https://github.com/makeplane/plane.git",
await utils.removeDir("./code/archive"); path: "./repo",
await utils.renameFile("./code/plane.env", "./code/.env.example"); branch: "preview",
await utils.renameFile("./code/docker-compose.yaml", "./code/docker-compose.yml"); });
await utils.copyDir("./repo/deploy/selfhost", "./code");
await utils.renameFile("./code/variables.env", "./code/.env.example");
await utils.removeContainerNames("./code/docker-compose.yml"); await utils.removeContainerNames("./code/docker-compose.yml");
await utils.removePorts("./code/docker-compose.yml"); await utils.removePorts("./code/docker-compose.yml");
await utils.searchReplace(
"./code/.env.example",
"APP_DOMAIN=localhost",
"APP_DOMAIN=$(PRIMARY_DOMAIN)"
);
await utils.searchReplace(
"./code/.env.example",
"WEB_URL=http://${APP_DOMAIN}",
"WEB_URL=https://$(PRIMARY_DOMAIN)"
);
await utils.searchReplace(
"./code/.env.example",
"CORS_ALLOWED_ORIGINS=http://${APP_DOMAIN}",
"CORS_ALLOWED_ORIGINS=https://$(PRIMARY_DOMAIN)"
);
+14
View File
@@ -0,0 +1,14 @@
#!/bin/bash
if [ ! -d "./repo" ]; then
git clone --depth 1 --branch preview --single-branch https://github.com/makeplane/plane.git repo
else
cd repo
git pull
cd ..
fi
cp -r ./repo/deploy/selfhost/. ./code
mv ./code/variables.env ./code/.env.example
+37 -202
View File
@@ -1,126 +1,62 @@
############ ############
# Secrets # Secrets
# # YOU MUST CHANGE THESE BEFORE GOING INTO PRODUCTION
# YOU MUST CHANGE ALL THE DEFAULT VALUES BELOW BEFORE STARTING
# THE CONTAINERS FOR THE FIRST TIME!
#
# Documentation:
# https://supabase.com/docs/guides/self-hosting/docker#configuring-and-securing-supabase
#
# To generate secrets and API keys:
# sh ./utils/generate-keys.sh
#
############ ############
# Postgres
POSTGRES_PASSWORD=your-super-secret-and-long-postgres-password POSTGRES_PASSWORD=your-super-secret-and-long-postgres-password
# Symmetric encryption key and JWT API keys
JWT_SECRET=your-super-secret-jwt-token-with-at-least-32-characters-long JWT_SECRET=your-super-secret-jwt-token-with-at-least-32-characters-long
ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJhbm9uIiwKICAgICJpc3MiOiAic3VwYWJhc2UtZGVtbyIsCiAgICAiaWF0IjogMTY0MTc2OTIwMCwKICAgICJleHAiOiAxNzk5NTM1NjAwCn0.dc_X5iR_VP_qT0zsiyj_I_OZ2T9FtRU2BBNWN8Bu4GE ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJhbm9uIiwKICAgICJpc3MiOiAic3VwYWJhc2UtZGVtbyIsCiAgICAiaWF0IjogMTY0MTc2OTIwMCwKICAgICJleHAiOiAxNzk5NTM1NjAwCn0.dc_X5iR_VP_qT0zsiyj_I_OZ2T9FtRU2BBNWN8Bu4GE
SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJzZXJ2aWNlX3JvbGUiLAogICAgImlzcyI6ICJzdXBhYmFzZS1kZW1vIiwKICAgICJpYXQiOiAxNjQxNzY5MjAwLAogICAgImV4cCI6IDE3OTk1MzU2MDAKfQ.DaYlNEoUrrEn2Ig7tqibS-PHK5vgusbcbo7X36XVt4Q SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJzZXJ2aWNlX3JvbGUiLAogICAgImlzcyI6ICJzdXBhYmFzZS1kZW1vIiwKICAgICJpYXQiOiAxNjQxNzY5MjAwLAogICAgImV4cCI6IDE3OTk1MzU2MDAKfQ.DaYlNEoUrrEn2Ig7tqibS-PHK5vgusbcbo7X36XVt4Q
# Access to Dashboard
DASHBOARD_USERNAME=supabase DASHBOARD_USERNAME=supabase
DASHBOARD_PASSWORD=this_password_is_insecure_and_should_be_updated DASHBOARD_PASSWORD=this_password_is_insecure_and_should_be_updated
# Used by Realtime and Supavisor
SECRET_KEY_BASE=UpNVntn3cDxHJpq99YMc1T1AQgQpc8kfYTuRgBiYa15BLrx8etQoXz3gZv1/u2oq SECRET_KEY_BASE=UpNVntn3cDxHJpq99YMc1T1AQgQpc8kfYTuRgBiYa15BLrx8etQoXz3gZv1/u2oq
VAULT_ENC_KEY=your-encryption-key-32-chars-min
# Used by Supavisor
VAULT_ENC_KEY=your-32-character-encryption-key
# Used by Studio to access Postgres via postgres-meta
PG_META_CRYPTO_KEY=your-encryption-key-32-chars-min
# Analytics - API tokens for log ingestion/querying, and for management
LOGFLARE_PUBLIC_ACCESS_TOKEN=your-super-secret-and-long-logflare-key-public
LOGFLARE_PRIVATE_ACCESS_TOKEN=your-super-secret-and-long-logflare-key-private
# Access to Storage via S3 protocol endpoint (see below)
S3_PROTOCOL_ACCESS_KEY_ID=625729a08b95bf1b7ff351a663f3a23c
S3_PROTOCOL_ACCESS_KEY_SECRET=850181e4652dd023b7a98c58ae0d2d34bd487ee0cc3254aed6eda37307425907
############ ############
# URLs - Configure hostnames below to reflect your actual domain name # Database - You can change these to any PostgreSQL database that has logical replication enabled.
############ ############
# Access to Dashboard and REST API
SUPABASE_PUBLIC_URL=http://localhost:8000
# Full external URL of the Auth service, used to construct OAuth callbacks,
# SAML endpoints, and email links
API_EXTERNAL_URL=http://localhost:8000
# See also the Auth section below for Site URL and Redirect URLs configuration
############
# Database - Postgres configuration
############
# Using default user (postgres)
POSTGRES_HOST=db POSTGRES_HOST=db
POSTGRES_DB=postgres POSTGRES_DB=postgres
# Default configuration includes Supavisor exposing POSTGRES_PORT
# Postgres uses POSTGRES_PORT inside the container
# Documentation:
# https://supabase.com/docs/guides/self-hosting/docker#accessing-postgres-through-supavisor
POSTGRES_PORT=5432 POSTGRES_PORT=5432
# default user is postgres
############ ############
# Supavisor - Database pooler # Supavisor -- Database pooler
############ ############
# Supavisor exposes POSTGRES_PORT and POOLER_PROXY_PORT_TRANSACTION,
# POSTGRES_PORT is used for session mode pooling
#
# Port to use for transaction mode pooling connections
POOLER_PROXY_PORT_TRANSACTION=6543 POOLER_PROXY_PORT_TRANSACTION=6543
# Maximum number of PostgreSQL connections Supavisor opens per pool
POOLER_DEFAULT_POOL_SIZE=20 POOLER_DEFAULT_POOL_SIZE=20
# Maximum number of client connections Supavisor accepts per pool
POOLER_MAX_CLIENT_CONN=100 POOLER_MAX_CLIENT_CONN=100
# Unique Supavisor tenant identifier
# Documentation:
# https://supabase.com/docs/guides/self-hosting/docker#accessing-postgres
POOLER_TENANT_ID=your-tenant-id POOLER_TENANT_ID=your-tenant-id
# Pool size for internal metadata storage used by Supavisor
# This is separate from client connections and used only by Supavisor itself ############
POOLER_DB_POOL_SIZE=5 # API Proxy - Configuration for the Kong Reverse proxy.
############
KONG_HTTP_PORT=8000
KONG_HTTPS_PORT=8443
############ ############
# Studio - Configuration for the Dashboard # API - Configuration for PostgREST.
############ ############
STUDIO_DEFAULT_ORGANIZATION=Default Organization PGRST_DB_SCHEMAS=public,storage,graphql_public
STUDIO_DEFAULT_PROJECT=Default Project
# Add your OpenAI API key to enable AI Assistant
OPENAI_API_KEY=sk-proj-xxxxxxxx
############ ############
# Auth - Configuration for the authentication server # Auth - Configuration for the GoTrue authentication server.
############ ############
## General settings ## General
SITE_URL=http://localhost:3000
# Equivalent to "Site URL" and "Redirect URLs" platform configuration options
# Documentation: https://supabase.com/docs/guides/auth/redirect-urls
SITE_URL=https://$(PRIMARY_DOMAIN)
ADDITIONAL_REDIRECT_URLS= ADDITIONAL_REDIRECT_URLS=
JWT_EXPIRY=3600 JWT_EXPIRY=3600
DISABLE_SIGNUP=false DISABLE_SIGNUP=false
API_EXTERNAL_URL=http://localhost:8000
## Mailer Config ## Mailer Config
MAILER_URLPATHS_CONFIRMATION="/auth/v1/verify" MAILER_URLPATHS_CONFIRMATION="/auth/v1/verify"
@@ -143,107 +79,41 @@ ENABLE_ANONYMOUS_USERS=false
ENABLE_PHONE_SIGNUP=true ENABLE_PHONE_SIGNUP=true
ENABLE_PHONE_AUTOCONFIRM=true ENABLE_PHONE_AUTOCONFIRM=true
## OAuth / Social login providers
# Uncomment and fill in the providers you want to enable. ############
# You must ALSO uncomment the matching GOTRUE_EXTERNAL_* lines in docker-compose.yml. # Studio - Configuration for the Dashboard
# Documentation: https://supabase.com/docs/guides/self-hosting/self-hosted-oauth ############
# GOOGLE_ENABLED=false
# GOOGLE_CLIENT_ID=
# GOOGLE_SECRET=
# GITHUB_ENABLED=false STUDIO_DEFAULT_ORGANIZATION=Default Organization
# GITHUB_CLIENT_ID= STUDIO_DEFAULT_PROJECT=Default Project
# GITHUB_SECRET=
# AZURE_ENABLED=false STUDIO_PORT=3000
# AZURE_CLIENT_ID= # replace if you intend to use Studio outside of localhost
# AZURE_SECRET= SUPABASE_PUBLIC_URL=http://localhost:8000
# Phone / SMS provider configuration # Enable webp support
# Uncomment to configure SMS delivery for phone auth and phone MFA. IMGPROXY_ENABLE_WEBP_DETECTION=true
# You must ALSO uncomment the matching GOTRUE_SMS_* lines in docker-compose.yml.
# Documentation: https://supabase.com/docs/guides/self-hosting/self-hosted-phone-mfa
# SMS_PROVIDER=twilio
# SMS_OTP_EXP=60
# SMS_OTP_LENGTH=6
# SMS_MAX_FREQUENCY=60s
# SMS_TEMPLATE=Your code is {{ .Code }}
# SMS_TWILIO_ACCOUNT_SID= # Add your OpenAI API key to enable SQL Editor Assistant
# SMS_TWILIO_AUTH_TOKEN= OPENAI_API_KEY=
# SMS_TWILIO_MESSAGE_SERVICE_SID=
# Test OTP: map phone numbers to fixed OTP codes for development
# Format: phone1:code1,phone2:code2
# SMS_TEST_OTP=
# Multi-factor authentication (MFA)
# Uncomment to change MFA defaults.
# You must ALSO uncomment the matching GOTRUE_MFA_* lines in docker-compose.yml.
# App Authenticator (TOTP) - enabled by default
# MFA_TOTP_ENROLL_ENABLED=true
# MFA_TOTP_VERIFY_ENABLED=true
# Phone MFA - disabled by default (opt-in)
# MFA_PHONE_ENROLL_ENABLED=false
# MFA_PHONE_VERIFY_ENABLED=false
## Maximum MFA factors a user can enroll
# MFA_MAX_ENROLLED_FACTORS=10
############ ############
# Storage - Configuration for Storage # Functions - Configuration for Functions
############ ############
# NOTE: VERIFY_JWT applies to all functions. Per-function VERIFY_JWT is not supported yet.
# Check the S3_PROTOCOL_ACCESS_KEY_ID/SECRET above, and
# refer to the documentation at:
# https://supabase.com/docs/guides/self-hosting/self-hosted-s3
# to learn how to configure the S3 protocol endpoint
# S3 bucket when using S3 backend, directory name when using 'file'
GLOBAL_S3_BUCKET=stub
# Used for S3 protocol endpoint configuration
REGION=stub
# Used by MinIO when added via:
# docker compose -f docker-compose.yml -f docker-compose.s3.yml up -d
MINIO_ROOT_USER=supa-storage
MINIO_ROOT_PASSWORD=secret1234
# Equivalent to project_ref as described here:
# https://supabase.com/docs/guides/storage/s3/authentication#session-token
STORAGE_TENANT_ID=stub
############
# Functions - Configuration for Edge functions
############
# Documentation:
# https://supabase.com/docs/guides/self-hosting/self-hosted-functions
# NOTE: VERIFY_JWT applies to all functions
FUNCTIONS_VERIFY_JWT=false FUNCTIONS_VERIFY_JWT=false
############ ############
# API - Configuration for PostgREST # Logs - Configuration for Logflare
# Please refer to https://supabase.com/docs/reference/self-hosting-analytics/introduction
############ ############
# Postgres schemas exposed via the REST API LOGFLARE_LOGGER_BACKEND_API_KEY=your-super-secret-and-long-logflare-key
PGRST_DB_SCHEMAS=public,storage,graphql_public
# Change vector.toml sinks to reflect this change
############ LOGFLARE_API_KEY=your-super-secret-and-long-logflare-key
# Analytics - Configuration for Logflare
############
# Check the LOGFLARE_* access token configuration above.
# If Logflare is externally exposed, configure securely!
# Docker socket location - this value will differ depending on your OS # Docker socket location - this value will differ depending on your OS
DOCKER_SOCKET_LOCATION=/var/run/docker.sock DOCKER_SOCKET_LOCATION=/var/run/docker.sock
@@ -251,38 +121,3 @@ DOCKER_SOCKET_LOCATION=/var/run/docker.sock
# Google Cloud Project details # Google Cloud Project details
GOOGLE_PROJECT_ID=GOOGLE_PROJECT_ID GOOGLE_PROJECT_ID=GOOGLE_PROJECT_ID
GOOGLE_PROJECT_NUMBER=GOOGLE_PROJECT_NUMBER GOOGLE_PROJECT_NUMBER=GOOGLE_PROJECT_NUMBER
############
# API Proxy - Configuration for the Kong API gateway
############
KONG_HTTP_PORT=8000
KONG_HTTPS_PORT=8443
############
# imgproxy
############
# Enable webp support
IMGPROXY_ENABLE_WEBP_DETECTION=true
############
# TLS Proxy - Optional Caddy or Nginx reverse proxy with Let's Encrypt
############
# Documentation:
# https://supabase.com/docs/guides/self-hosting/self-hosted-proxy-https
# Usage:
# docker compose -f docker-compose.yml -f docker-compose.caddy.yml up -d
# docker compose -f docker-compose.yml -f docker-compose.nginx.yml up -d
# Domain name for the proxy (must point to your server)
PROXY_DOMAIN=your-domain.example.com
# Email for Let's Encrypt certificate notifications (nginx only, Caddy uses PROXY_DOMAIN).
# This should be a valid email, not a placehoder (otherwise Certbot may fail to start).
CERTBOT_EMAIL=admin@example.com
-383
View File
@@ -1,383 +0,0 @@
# Changelog
All notable changes to the Supabase self-hosted Docker configuration.
Changes are grouped by service rather than by change type. See [versions.md](./versions.md)
for complete image version history and rollback information.
Check updates for each service to learn more.
**Note:** Configuration updates marked with "requires [...] update" are already included in the latest version of the repository. Pull the latest changes or refer to the linked PR for manual updates. After updating `docker-compose.yml`, pull latest images and recreate containers - use `docker compose pull && docker compose down && docker compose up -d`.
---
## Unreleased
---
## [2026-02-18]
### Storage
- Updated `supabase/storage-api` to `v1.37.8` in `docker-compose.s3.yml`
- Changed MinIO image in `docker-compose.s3.yml` to use Chainguard [minio](https://images.chainguard.dev/directory/image/minio/overview) and [minio-client](https://images.chainguard.dev/directory/image/minio-client/overview) (requires `docker-compose.s3.yml` update) - PR [#42942](https://github.com/supabase/supabase/pull/42942)
- Removed `imgproxy` service from `docker-compose.s3.yml` to minimize redundancy - PR [#42942](https://github.com/supabase/supabase/pull/42942)
- Fixed inconsistent `storage` service entry ordering in `docker-compose.yml` and `docker-compose.s3.yml` to improve diff readability (requires `docker-compose.yml` and `docker-compose.s3.yml` update) - PR [#42942](https://github.com/supabase/supabase/pull/42942)
### Edge Runtime
- Added a `deno-cache` named volume to to avoid re-downloading dependencies (requires `docker-compose.yml` and `volumes/functions/*` update) - PR [#40822](https://github.com/supabase/supabase/pull/40822)
---
## [2026-02-16]
⚠️ **Note:** This update includes several breaking changes, including a security fix for Analytics. Please check the details below. The following configuration files have been updated: `docker-compose.yml`, `.env.example`, `docker-compose.s3.yml`, `volumes/api/kong.yml`, and `volumes/logs/vector.yml`.
### Studio
- Updated to `2026.02.16-sha-26c615c`
- Added Edge Functions management UI (requires `docker-compose.yml` update) - PR [#40690](https://github.com/supabase/supabase/pull/40690), PR [#42322](https://github.com/supabase/supabase/pull/42322), PR [#42349](https://github.com/supabase/supabase/pull/42349), PR [#42350](https://github.com/supabase/supabase/pull/42350)
### MCP Server
- Updated to `v0.6.3` - [Release](https://github.com/supabase-community/supabase-mcp/releases/tag/v0.6.3)
### Auth
- Updated to `v2.186.0` - [Changelog](https://github.com/supabase/auth/blob/master/CHANGELOG.md) | [Release](https://github.com/supabase/auth/releases/tag/v2.186.0)
### PostgREST
- Updated to `v14.5` - [Changelog](https://github.com/PostgREST/postgrest/blob/main/CHANGELOG.md) | [Release](https://github.com/PostgREST/postgrest/releases/tag/v14.5)
### Realtime
- Updated to `v2.76.5` - [Release](https://github.com/supabase/realtime/releases/tag/v2.76.5)
### Storage
- Updated to `v1.37.8` - [Release](https://github.com/supabase/storage/releases/tag/v1.37.8)
- ⚠️ Added configuration to access buckets via `/storage/v1/s3` endpoint (requires `docker-compose.s3.yml` update) - PR [#37185](https://github.com/supabase/supabase/pull/37185)
- ⚠️ Changed environment variable configuration for Storage (requires `docker-compose.yml`, `.env.example` and `.env` update) - PR [#37185](https://github.com/supabase/supabase/pull/37185), PR [#42862](https://github.com/supabase/supabase/pull/42862)
### Edge Runtime
- Updated to `v1.70.3` - [Release](https://github.com/supabase/edge-runtime/releases/tag/v1.70.3)
### Analytics (Logflare)
- Updated to `v1.31.2` - [Release](https://github.com/Logflare/logflare/releases/tag/v1.31.2)
- ⚠️ Changed default configuration to disable Logflare on `0.0.0.0:4000` to prevent access to `/dashboard` (requires `docker-compose.yml` update). Read more in "Production Recommendations" section of Logflare [documentation](https://supabase.com/docs/reference/self-hosting-analytics/introduction) - PR [#42857](https://github.com/supabase/supabase/pull/42857)
- ⚠️ Changed Kong routes to not include `/analytics/v1` by default (requires `/volumes/api/kong.yml` update) - PR [#42857](https://github.com/supabase/supabase/pull/42857)
### Vector
- Updated to `0.53.0-alpine` - [Changelog](https://vector.dev/releases/0.53.0/) | [Release](https://github.com/vectordotdev/vector/releases/tag/v0.53.0)
- ⚠️ Major version jump from `0.28.1` (requires `volumes/logs/vector.yml` update) - PR [#42525](https://github.com/supabase/supabase/pull/42525)
- ⚠️ Changed Postgres sink configuration to bypass Kong (requires `volumes/logs/vector.yml` update) - PR [#42857](https://github.com/supabase/supabase/pull/42857)
- ⚠️ Changed retry settings for all sinks to increase timeouts (requires `volumes/logs/vector.yml` update) - PR [#42857](https://github.com/supabase/supabase/pull/42857)
---
## [2026-02-05]
### Storage
- Updated to `v1.37.1` - [Release](https://github.com/supabase/storage/releases/tag/v1.37.1)
- Fixed an issue with Storage not starting because of an issue with migrations - PR [storage#845](https://github.com/supabase/storage/pull/845)
---
## [2026-01-27]
### Studio
- Updated to `2026.01.27-sha-6aa59ff`
- Added SQL snippets (requires `docker-compose.yml` update) - PR [#41112](https://github.com/supabase/supabase/pull/41112), PR [#41557](https://github.com/supabase/supabase/pull/41557)
- Fixed type generator - PR [#40481](https://github.com/supabase/supabase/pull/40481)
- Fixed minor UI discrepancies - PR [#40579](https://github.com/supabase/supabase/pull/40579), PR [#41936](https://github.com/supabase/supabase/pull/41936), PR [#41970](https://github.com/supabase/supabase/pull/41970), PR [#41971](https://github.com/supabase/supabase/pull/41971), PR [#41972](https://github.com/supabase/supabase/pull/41972), PR [#42015](https://github.com/supabase/supabase/pull/42015)
### Auth
- Updated to `v2.185.0` - [Changelog](https://github.com/supabase/auth/blob/master/CHANGELOG.md) | [Release](https://github.com/supabase/auth/releases/tag/v2.185.0)
- ⚠️ Fixed security related issues
### PostgREST
- Updated to `v14.3` - [Changelog](https://github.com/PostgREST/postgrest/blob/main/CHANGELOG.md) | [Release](https://github.com/PostgREST/postgrest/releases/tag/v14.3)
### Realtime
- Updated to `v2.72.0` - [Release](https://github.com/supabase/realtime/releases/tag/v2.72.0)
- Changed healthchecks logging to off by default (requires `docker-compose.yml` update) - PR [realtime#1677](https://github.com/supabase/realtime/pull/1677), PR [#42156](https://github.com/supabase/supabase/pull/42156)
- Changed logging configuration and healthcheck frequency to reduce log volume (requires `docker-compose.yml` update) - PR [#42112](https://github.com/supabase/supabase/pull/42112)
### Storage
- Updated to `v1.33.5` - [Release](https://github.com/supabase/storage/releases/tag/v1.33.5)
### imgproxy
- Updated to `v3.30.1` - [Changelog](https://github.com/imgproxy/imgproxy/blob/master/CHANGELOG.md) | [Release](https://github.com/imgproxy/imgproxy/releases/tag/v3.30.1)
### Postgres Meta
- Updated to `v0.95.2` - [Release](https://github.com/supabase/postgres-meta/releases/tag/v0.95.2)
### Edge Runtime
- Updated to `v1.70.0` - [Release](https://github.com/supabase/edge-runtime/releases/tag/v1.70.0)
### Analytics (Logflare)
- Updated to `v1.30.3` - [Release](https://github.com/Logflare/logflare/releases/tag/v1.30.3)
### Postgres
- No image update
- Fixed Postgres logging configuration (requires `volumes/logs/vector.yml` update) - PR [#41800](https://github.com/supabase/supabase/pull/41800)
---
## [2025-12-18]
### Documentation
- Updated self-hosting installation and configuration guide - PR [#40901](https://github.com/supabase/supabase/pull/40901), PR [#41438](https://github.com/supabase/supabase/pull/41438)
### Utils
- Added `generate-keys.sh` - PR [#41363](https://github.com/supabase/supabase/pull/41363)
- Added `db-passwd.sh` - PR [#41432](https://github.com/supabase/supabase/pull/41432)
- Changed `reset.sh` to POSIX and added more checks - PR [#41361](https://github.com/supabase/supabase/pull/41361)
### Studio
- Updated to `2025.12.17-sha-43f4f7f`
- ⚠️ Fixed additional issues related to [React2Shell](https://vercel.com/kb/bulletin/react2shell)
- Fixed an issue with the Users page not being updated on changes - PR [#41254](https://github.com/supabase/supabase/pull/41254)
### MCP Server
- Updated to `v0.5.10` - [Release](https://github.com/supabase-community/supabase-mcp/releases/tag/v0.5.10)
### Auth
- Updated to `v2.184.0` - [Changelog](https://github.com/supabase/auth/blob/master/CHANGELOG.md) | [Release](https://github.com/supabase/auth/releases/tag/v2.184.0)
### Postgres Meta
- Updated to `v0.95.1` - [Release](https://github.com/supabase/postgres-meta/releases/tag/v0.95.1)
### Analytics (Logflare)
- Updated to `v1.27.0` - [Release](https://github.com/Logflare/logflare/releases/tag/v1.27.0)
- Fixed multiple issues, including a race condition
---
## [2025-12-10]
### Studio
- Updated to `2025.12.09-sha-434634f`
- ⚠️ Fixed security issues related to [React2Shell](https://vercel.com/kb/bulletin/react2shell)
### MCP Server
- Updated to `v0.5.9` - [Release](https://github.com/supabase-community/supabase-mcp/releases/tag/v0.5.9)
- ⚠️ Changed MCP tool `get_anon_key` to `get_publishable_keys`
### PostgREST
- Updated to `v14.1` - [Changelog](https://github.com/PostgREST/postgrest/blob/main/CHANGELOG.md) | [Release](https://github.com/PostgREST/postgrest/releases/tag/v14.1)
- ⚠️ **Major upgrade from v13.x to v14.x** - please report any unexpected behavior
### Realtime
- Updated to `v2.68.0` - [Releases](https://github.com/supabase/realtime/releases/tag/v2.68.0)
### Storage
- Updated to `v1.33.0` - [Release](https://github.com/supabase/storage/releases/tag/v1.33.0)
### Edge Runtime
- Updated to `v1.69.28` - [Release](https://github.com/supabase/edge-runtime/releases/tag/v1.69.28)
### Analytics (Logflare)
- Updated to `v1.26.25` - [Release](https://github.com/Logflare/logflare/releases/tag/v1.26.25)
---
## [2025-12-08]
### Realtime
- No image update
- Changed boolean values to strings in Docker Compose for better compatibility with Podman - PR [#40994](https://github.com/supabase/supabase/pull/40994), also PR [realtime#1614](https://github.com/supabase/realtime/pull/1614)
- Changed healthcheck in Docker Compose for better compatibility with Podman - PR [#41159](https://github.com/supabase/supabase/pull/41159)
---
## [2025-11-26]
### Studio
- Updated to `2025.11.26-sha-8f096b5`
- Fixed MCP `get_advisors` tool - PR [#40783](https://github.com/supabase/supabase/pull/40783)
- Fixed AI Assistant request schema - PR [#40830](https://github.com/supabase/supabase/pull/40830)
- Fixed log drains page - PR [#40835](https://github.com/supabase/supabase/pull/40835)
### Realtime
- Updated to `v2.65.3` - [Release](https://github.com/supabase/realtime/releases/tag/v2.65.3)
### Analytics (Logflare)
- Updated to `v1.26.13` - [Release](https://github.com/Logflare/logflare/releases/tag/v1.26.13)
- Fixed crashdump when `POSTGRES_BACKEND_URL` is malformed - PR [logflare#2954](https://github.com/Logflare/logflare/pull/2954)
---
## [2025-11-25]
### Studio
- Updated to `2025.11.24-sha-d990ae8` - [Dashboard updates](https://github.com/orgs/supabase/discussions/40734)
- Fixed Queues configuration UI and added [documentation for exposed queue schema](https://supabase.com/docs/guides/queues/expose-self-hosted-queues) - PR [#40078](https://github.com/supabase/supabase/pull/40078)
- Fixed parameterized SQL queries in MCP tools - PR [#40499](https://github.com/supabase/supabase/pull/40499)
- Fixed Studio showing paid options for log drains - PR [#40510](https://github.com/supabase/supabase/pull/40510)
- Fixed AI Assistant authentication - PR [#40654](https://github.com/supabase/supabase/pull/40654)
### Auth
- Updated to `v2.183.0` - [Changelog](https://github.com/supabase/auth/blob/master/CHANGELOG.md) | [Release](https://github.com/supabase/auth/releases/tag/v2.183.0)
### Realtime
- Updated to `v2.65.2` - [Release](https://github.com/supabase/realtime/releases/tag/v2.65.2)
- Fixed handling of boolean configurations options - PR [realtime#1614](https://github.com/supabase/realtime/pull/1614)
### Storage
- Updated to `v1.32.0` - [Release](https://github.com/supabase/storage/releases/tag/v1.32.0)
### Edge Runtime
- Updated to `v1.69.25` - [Release](https://github.com/supabase/edge-runtime/releases/tag/v1.69.25)
### Analytics (Logflare)
- Updated to `v1.26.12` - [Release](https://github.com/Logflare/logflare/releases/tag/v1.26.12)
- Fixed Auth logs query - PR [logflare#2936](https://github.com/Logflare/logflare/pull/2936)
- Fixed build configuration to prevent crashes with "Illegal instruction (core dumped)" - PR [logflare#2942](https://github.com/Logflare/logflare/pull/2942)
---
## [2025-11-17]
### Storage
- No image update
- Fixed resumable uploads for files larger than 6MB (requires `docker-compose.yml` update) - PR [#40500](https://github.com/supabase/supabase/pull/40500)
---
## [2025-11-12]
### Studio
- Updated to `2025.11.10-sha-5291fe3` - [Dashboard updates](https://github.com/orgs/supabase/discussions/40083)
- Added log drains - PR [#28297](https://github.com/supabase/supabase/pull/28297)
- Fixed Studio using `postgres` role instead of `supabase_admin` - PR [#39946](https://github.com/supabase/supabase/pull/39946)
### Auth
- Updated to `v2.182.1` - [Changelog](https://github.com/supabase/auth/blob/master/CHANGELOG.md#21821-2025-11-05) | [Release](https://github.com/supabase/auth/releases/tag/v2.182.1)
### Realtime
- Updated to `v2.63.0` - [Release](https://github.com/supabase/realtime/releases/tag/v2.63.0)
### Storage
- Updated to `v1.29.0` - [Release](https://github.com/supabase/storage/releases/tag/v1.29.0)
### Edge Runtime
- Updated to `v1.69.23` - [Release](https://github.com/supabase/edge-runtime/releases/tag/v1.69.23)
### Supavisor
- Updated to `v2.7.4` - [Release](https://github.com/supabase/supavisor/releases/tag/v2.7.4)
---
## [2025-11-05]
### Studio
- No image update
- Fixed Studio failing to connect to Postgres with non-default settings (requires `docker-compose.yml` update) - PR [#40169](https://github.com/supabase/supabase/pull/40169)
### Realtime
- No image update
- Fixed realtime logs not showing in Studio (requires `volumes/logs/vector.yml` update) - PR [#39963](https://github.com/supabase/supabase/pull/39963)
---
## [2025-10-28]
### Studio
- Updated to `2025.10.27-sha-85b84e0` - [Dashboard updates](https://github.com/orgs/supabase/discussions/40083)
- Fixed broken authentication when uploading files to Storage - PR [#39829](https://github.com/supabase/supabase/pull/39829)
### Realtime
- Updated to `v2.57.2` - [Release](https://github.com/supabase/realtime/releases/tag/v2.57.2)
### Storage
- Updated to `v1.28.2` - [Release](https://github.com/supabase/storage/releases/tag/v1.28.2)
### Postgres Meta
- Updated to `v0.93.1` - [Release](https://github.com/supabase/postgres-meta/releases/tag/v0.93.1)
### Edge Runtime
- Updated to `v1.69.15` - [Release](https://github.com/supabase/edge-runtime/releases/tag/v1.69.15)
---
## [2025-10-27]
### Studio
- No image update
- Added Kong configuration for MCP server routes (requires `volumes/api/kong.yml` update) - PR [#39849](https://github.com/supabase/supabase/pull/39849)
- Added [documentation page](https://supabase.com/docs/guides/self-hosting/enable-mcp) for MCP server configuration - PR [#39952](https://github.com/supabase/supabase/pull/39952)
---
## [2025-10-21]
### Studio
- Updated to `2025.10.20-sha-5005fc6` - [Dashboard updates](https://github.com/orgs/supabase/discussions/39709)
- Fixed issues with Edge Functions and cron logs not being visible in Studio - PR [#39388](https://github.com/supabase/supabase/pull/39388), PR [#39704](https://github.com/supabase/supabase/pull/39704), PR [#39711](https://github.com/supabase/supabase/pull/39711)
### Realtime
- Updated to `v2.56.0` - [Release](https://github.com/supabase/realtime/releases/tag/v2.56.0)
### Storage
- Updated to `v1.28.1` - [Release](https://github.com/supabase/storage/releases/tag/v1.28.1)
### Postgres Meta
- Updated to `v0.93.0` - [Release](https://github.com/supabase/postgres-meta/releases/tag/v0.93.0)
### Edge Runtime
- Updated to `v1.69.14` - [Release](https://github.com/supabase/edge-runtime/releases/tag/v1.69.14)
### Supavisor
- Updated to `v2.7.3` - [Release](https://github.com/supabase/supavisor/releases/tag/v2.7.3)
---
## [2025-10-13]
### Analytics (Logflare)
- Updated to `v1.22.6` - [Release](https://github.com/Logflare/logflare/releases/tag/v1.22.6)
---
## [2025-10-08]
### Studio
- Updated to `2025.10.01-sha-8460121` - [Dashboard updates](https://github.com/orgs/supabase/discussions/39709)
- Added "local" remote MCP server - PR [#38797](https://github.com/supabase/supabase/pull/38797), PR [#39041](https://github.com/supabase/supabase/pull/39041)
- ⚠️ Changed Studio connection method to `postgres-meta` - affects non-standard database port configurations
### Auth
- Updated to `v2.180.0` - [Release](https://github.com/supabase/auth/releases/tag/v2.180.0)
### PostgREST
- Updated to `v13.0.7` - [Release](https://github.com/PostgREST/postgrest/releases/tag/v13.0.7) | [Changelog](https://github.com/PostgREST/postgrest/blob/main/CHANGELOG.md)
### Realtime
- Updated to `v2.51.11` - [Release](https://github.com/supabase/realtime/releases/tag/v2.51.11)
### Storage
- Updated to `v1.28.0` - [Release](https://github.com/supabase/storage/releases/tag/v1.28.0)
### Postgres Meta
- Updated to `v0.91.6` - [Release](https://github.com/supabase/postgres-meta/releases/tag/v0.91.6)
### Analytics (Logflare)
- Updated to `v1.22.4` - [Release](https://github.com/Logflare/logflare/releases/tag/v1.22.4)
### Postgres
- Updated to `15.8.1.085` - [Release](https://github.com/supabase/postgres/releases/tag/15.8.1.085)
### Supavisor
- Updated to `2.7.0` - [Release](https://github.com/supabase/supavisor/releases/tag/v2.7.0)
---
+2 -86
View File
@@ -1,87 +1,3 @@
# Self-Hosted Supabase with Docker # Supabase Docker
This is the official Docker Compose setup for self-hosted Supabase. It provides a complete stack with all Supabase services running locally or on your infrastructure. This is a minimal Docker Compose setup for self-hosting Supabase. Follow the steps [here](https://supabase.com/docs/guides/hosting/docker) to get started.
## Getting Started
Follow the detailed setup guide in our documentation: [Self-Hosting with Docker](https://supabase.com/docs/guides/self-hosting/docker)
The guide covers:
- Prerequisites (Git and Docker)
- Initial setup and configuration
- Securing your installation
- Accessing services
- Updating your instance
## What's Included
This Docker Compose configuration includes the following services:
- **[Studio](https://github.com/supabase/supabase/tree/master/apps/studio)** - A dashboard for managing your self-hosted Supabase project
- **[Kong](https://github.com/Kong/kong)** - Kong API gateway
- **[Auth](https://github.com/supabase/auth)** - JWT-based authentication API for user sign-ups, logins, and session management
- **[PostgREST](https://github.com/PostgREST/postgrest)** - Web server that turns your PostgreSQL database directly into a RESTful API
- **[Realtime](https://github.com/supabase/realtime)** - Elixir server that listens to PostgreSQL database changes and broadcasts them over websockets
- **[Storage](https://github.com/supabase/storage)** - RESTful API for managing files in S3, with Postgres handling permissions
- **[imgproxy](https://github.com/imgproxy/imgproxy)** - Fast and secure image processing server
- **[postgres-meta](https://github.com/supabase/postgres-meta)** - RESTful API for managing Postgres (fetch tables, add roles, run queries)
- **[PostgreSQL](https://github.com/supabase/postgres)** - Object-relational database with over 30 years of active development
- **[Edge Runtime](https://github.com/supabase/edge-runtime)** - Web server based on Deno runtime for running JavaScript, TypeScript, and WASM services
- **[Logflare](https://github.com/Logflare/logflare)** - Log management and event analytics platform
- **[Vector](https://github.com/vectordotdev/vector)** - High-performance observability data pipeline for logs
- **[Supavisor](https://github.com/supabase/supavisor)** - Supabase's Postgres connection pooler
## Documentation
- **[Documentation](https://supabase.com/docs/guides/self-hosting/docker)** - Setup and configuration guides
- **[CHANGELOG.md](./CHANGELOG.md)** - Track recent updates and changes to services
- **[versions.md](./versions.md)** - Complete history of Docker image versions for rollback reference
## Updates
To update your self-hosted Supabase instance:
1. Review [CHANGELOG.md](./CHANGELOG.md) for breaking changes
2. Check [versions.md](./versions.md) for new image versions
3. Update `docker-compose.yml` if there are configuration changes
4. Pull the latest images: `docker compose pull`
5. Stop services: `docker compose down`
6. Start services with new configuration: `docker compose up -d`
**Note:** Consider to always backup your database before updating.
## Community & Support
For troubleshooting common issues, see:
- [GitHub Discussions](https://github.com/orgs/supabase/discussions?discussions_q=is%3Aopen+label%3Aself-hosted) - Questions, feature requests, and workarounds
- [GitHub Issues](https://github.com/supabase/supabase/issues?q=is%3Aissue%20state%3Aopen%20label%3Aself-hosted) - Known issues
- [Documentation](https://supabase.com/docs/guides/self-hosting) - Setup and configuration guides
Self-hosted Supabase is community-supported. Get help and connect with other users:
- [Discord](https://discord.supabase.com) - Real-time chat and community support
- [Reddit](https://www.reddit.com/r/Supabase/) - Official Supabase subreddit
Share your self-hosting experience:
- [GitHub Discussions](https://github.com/orgs/supabase/discussions/39820) - "Self-hosting: What's working (and what's not)?"
## Important Notes
### Security
⚠️ **The default configuration is not secure for production use.**
Before deploying to production, you must:
- Update all default passwords and secrets in the `.env` file
- Generate new JWT secrets
- Review and update CORS settings
- Consider setting up a secure proxy in front of self-hosted Supabase
- Review and adjust network security configuration (ACLs, etc.)
- Set up proper backup procedures
See the [security section](https://supabase.com/docs/guides/self-hosting/docker#configuring-and-securing-supabase) in the documentation.
## License
This repository is licensed under the Apache 2.0 License. See the main [Supabase repository](https://github.com/supabase/supabase) for details.
+1 -11
View File
@@ -4,20 +4,10 @@ services:
studio: studio:
build: build:
context: .. context: ..
dockerfile: apps/studio/Dockerfile dockerfile: studio/Dockerfile
target: dev target: dev
ports: ports:
- 8082:8082 - 8082:8082
develop:
watch:
- action: sync
path: ../apps/studio
target: /app/apps/studio
ignore:
- node_modules/
- action: rebuild
path: package.json
mail: mail:
container_name: supabase-mail container_name: supabase-mail
image: inbucket/inbucket:3.0.3 image: inbucket/inbucket:3.0.3
-34
View File
@@ -1,34 +0,0 @@
services:
kong:
ports: !reset []
caddy:
container_name: supabase-caddy
image: caddy:2
restart: unless-stopped
ports:
- "80:80"
- "443:443"
- "443:443/udp"
depends_on:
kong:
condition: service_healthy
environment:
PROXY_DOMAIN: ${PROXY_DOMAIN}
PROXY_AUTH_USERNAME: ${DASHBOARD_USERNAME}
PROXY_AUTH_PASSWORD: ${DASHBOARD_PASSWORD}
command:
- /bin/sh
- -c
- |
PROXY_AUTH_PASSWORD=$$(caddy hash-password --plaintext "$$PROXY_AUTH_PASSWORD") && \
caddy run --config /etc/caddy/Caddyfile --adapter caddyfile
volumes:
- ./volumes/proxy/caddy:/etc/caddy
- caddy_data:/data
- caddy_config:/config
volumes:
caddy_data:
caddy_config:
-33
View File
@@ -1,33 +0,0 @@
services:
kong:
ports: !reset []
nginx:
container_name: supabase-nginx
image: jonasal/nginx-certbot:6.0.1-nginx1.29.5
restart: unless-stopped
ports:
- "80:80"
- "443:443"
depends_on:
kong:
condition: service_healthy
environment:
PROXY_DOMAIN: ${PROXY_DOMAIN}
CERTBOT_EMAIL: ${CERTBOT_EMAIL}
PROXY_AUTH_USERNAME: ${DASHBOARD_USERNAME}
PROXY_AUTH_PASSWORD: ${DASHBOARD_PASSWORD}
command:
- /bin/bash
- -c
- |
printf '%s:%s\n' "$${PROXY_AUTH_USERNAME}" "$$(openssl passwd -apr1 "$${PROXY_AUTH_PASSWORD}")" > /etc/nginx/user_conf.d/dashboard-passwd && \
envsubst '$${PROXY_DOMAIN}' < /etc/nginx/supabase-nginx.conf.tpl > /etc/nginx/user_conf.d/nginx.conf && \
/scripts/start_nginx_certbot.sh
volumes:
- ./volumes/proxy/nginx/supabase-nginx.conf.tpl:/etc/nginx/supabase-nginx.conf.tpl:ro
- nginx_letsencrypt:/etc/letsencrypt
volumes:
nginx_letsencrypt:
+37 -30
View File
@@ -1,16 +1,16 @@
services: services:
minio: minio:
image: cgr.dev/chainguard/minio image: minio/minio
#ports: ports:
# - '9000:9000' - '9000:9000'
# - '9001:9001' - '9001:9001'
environment: environment:
MINIO_ROOT_USER: ${MINIO_ROOT_USER} MINIO_ROOT_USER: supa-storage
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD} MINIO_ROOT_PASSWORD: secret1234
command: server --console-address ":9001" /data command: server --console-address ":9001" /data
healthcheck: healthcheck:
test: [ "CMD", "mc", "ready", "local" ] test: [ "CMD", "curl", "-f", "http://minio:9000/minio/health/live" ]
interval: 2s interval: 2s
timeout: 10s timeout: 10s
retries: 5 retries: 5
@@ -18,20 +18,20 @@ services:
- ./volumes/storage:/data:z - ./volumes/storage:/data:z
minio-createbucket: minio-createbucket:
image: cgr.dev/chainguard/minio-client:latest-dev image: minio/mc
depends_on: depends_on:
minio: minio:
condition: service_healthy condition: service_healthy
entrypoint: > entrypoint: >
/bin/sh -ec " /bin/sh -c "
mc alias set supa-minio http://minio:9000 ${MINIO_ROOT_USER} ${MINIO_ROOT_PASSWORD} && /usr/bin/mc alias set supa-minio http://minio:9000 supa-storage secret1234;
mc mb --ignore-existing supa-minio/${GLOBAL_S3_BUCKET} /usr/bin/mc mb supa-minio/stub;
exit 0;
" "
storage: storage:
container_name: supabase-storage container_name: supabase-storage
image: supabase/storage-api:v1.37.8 image: supabase/storage-api:v1.11.13
restart: unless-stopped
depends_on: depends_on:
db: db:
# Disable this if you are using an external Postgres database # Disable this if you are using an external Postgres database
@@ -40,8 +40,6 @@ services:
condition: service_started condition: service_started
imgproxy: imgproxy:
condition: service_started condition: service_started
minio-createbucket:
condition: service_completed_successfully
minio: minio:
condition: service_healthy condition: service_healthy
healthcheck: healthcheck:
@@ -52,36 +50,45 @@ services:
"--no-verbose", "--no-verbose",
"--tries=1", "--tries=1",
"--spider", "--spider",
"http://storage:5000/status" "http://localhost:5000/status"
] ]
timeout: 5s timeout: 5s
interval: 5s interval: 5s
retries: 3 retries: 3
restart: unless-stopped
environment: environment:
ANON_KEY: ${ANON_KEY} ANON_KEY: ${ANON_KEY}
SERVICE_KEY: ${SERVICE_ROLE_KEY} SERVICE_KEY: ${SERVICE_ROLE_KEY}
POSTGREST_URL: http://rest:3000 POSTGREST_URL: http://rest:3000
PGRST_JWT_SECRET: ${JWT_SECRET} PGRST_JWT_SECRET: ${JWT_SECRET}
DATABASE_URL: postgres://supabase_storage_admin:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB} DATABASE_URL: postgres://supabase_storage_admin:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}
REQUEST_ALLOW_X_FORWARDED_PATH: "true"
FILE_SIZE_LIMIT: 52428800 FILE_SIZE_LIMIT: 52428800
STORAGE_BACKEND: s3 STORAGE_BACKEND: s3
# S3 bucket when using S3 backend, directory name when using 'file' GLOBAL_S3_BUCKET: stub
GLOBAL_S3_BUCKET: ${GLOBAL_S3_BUCKET}
# S3 Backend configuration
GLOBAL_S3_ENDPOINT: http://minio:9000 GLOBAL_S3_ENDPOINT: http://minio:9000
GLOBAL_S3_PROTOCOL: http GLOBAL_S3_PROTOCOL: http
GLOBAL_S3_FORCE_PATH_STYLE: true GLOBAL_S3_FORCE_PATH_STYLE: true
AWS_ACCESS_KEY_ID: ${MINIO_ROOT_USER} AWS_ACCESS_KEY_ID: supa-storage
AWS_SECRET_ACCESS_KEY: ${MINIO_ROOT_PASSWORD} AWS_SECRET_ACCESS_KEY: secret1234
#FILE_STORAGE_BACKEND_PATH: /var/lib/storage AWS_DEFAULT_REGION: stub
TENANT_ID: ${STORAGE_TENANT_ID} FILE_STORAGE_BACKEND_PATH: /var/lib/storage
TENANT_ID: stub
# TODO: https://github.com/supabase/storage-api/issues/55 # TODO: https://github.com/supabase/storage-api/issues/55
REGION: ${REGION} REGION: stub
ENABLE_IMAGE_TRANSFORMATION: "true" ENABLE_IMAGE_TRANSFORMATION: "true"
IMGPROXY_URL: http://imgproxy:5001 IMGPROXY_URL: http://imgproxy:5001
# S3 protocol endpoint configuration volumes:
S3_PROTOCOL_ACCESS_KEY_ID: ${S3_PROTOCOL_ACCESS_KEY_ID} - ./volumes/storage:/var/lib/storage:z
S3_PROTOCOL_ACCESS_KEY_SECRET: ${S3_PROTOCOL_ACCESS_KEY_SECRET}
#volumes: imgproxy:
# - ./volumes/storage:/var/lib/storage:z container_name: supabase-imgproxy
image: darthsim/imgproxy:v3.8.0
healthcheck:
test: [ "CMD", "imgproxy", "health" ]
timeout: 5s
interval: 5s
retries: 3
environment:
IMGPROXY_BIND: ":5001"
IMGPROXY_USE_ETAG: "true"
IMGPROXY_ENABLE_WEBP_DETECTION: ${IMGPROXY_ENABLE_WEBP_DETECTION}
+48 -120
View File
@@ -10,7 +10,7 @@ name: supabase
services: services:
studio: studio:
image: supabase/studio:2026.02.16-sha-26c615c image: supabase/studio:2025.05.19-sha-3487831
restart: unless-stopped restart: unless-stopped
healthcheck: healthcheck:
test: test:
@@ -28,15 +28,8 @@ services:
analytics: analytics:
condition: service_healthy condition: service_healthy
environment: environment:
# Binds nestjs listener to both IPv4 and IPv6 network interfaces
HOSTNAME: "::"
STUDIO_PG_META_URL: http://meta:8080 STUDIO_PG_META_URL: http://meta:8080
POSTGRES_PORT: ${POSTGRES_PORT}
POSTGRES_HOST: ${POSTGRES_HOST}
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
PG_META_CRYPTO_KEY: ${PG_META_CRYPTO_KEY}
DEFAULT_ORGANIZATION_NAME: ${STUDIO_DEFAULT_ORGANIZATION} DEFAULT_ORGANIZATION_NAME: ${STUDIO_DEFAULT_ORGANIZATION}
DEFAULT_PROJECT_NAME: ${STUDIO_DEFAULT_PROJECT} DEFAULT_PROJECT_NAME: ${STUDIO_DEFAULT_PROJECT}
@@ -48,22 +41,13 @@ services:
SUPABASE_SERVICE_KEY: ${SERVICE_ROLE_KEY} SUPABASE_SERVICE_KEY: ${SERVICE_ROLE_KEY}
AUTH_JWT_SECRET: ${JWT_SECRET} AUTH_JWT_SECRET: ${JWT_SECRET}
# LOGFLARE_API_KEY is deprecated LOGFLARE_API_KEY: ${LOGFLARE_API_KEY}
LOGFLARE_API_KEY: ${LOGFLARE_PUBLIC_ACCESS_TOKEN}
LOGFLARE_PUBLIC_ACCESS_TOKEN: ${LOGFLARE_PUBLIC_ACCESS_TOKEN}
LOGFLARE_PRIVATE_ACCESS_TOKEN: ${LOGFLARE_PRIVATE_ACCESS_TOKEN}
LOGFLARE_URL: http://analytics:4000 LOGFLARE_URL: http://analytics:4000
NEXT_PUBLIC_ENABLE_LOGS: true NEXT_PUBLIC_ENABLE_LOGS: true
# Comment to use Big Query backend for analytics # Comment to use Big Query backend for analytics
NEXT_ANALYTICS_BACKEND_PROVIDER: postgres NEXT_ANALYTICS_BACKEND_PROVIDER: postgres
# Uncomment to use Big Query backend for analytics # Uncomment to use Big Query backend for analytics
# NEXT_ANALYTICS_BACKEND_PROVIDER: bigquery # NEXT_ANALYTICS_BACKEND_PROVIDER: bigquery
SNIPPETS_MANAGEMENT_FOLDER: /app/snippets
EDGE_FUNCTIONS_MANAGEMENT_FOLDER: /app/edge-functions
volumes:
- ./volumes/snippets:/app/snippets:Z
- ./volumes/functions:/app/edge-functions:Z
kong: kong:
image: kong:2.8.1 image: kong:2.8.1
@@ -71,8 +55,6 @@ services:
volumes: volumes:
# https://github.com/supabase/supabase/issues/12661 # https://github.com/supabase/supabase/issues/12661
- ./volumes/api/kong.yml:/home/kong/temp.yml:ro,z - ./volumes/api/kong.yml:/home/kong/temp.yml:ro,z
#- ./volumes/api/server.crt:/home/kong/server.crt:ro
#- ./volumes/api/server.key:/home/kong/server.key:ro
depends_on: depends_on:
analytics: analytics:
condition: service_healthy condition: service_healthy
@@ -81,11 +63,9 @@ services:
KONG_DECLARATIVE_CONFIG: /home/kong/kong.yml KONG_DECLARATIVE_CONFIG: /home/kong/kong.yml
# https://github.com/supabase/cli/issues/14 # https://github.com/supabase/cli/issues/14
KONG_DNS_ORDER: LAST,A,CNAME KONG_DNS_ORDER: LAST,A,CNAME
KONG_PLUGINS: request-transformer,cors,key-auth,acl,basic-auth,request-termination,ip-restriction KONG_PLUGINS: request-transformer,cors,key-auth,acl,basic-auth
KONG_NGINX_PROXY_PROXY_BUFFER_SIZE: 160k KONG_NGINX_PROXY_PROXY_BUFFER_SIZE: 160k
KONG_NGINX_PROXY_PROXY_BUFFERS: 64 160k KONG_NGINX_PROXY_PROXY_BUFFERS: 64 160k
#KONG_SSL_CERT: /home/kong/server.crt
#KONG_SSL_CERT_KEY: /home/kong/server.key
SUPABASE_ANON_KEY: ${ANON_KEY} SUPABASE_ANON_KEY: ${ANON_KEY}
SUPABASE_SERVICE_KEY: ${SERVICE_ROLE_KEY} SUPABASE_SERVICE_KEY: ${SERVICE_ROLE_KEY}
DASHBOARD_USERNAME: ${DASHBOARD_USERNAME} DASHBOARD_USERNAME: ${DASHBOARD_USERNAME}
@@ -95,7 +75,7 @@ services:
/docker-entrypoint.sh kong docker-start' /docker-entrypoint.sh kong docker-start'
auth: auth:
image: supabase/gotrue:v2.186.0 image: supabase/gotrue:v2.172.1
restart: unless-stopped restart: unless-stopped
healthcheck: healthcheck:
test: test:
@@ -120,7 +100,10 @@ services:
GOTRUE_API_HOST: 0.0.0.0 GOTRUE_API_HOST: 0.0.0.0
GOTRUE_API_PORT: 9999 GOTRUE_API_PORT: 9999
API_EXTERNAL_URL: ${API_EXTERNAL_URL} API_EXTERNAL_URL: ${API_EXTERNAL_URL}
GOTRUE_EXTERNAL_GOOGLE_ENABLED: ${GOOGLE_ENABLED}
GOTRUE_EXTERNAL_GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID}
GOTRUE_EXTERNAL_GOOGLE_SECRET: ${GOOGLE_SECRET}
GOTRUE_EXTERNAL_GOOGLE_REDIRECT_URI: ${API_EXTERNAL_URL}/auth/v1/callback
GOTRUE_DB_DRIVER: postgres GOTRUE_DB_DRIVER: postgres
GOTRUE_DB_DATABASE_URL: postgres://supabase_auth_admin:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB} GOTRUE_DB_DATABASE_URL: postgres://supabase_auth_admin:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}
@@ -156,47 +139,7 @@ services:
GOTRUE_EXTERNAL_PHONE_ENABLED: ${ENABLE_PHONE_SIGNUP} GOTRUE_EXTERNAL_PHONE_ENABLED: ${ENABLE_PHONE_SIGNUP}
GOTRUE_SMS_AUTOCONFIRM: ${ENABLE_PHONE_AUTOCONFIRM} GOTRUE_SMS_AUTOCONFIRM: ${ENABLE_PHONE_AUTOCONFIRM}
# Uncomment to enable OAuth / social login providers. # Uncomment to enable custom access token hook. Please see: https://supabase.com/docs/guides/auth/auth-hooks for full list of hooks and additional details about custom_access_token_hook
# GOTRUE_EXTERNAL_GOOGLE_ENABLED: ${GOOGLE_ENABLED}
# GOTRUE_EXTERNAL_GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID}
# GOTRUE_EXTERNAL_GOOGLE_SECRET: ${GOOGLE_SECRET}
# GOTRUE_EXTERNAL_GOOGLE_REDIRECT_URI: ${API_EXTERNAL_URL}/auth/v1/callback
# GOTRUE_EXTERNAL_GITHUB_ENABLED: ${GITHUB_ENABLED}
# GOTRUE_EXTERNAL_GITHUB_CLIENT_ID: ${GITHUB_CLIENT_ID}
# GOTRUE_EXTERNAL_GITHUB_SECRET: ${GITHUB_SECRET}
# GOTRUE_EXTERNAL_GITHUB_REDIRECT_URI: ${API_EXTERNAL_URL}/auth/v1/callback
# GOTRUE_EXTERNAL_AZURE_ENABLED: ${AZURE_ENABLED}
# GOTRUE_EXTERNAL_AZURE_CLIENT_ID: ${AZURE_CLIENT_ID}
# GOTRUE_EXTERNAL_AZURE_SECRET: ${AZURE_SECRET}
# GOTRUE_EXTERNAL_AZURE_REDIRECT_URI: ${API_EXTERNAL_URL}/auth/v1/callback
# Uncomment to configure SMS delivery (phone auth and phone MFA).
# GOTRUE_SMS_PROVIDER: ${SMS_PROVIDER}
# GOTRUE_SMS_OTP_EXP: ${SMS_OTP_EXP}
# GOTRUE_SMS_OTP_LENGTH: ${SMS_OTP_LENGTH}
# GOTRUE_SMS_MAX_FREQUENCY: ${SMS_MAX_FREQUENCY}
# GOTRUE_SMS_TEMPLATE: ${SMS_TEMPLATE}
# Twilio credentials (when SMS_PROVIDER=twilio)
# GOTRUE_SMS_TWILIO_ACCOUNT_SID: ${SMS_TWILIO_ACCOUNT_SID}
# GOTRUE_SMS_TWILIO_AUTH_TOKEN: ${SMS_TWILIO_AUTH_TOKEN}
# GOTRUE_SMS_TWILIO_MESSAGE_SERVICE_SID: ${SMS_TWILIO_MESSAGE_SERVICE_SID}
# Test OTP mappings for development
# GOTRUE_SMS_TEST_OTP: ${SMS_TEST_OTP}
# Uncomment to configure multi-factor authentication (MFA).
# GOTRUE_MFA_TOTP_ENROLL_ENABLED: ${MFA_TOTP_ENROLL_ENABLED}
# GOTRUE_MFA_TOTP_VERIFY_ENABLED: ${MFA_TOTP_VERIFY_ENABLED}
# GOTRUE_MFA_PHONE_ENROLL_ENABLED: ${MFA_PHONE_ENROLL_ENABLED}
# GOTRUE_MFA_PHONE_VERIFY_ENABLED: ${MFA_PHONE_VERIFY_ENABLED}
# GOTRUE_MFA_MAX_ENROLLED_FACTORS: ${MFA_MAX_ENROLLED_FACTORS}
# Uncomment to enable custom access token hook.
# See: https://supabase.com/docs/guides/auth/auth-hooks for
# full list of hooks and additional details about custom_access_token_hook
# GOTRUE_HOOK_CUSTOM_ACCESS_TOKEN_ENABLED: "true" # GOTRUE_HOOK_CUSTOM_ACCESS_TOKEN_ENABLED: "true"
# GOTRUE_HOOK_CUSTOM_ACCESS_TOKEN_URI: "pg-functions://postgres/public/custom_access_token_hook" # GOTRUE_HOOK_CUSTOM_ACCESS_TOKEN_URI: "pg-functions://postgres/public/custom_access_token_hook"
@@ -217,7 +160,7 @@ services:
# GOTRUE_HOOK_SEND_EMAIL_SECRETS: "v1,whsec_VGhpcyBpcyBhbiBleGFtcGxlIG9mIGEgc2hvcnRlciBCYXNlNjQgc3RyaW5n" # GOTRUE_HOOK_SEND_EMAIL_SECRETS: "v1,whsec_VGhpcyBpcyBhbiBleGFtcGxlIG9mIGEgc2hvcnRlciBCYXNlNjQgc3RyaW5n"
rest: rest:
image: postgrest/postgrest:v14.5 image: postgrest/postgrest:v12.2.12
restart: unless-stopped restart: unless-stopped
depends_on: depends_on:
db: db:
@@ -237,7 +180,7 @@ services:
realtime: realtime:
# This container name looks inconsistent but is correct because realtime constructs tenant id by parsing the subdomain # This container name looks inconsistent but is correct because realtime constructs tenant id by parsing the subdomain
image: supabase/realtime:v2.76.5 image: supabase/realtime:v2.34.47
restart: unless-stopped restart: unless-stopped
depends_on: depends_on:
db: db:
@@ -248,14 +191,19 @@ services:
healthcheck: healthcheck:
test: test:
[ [
"CMD-SHELL", "CMD",
"curl -sSfL --head -o /dev/null -H \"Authorization: Bearer "curl",
${ANON_KEY}\" http://localhost:4000/api/tenants/realtime-dev/health" "-sSfL",
"--head",
"-o",
"/dev/null",
"-H",
"Authorization: Bearer ${ANON_KEY}",
"http://localhost:4000/api/tenants/realtime-dev/health"
] ]
timeout: 5s timeout: 5s
interval: 30s interval: 5s
retries: 3 retries: 3
start_period: 10s
environment: environment:
PORT: 4000 PORT: 4000
DB_HOST: ${POSTGRES_HOST} DB_HOST: ${POSTGRES_HOST}
@@ -271,22 +219,15 @@ services:
DNS_NODES: "''" DNS_NODES: "''"
RLIMIT_NOFILE: "10000" RLIMIT_NOFILE: "10000"
APP_NAME: realtime APP_NAME: realtime
SEED_SELF_HOST: "true" SEED_SELF_HOST: true
RUN_JANITOR: "true" RUN_JANITOR: true
DISABLE_HEALTHCHECK_LOGGING: "true"
# To use S3 backed storage: docker compose -f docker-compose.yml -f docker-compose.s3.yml up # To use S3 backed storage: docker compose -f docker-compose.yml -f docker-compose.s3.yml up
storage: storage:
image: supabase/storage-api:v1.37.8 image: supabase/storage-api:v1.22.17
restart: unless-stopped restart: unless-stopped
depends_on: volumes:
db: - ./volumes/storage:/var/lib/storage:z
# Disable this if you are using an external Postgres database
condition: service_healthy
rest:
condition: service_started
imgproxy:
condition: service_started
healthcheck: healthcheck:
test: test:
[ [
@@ -300,37 +241,32 @@ services:
timeout: 5s timeout: 5s
interval: 5s interval: 5s
retries: 3 retries: 3
depends_on:
db:
# Disable this if you are using an external Postgres database
condition: service_healthy
rest:
condition: service_started
imgproxy:
condition: service_started
environment: environment:
ANON_KEY: ${ANON_KEY} ANON_KEY: ${ANON_KEY}
SERVICE_KEY: ${SERVICE_ROLE_KEY} SERVICE_KEY: ${SERVICE_ROLE_KEY}
POSTGREST_URL: http://rest:3000 POSTGREST_URL: http://rest:3000
PGRST_JWT_SECRET: ${JWT_SECRET} PGRST_JWT_SECRET: ${JWT_SECRET}
DATABASE_URL: postgres://supabase_storage_admin:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB} DATABASE_URL: postgres://supabase_storage_admin:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}
REQUEST_ALLOW_X_FORWARDED_PATH: "true"
FILE_SIZE_LIMIT: 52428800 FILE_SIZE_LIMIT: 52428800
STORAGE_BACKEND: file STORAGE_BACKEND: file
# S3 bucket when using S3 backend, directory name when using 'file'
GLOBAL_S3_BUCKET: ${GLOBAL_S3_BUCKET}
# S3 Backend configuration
#GLOBAL_S3_ENDPOINT: https://your-s3-endpoint
#GLOBAL_S3_PROTOCOL: https
#GLOBAL_S3_FORCE_PATH_STYLE: true
#AWS_ACCESS_KEY_ID: your-access-key-id
#AWS_SECRET_ACCESS_KEY: your-secret-access-key
FILE_STORAGE_BACKEND_PATH: /var/lib/storage FILE_STORAGE_BACKEND_PATH: /var/lib/storage
TENANT_ID: ${STORAGE_TENANT_ID} TENANT_ID: stub
# TODO: https://github.com/supabase/storage-api/issues/55 # TODO: https://github.com/supabase/storage-api/issues/55
REGION: ${REGION} REGION: stub
GLOBAL_S3_BUCKET: stub
ENABLE_IMAGE_TRANSFORMATION: "true" ENABLE_IMAGE_TRANSFORMATION: "true"
IMGPROXY_URL: http://imgproxy:5001 IMGPROXY_URL: http://imgproxy:5001
# S3 protocol endpoint configuration
S3_PROTOCOL_ACCESS_KEY_ID: ${S3_PROTOCOL_ACCESS_KEY_ID}
S3_PROTOCOL_ACCESS_KEY_SECRET: ${S3_PROTOCOL_ACCESS_KEY_SECRET}
volumes:
- ./volumes/storage:/var/lib/storage:z
imgproxy: imgproxy:
image: darthsim/imgproxy:v3.30.1 image: darthsim/imgproxy:v3.8.0
restart: unless-stopped restart: unless-stopped
volumes: volumes:
- ./volumes/storage:/var/lib/storage:z - ./volumes/storage:/var/lib/storage:z
@@ -344,10 +280,9 @@ services:
IMGPROXY_LOCAL_FILESYSTEM_ROOT: / IMGPROXY_LOCAL_FILESYSTEM_ROOT: /
IMGPROXY_USE_ETAG: "true" IMGPROXY_USE_ETAG: "true"
IMGPROXY_ENABLE_WEBP_DETECTION: ${IMGPROXY_ENABLE_WEBP_DETECTION} IMGPROXY_ENABLE_WEBP_DETECTION: ${IMGPROXY_ENABLE_WEBP_DETECTION}
IMGPROXY_MAX_SRC_RESOLUTION: 16.8
meta: meta:
image: supabase/postgres-meta:v0.95.2 image: supabase/postgres-meta:v0.89.0
restart: unless-stopped restart: unless-stopped
depends_on: depends_on:
db: db:
@@ -362,21 +297,18 @@ services:
PG_META_DB_NAME: ${POSTGRES_DB} PG_META_DB_NAME: ${POSTGRES_DB}
PG_META_DB_USER: supabase_admin PG_META_DB_USER: supabase_admin
PG_META_DB_PASSWORD: ${POSTGRES_PASSWORD} PG_META_DB_PASSWORD: ${POSTGRES_PASSWORD}
CRYPTO_KEY: ${PG_META_CRYPTO_KEY}
functions: functions:
image: supabase/edge-runtime:v1.70.3 image: supabase/edge-runtime:v1.67.4
restart: unless-stopped restart: unless-stopped
volumes: volumes:
- ./volumes/functions:/home/deno/functions:Z - ./volumes/functions:/home/deno/functions:Z
- deno-cache:/root/.cache/deno
depends_on: depends_on:
analytics: analytics:
condition: service_healthy condition: service_healthy
environment: environment:
JWT_SECRET: ${JWT_SECRET} JWT_SECRET: ${JWT_SECRET}
SUPABASE_URL: http://kong:8000 SUPABASE_URL: http://kong:8000
SUPABASE_PUBLIC_URL: ${SUPABASE_PUBLIC_URL}
SUPABASE_ANON_KEY: ${ANON_KEY} SUPABASE_ANON_KEY: ${ANON_KEY}
SUPABASE_SERVICE_ROLE_KEY: ${SERVICE_ROLE_KEY} SUPABASE_SERVICE_ROLE_KEY: ${SERVICE_ROLE_KEY}
SUPABASE_DB_URL: postgresql://postgres:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB} SUPABASE_DB_URL: postgresql://postgres:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}
@@ -385,10 +317,8 @@ services:
command: [ "start", "--main-service", "/home/deno/functions/main" ] command: [ "start", "--main-service", "/home/deno/functions/main" ]
analytics: analytics:
image: supabase/logflare:1.31.2 image: supabase/logflare:1.12.0
restart: unless-stopped restart: unless-stopped
# ports:
# - 4000:4000
# Uncomment to use Big Query backend for analytics # Uncomment to use Big Query backend for analytics
# volumes: # volumes:
# - type: bind # - type: bind
@@ -412,10 +342,10 @@ services:
DB_PORT: ${POSTGRES_PORT} DB_PORT: ${POSTGRES_PORT}
DB_PASSWORD: ${POSTGRES_PASSWORD} DB_PASSWORD: ${POSTGRES_PASSWORD}
DB_SCHEMA: _analytics DB_SCHEMA: _analytics
LOGFLARE_PUBLIC_ACCESS_TOKEN: ${LOGFLARE_PUBLIC_ACCESS_TOKEN} LOGFLARE_API_KEY: ${LOGFLARE_API_KEY}
LOGFLARE_PRIVATE_ACCESS_TOKEN: ${LOGFLARE_PRIVATE_ACCESS_TOKEN}
LOGFLARE_SINGLE_TENANT: true LOGFLARE_SINGLE_TENANT: true
LOGFLARE_SUPABASE_MODE: true LOGFLARE_SUPABASE_MODE: true
LOGFLARE_MIN_CLUSTER_SIZE: 1
# Comment variables to use Big Query backend for analytics # Comment variables to use Big Query backend for analytics
POSTGRES_BACKEND_URL: postgresql://supabase_admin:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/_supabase POSTGRES_BACKEND_URL: postgresql://supabase_admin:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/_supabase
@@ -427,7 +357,7 @@ services:
# Comment out everything below this point if you are using an external Postgres database # Comment out everything below this point if you are using an external Postgres database
db: db:
image: supabase/postgres:15.8.1.085 image: supabase/postgres:15.8.1.060
restart: unless-stopped restart: unless-stopped
volumes: volumes:
- ./volumes/db/realtime.sql:/docker-entrypoint-initdb.d/migrations/99-realtime.sql:Z - ./volumes/db/realtime.sql:/docker-entrypoint-initdb.d/migrations/99-realtime.sql:Z
@@ -475,7 +405,7 @@ services:
] ]
vector: vector:
image: timberio/vector:0.53.0-alpine image: timberio/vector:0.28.1-alpine
restart: unless-stopped restart: unless-stopped
volumes: volumes:
- ./volumes/logs/vector.yml:/etc/vector/vector.yml:ro,z - ./volumes/logs/vector.yml:/etc/vector/vector.yml:ro,z
@@ -494,14 +424,14 @@ services:
interval: 5s interval: 5s
retries: 3 retries: 3
environment: environment:
LOGFLARE_PUBLIC_ACCESS_TOKEN: ${LOGFLARE_PUBLIC_ACCESS_TOKEN} LOGFLARE_API_KEY: ${LOGFLARE_API_KEY}
command: [ "--config", "/etc/vector/vector.yml" ] command: [ "--config", "/etc/vector/vector.yml" ]
security_opt: security_opt:
- "label=disable" - "label=disable"
# Update the DATABASE_URL if you are using an external Postgres database # Update the DATABASE_URL if you are using an external Postgres database
supavisor: supavisor:
image: supabase/supavisor:2.7.4 image: supabase/supavisor:2.5.1
restart: unless-stopped restart: unless-stopped
volumes: volumes:
- ./volumes/pooler/pooler.exs:/etc/pooler/pooler.exs:ro,z - ./volumes/pooler/pooler.exs:/etc/pooler/pooler.exs:ro,z
@@ -529,7 +459,7 @@ services:
POSTGRES_PORT: ${POSTGRES_PORT} POSTGRES_PORT: ${POSTGRES_PORT}
POSTGRES_DB: ${POSTGRES_DB} POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
DATABASE_URL: ecto://supabase_admin:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/_supabase DATABASE_URL: ecto://supabase_admin:${POSTGRES_PASSWORD}@db:${POSTGRES_PORT}/_supabase
CLUSTER_POSTGRES: true CLUSTER_POSTGRES: true
SECRET_KEY_BASE: ${SECRET_KEY_BASE} SECRET_KEY_BASE: ${SECRET_KEY_BASE}
VAULT_ENC_KEY: ${VAULT_ENC_KEY} VAULT_ENC_KEY: ${VAULT_ENC_KEY}
@@ -541,7 +471,6 @@ services:
POOLER_DEFAULT_POOL_SIZE: ${POOLER_DEFAULT_POOL_SIZE} POOLER_DEFAULT_POOL_SIZE: ${POOLER_DEFAULT_POOL_SIZE}
POOLER_MAX_CLIENT_CONN: ${POOLER_MAX_CLIENT_CONN} POOLER_MAX_CLIENT_CONN: ${POOLER_MAX_CLIENT_CONN}
POOLER_POOL_MODE: transaction POOLER_POOL_MODE: transaction
DB_POOL_SIZE: ${POOLER_DB_POOL_SIZE}
command: command:
[ [
"/bin/sh", "/bin/sh",
@@ -552,4 +481,3 @@ services:
volumes: volumes:
db-config: db-config:
deno-cache:
+29 -61
View File
@@ -1,76 +1,44 @@
#!/bin/sh #!/bin/bash
set -e echo "WARNING: This will remove all containers and container data, and will reset the .env file. This action cannot be undone!"
read -p "Are you sure you want to proceed? (y/N) " -n 1 -r
auto_confirm=0 echo # Move to a new line
if [[ ! $REPLY =~ ^[Yy]$ ]]
confirm () { then
if [ "$auto_confirm" = "1" ]; then echo "Operation cancelled."
return 0 exit 1
fi
printf "Are you sure you want to proceed? (y/N) "
read -r REPLY
case "$REPLY" in
[Yy])
;;
*)
echo "Script canceled."
exit 1
;;
esac
}
if [ "$1" = "-y" ]; then
auto_confirm=1
fi fi
echo "" echo "Stopping and removing all containers..."
echo "*** WARNING: This will remove all containers and container data, and optionally reset .env ***" docker compose -f docker-compose.yml -f ./dev/docker-compose.dev.yml down -v --remove-orphans
echo ""
confirm echo "Cleaning up bind-mounted directories..."
BIND_MOUNTS=(
"./volumes/db/data"
)
echo "===> Stopping and removing all containers..." for DIR in "${BIND_MOUNTS[@]}"; do
if [ -d "$DIR" ]; then
if [ -f ".env" ]; then echo "Deleting $DIR..."
docker compose -f docker-compose.yml -f ./dev/docker-compose.dev.yml down -v --remove-orphans rm -rf "$DIR"
elif [ -f ".env.example" ]; then else
echo "No .env found, using .env.example for docker compose down..." echo "Directory $DIR does not exist. Skipping bind mount deletion step..."
docker compose --env-file .env.example -f docker-compose.yml -f ./dev/docker-compose.dev.yml down -v --remove-orphans fi
else
echo "Skipping 'docker compose down' because there's no env-file."
fi
echo "===> Cleaning up bind-mounted directories..."
BIND_MOUNTS="./volumes/db/data ./volumes/storage"
for dir in $BIND_MOUNTS; do
if [ -d "$dir" ]; then
echo "Removing $dir..."
confirm
rm -rf "$dir"
else
echo "$dir not found."
fi
done done
echo "===> Resetting .env file (will save backup to .env.old)..." echo "Resetting .env file..."
confirm if [ -f ".env" ]; then
if [ -f ".env" ] || [ -L ".env" ]; then echo "Removing existing .env file..."
echo "Renaming existing .env file to .env.old" rm -f .env
mv .env .env.old
else else
echo "No .env file found." echo "No .env file found. Skipping .env removal step..."
fi fi
if [ -f ".env.example" ]; then if [ -f ".env.example" ]; then
echo "===> Copying .env.example to .env" echo "Copying .env.example to .env..."
cp .env.example .env cp .env.example .env
else else
echo "No .env.example found, can't restore .env to default values." echo ".env.example file not found. Skipping .env reset step..."
fi fi
echo "Cleanup complete!" echo "Cleanup complete!"
echo "Re-run 'docker compose pull' to update images."
echo ""
-157
View File
@@ -1,157 +0,0 @@
#!/bin/sh
#
# Portions of this code are derived from Inder Singh's update-db-pass.sh
# Copyright 2025 Inder Singh. Licensed under Apache License 2.0.
# Original source:
# https://github.com/singh-inder/supabase-automated-self-host/blob/main/docker/update-db-pass.sh
#
# GitHub discussion here:
# https://github.com/supabase/supabase/issues/22605#issuecomment-3323382144
#
# Changed:
# - POSIX shell compatibility
# - No hardcoded values for database service and admin user
# - Use .env for the admin user and database service port
# - Does _not_ set password for supabase_read_only_user (this role is not
# supposed to have a password)
# - Print all values and confirm before updating
# - Stop on any errors
#
# Heads up:
# - Updating _analytics.source_backends is not needed after PR logflare#2069
# - Newer Logflare versions use a different table and update connection string
#
set -e
if ! docker compose version > /dev/null 2>&1; then
echo "Docker Compose not found."
exit 1
fi
if [ ! -f .env ]; then
echo "Missing .env file. Exiting."
exit 1
fi
# Generate random hex-only password to avoid issues with SQL/shell
new_passwd="$(openssl rand -hex 16)"
# If replacing with a custom password, avoid using @/?#:&
# https://supabase.com/docs/guides/database/postgres/roles#passwords
# new_passwd="d0notUseSpecialSymbolsForPq123-"
# Check Postgres service
db_image_prefix="supabase.postgres:"
compose_output=$(docker compose ps \
--format '{{.Image}}\t{{.Service}}\t{{.Status}}' 2>/dev/null | \
grep -m1 "^$db_image_prefix" || true)
if [ -z "$compose_output" ]; then
echo "Postgres container not found. Exiting."
exit 1
fi
db_image=$(echo "$compose_output" | cut -f1)
db_srv_name=$(echo "$compose_output" | cut -f2)
db_srv_status=$(echo "$compose_output" | cut -f3)
case "$db_srv_status" in
Up*)
;;
*)
echo "Postgres container status: $db_srv_status"
echo "Exiting."
exit 1
;;
esac
db_srv_port=$(grep "^POSTGRES_PORT=" .env | cut -d '=' -f 2)
port_source=" (.env):"
if [ -z "$db_srv_port" ]; then
db_srv_port="5432"
port_source=" (default):"
fi
db_admin_user="supabase_admin"
echo ""
echo "*** Check configuration below before updating database passwords! ***"
echo ""
echo "Service name: $db_srv_name"
echo "Service status: $db_srv_status"
echo "Service port${port_source} $db_srv_port"
echo "Image: $db_image"
echo ""
echo "Admin user: $db_admin_user"
if ! test -t 0; then
echo ""
echo "Running non-interactively. Not updating passwords."
exit 0
fi
echo "New database password: $new_passwd"
echo ""
printf "Update database passwords? (y/N) "
read -r REPLY
case "$REPLY" in
[Yy])
;;
*)
echo "Canceled. Not updating passwords."
exit 0
;;
esac
echo "Updating passwords..."
echo "Connecting to the database service container..."
docker compose exec -T "$db_srv_name" psql -U "$db_admin_user" -d "_supabase" -v ON_ERROR_STOP=1 <<EOF
alter user anon with password '${new_passwd}';
alter user authenticated with password '${new_passwd}';
alter user authenticator with password '${new_passwd}';
alter user dashboard_user with password '${new_passwd}';
alter user pgbouncer with password '${new_passwd}';
alter user postgres with password '${new_passwd}';
alter user service_role with password '${new_passwd}';
alter user supabase_admin with password '${new_passwd}';
alter user supabase_auth_admin with password '${new_passwd}';
alter user supabase_functions_admin with password '${new_passwd}';
alter user supabase_replication_admin with password '${new_passwd}';
alter user supabase_storage_admin with password '${new_passwd}';
DROP SCHEMA _supavisor CASCADE;
create schema if not exists _supavisor;
alter schema _supavisor owner to supabase_admin;
DO \$\$
BEGIN
IF EXISTS (
SELECT 1
FROM information_schema.tables
WHERE table_schema = '_analytics'
AND table_name = 'source_backends'
) THEN
UPDATE _analytics.source_backends
SET config = jsonb_set(
config,
'{url}',
'"postgresql://${db_admin_user}:${new_passwd}@${db_srv_name}:${db_srv_port}/postgres"',
false
)
WHERE type = 'postgres';
END IF;
END
\$\$;
EOF
echo "Updating POSTGRES_PASSWORD in .env..."
sed -i.old "s|^POSTGRES_PASSWORD=.*$|POSTGRES_PASSWORD=$new_passwd|" .env
echo ""
echo "Success. To update and restart containers use:"
echo ""
echo "docker compose up -d --force-recreate"
echo ""
-123
View File
@@ -1,123 +0,0 @@
#!/bin/sh
#
# Portions of this code are derived from Inder Singh's setup.sh shell script.
# Copyright 2025 Inder Singh. Licensed under Apache License 2.0.
# Original source: https://github.com/singh-inder/supabase-automated-self-host/blob/main/setup.sh
#
set -e
gen_hex() {
openssl rand -hex "$1"
}
gen_base64() {
openssl rand -base64 "$1"
}
base64_url_encode() {
openssl enc -base64 -A | tr '+/' '-_' | tr -d '='
}
gen_token() {
payload=$1
payload_base64=$(printf %s "$payload" | base64_url_encode)
header_base64=$(printf %s "$header" | base64_url_encode)
signed_content="${header_base64}.${payload_base64}"
signature=$(printf %s "$signed_content" | openssl dgst -binary -sha256 -hmac "$jwt_secret" | base64_url_encode)
printf '%s' "${signed_content}.${signature}"
}
if ! command -v openssl >/dev/null 2>&1; then
echo "Error: openssl is required but not found."
exit 1
fi
jwt_secret="$(gen_base64 30)"
# Used in get_token()
header='{"alg":"HS256","typ":"JWT"}'
iat=$(date +%s)
exp=$((iat + 5 * 3600 * 24 * 365)) # 5 years
# Normalizes JSON formatting so that the token matches https://www.jwt.io/ results
anon_payload="{\"role\":\"anon\",\"iss\":\"supabase\",\"iat\":$iat,\"exp\":$exp}"
service_role_payload="{\"role\":\"service_role\",\"iss\":\"supabase\",\"iat\":$iat,\"exp\":$exp}"
#echo "anon_payload=$anon_payload"
#echo "service_role_payload=$service_role_payload"
anon_key=$(gen_token "$anon_payload")
service_role_key=$(gen_token "$service_role_payload")
secret_key_base=$(gen_base64 48)
vault_enc_key=$(gen_hex 16)
pg_meta_crypto_key=$(gen_base64 24)
logflare_public_access_token=$(gen_base64 24)
logflare_private_access_token=$(gen_base64 24)
s3_protocol_access_key_id=$(gen_hex 16)
s3_protocol_access_key_secret=$(gen_hex 32)
minio_root_password=$(gen_hex 16)
echo ""
echo "JWT_SECRET=${jwt_secret}"
echo ""
#echo "Issued at: $iat"
#echo "Expire: $exp"
echo "ANON_KEY=${anon_key}"
echo "SERVICE_ROLE_KEY=${service_role_key}"
echo ""
echo "SECRET_KEY_BASE=${secret_key_base}"
echo "VAULT_ENC_KEY=${vault_enc_key}"
echo "PG_META_CRYPTO_KEY=${pg_meta_crypto_key}"
echo "LOGFLARE_PUBLIC_ACCESS_TOKEN=${logflare_public_access_token}"
echo "LOGFLARE_PRIVATE_ACCESS_TOKEN=${logflare_private_access_token}"
echo "S3_PROTOCOL_ACCESS_KEY_ID=${s3_protocol_access_key_id}"
echo "S3_PROTOCOL_ACCESS_KEY_SECRET=${s3_protocol_access_key_secret}"
echo "MINIO_ROOT_PASSWORD=${minio_root_password}"
echo ""
postgres_password=$(gen_hex 16)
dashboard_password=$(gen_hex 16)
echo "POSTGRES_PASSWORD=${postgres_password}"
echo "DASHBOARD_PASSWORD=${dashboard_password}"
echo ""
if ! test -t 0; then
echo "Running non-interactively. Skipping .env update."
exit 0
fi
printf "Update .env file? (y/N) "
read -r REPLY
case "$REPLY" in
[Yy])
;;
*)
echo "Not updating .env"
exit 0
;;
esac
echo "Updating .env..."
sed \
-i.old \
-e "s|^JWT_SECRET=.*$|JWT_SECRET=${jwt_secret}|" \
-e "s|^ANON_KEY=.*$|ANON_KEY=${anon_key}|" \
-e "s|^SERVICE_ROLE_KEY=.*$|SERVICE_ROLE_KEY=${service_role_key}|" \
-e "s|^SECRET_KEY_BASE=.*$|SECRET_KEY_BASE=${secret_key_base}|" \
-e "s|^VAULT_ENC_KEY=.*$|VAULT_ENC_KEY=${vault_enc_key}|" \
-e "s|^PG_META_CRYPTO_KEY=.*$|PG_META_CRYPTO_KEY=${pg_meta_crypto_key}|" \
-e "s|^LOGFLARE_PUBLIC_ACCESS_TOKEN=.*$|LOGFLARE_PUBLIC_ACCESS_TOKEN=${logflare_public_access_token}|" \
-e "s|^LOGFLARE_PRIVATE_ACCESS_TOKEN=.*$|LOGFLARE_PRIVATE_ACCESS_TOKEN=${logflare_private_access_token}|" \
-e "s|^S3_PROTOCOL_ACCESS_KEY_ID=.*$|S3_PROTOCOL_ACCESS_KEY_ID=${s3_protocol_access_key_id}|" \
-e "s|^S3_PROTOCOL_ACCESS_KEY_SECRET=.*$|S3_PROTOCOL_ACCESS_KEY_SECRET=${s3_protocol_access_key_secret}|" \
-e "s|^MINIO_ROOT_PASSWORD=.*$|MINIO_ROOT_PASSWORD=${minio_root_password}|" \
-e "s|^POSTGRES_PASSWORD=.*$|POSTGRES_PASSWORD=${postgres_password}|" \
-e "s|^DASHBOARD_PASSWORD=.*$|DASHBOARD_PASSWORD=${dashboard_password}|" \
.env
-107
View File
@@ -1,107 +0,0 @@
# Docker Image Versions
## 2026-02-16
- supabase/studio:2026.02.16-sha-26c615c (prev supabase/studio:2026.01.27-sha-6aa59ff)
- supabase/gotrue:v2.186.0 (prev supabase/gotrue:v2.185.0)
- postgrest/postgrest:v14.5 (prev postgrest/postgrest:v14.3)
- supabase/realtime:v2.76.5 (prev supabase/realtime:v2.72.0)
- supabase/storage-api:v1.37.8 (prev supabase/storage-api:v1.37.1)
- supabase/edge-runtime:v1.70.3 (prev supabase/edge-runtime:v1.70.0)
- supabase/logflare:1.31.2 (prev supabase/logflare:1.30.3)
- timberio/vector:0.53.0-alpine (prev timberio/vector:0.28.1-alpine)
## 2026-02-05
- supabase/storage-api:v1.37.1 (prev supabase/storage-api:v1.33.5)
## 2026-01-27
- supabase/studio:2026.01.27-sha-6aa59ff (prev supabase/studio:2025.12.17-sha-43f4f7f)
- supabase/gotrue:v2.185.0 (prev supabase/gotrue:v2.184.0)
- postgrest/postgrest:v14.3 (prev postgrest/postgrest:v14.1)
- supabase/realtime:v2.72.0 (prev supabase/realtime:v2.68.0)
- supabase/storage-api:v1.33.5 (prev supabase/storage-api:v1.33.0)
- darthsim/imgproxy:v3.30.1 (prev darthsim/imgproxy:v3.8.0)
- supabase/postgres-meta:v0.95.2 (prev supabase/postgres-meta:v0.95.1)
- supabase/edge-runtime:v1.70.0 (prev supabase/edge-runtime:v1.69.28)
- supabase/logflare:1.30.3 (prev supabase/logflare:1.27.0)
## 2025-12-18
- supabase/studio:2025.12.17-sha-43f4f7f (prev supabase/studio:2025.12.09-sha-434634f)
- supabase/gotrue:v2.184.0 (prev supabase/gotrue:v2.183.0)
- supabase/postgres-meta:v0.95.1 (prev supabase/postgres-meta:v0.93.1)
- supabase/logflare:1.27.0 (prev supabase/logflare:1.26.25)
## 2025-12-10
- supabase/studio:2025.12.09-sha-434634f (prev supabase/studio:2025.11.26-sha-8f096b5)
- postgrest/postgrest:v14.1 (prev postgrest/postgrest:v13.0.7)
- supabase/realtime:v2.68.0 (prev supabase/realtime:v2.65.3)
- supabase/storage-api:v1.33.0 (prev supabase/storage-api:v1.32.0)
- supabase/edge-runtime:v1.69.28 (prev supabase/edge-runtime:v1.69.25)
- supabase/logflare:1.26.25 (prev supabase/logflare:1.26.13)
## 2025-11-26
- supabase/studio:2025.11.26-sha-8f096b5 (prev supabase/studio:2025.11.24-sha-d990ae8)
- supabase/realtime:v2.65.3 (prev supabase/realtime:v2.65.2)
- supabase/logflare:1.26.13 (prev supabase/logflare:1.26.12)
## 2025-11-25
- supabase/studio:2025.11.24-sha-d990ae8 (prev supabase/studio:2025.11.10-sha-5291fe3)
- supabase/gotrue:v2.183.0 (prev supabase/gotrue:v2.182.1)
- supabase/realtime:v2.65.2 (prev supabase/realtime:v2.63.0)
- supabase/storage-api:v1.32.0 (prev supabase/storage-api:v1.29.0)
- supabase/edge-runtime:v1.69.25 (prev supabase/edge-runtime:v1.69.23)
- supabase/logflare:1.26.12 (prev supabase/logflare:1.22.6)
## 2025-11-12
- supabase/studio:2025.11.10-sha-5291fe3 (prev 2025.10.27-sha-85b84e0)
- supabase/gotrue:v2.182.1 (prev v2.180.0)
- supabase/realtime:v2.63.0 (prev v2.57.2)
- supabase/storage-api:v1.29.0 (prev v1.28.2)
- supabase/edge-runtime:v1.69.23 (prev v1.69.15)
- supabase/supavisor:2.7.4 (prev 2.7.3)
## 2025-10-28
- supabase/studio:2025.10.27-sha-85b84e0 (prev 2025.10.20-sha-5005fc6)
- supabase/realtime:v2.57.2 (prev v2.56.0)
- supabase/storage-api:v1.28.2 (prev v1.28.1)
- supabase/postgres-meta:v0.93.1 (prev v0.93.0)
- supabase/edge-runtime:v1.69.15 (prev v1.69.14)
## 2025-10-21
- supabase/studio:2025.10.20-sha-5005fc6 (prev 2025.10.01-sha-8460121)
- supabase/realtime:v2.56.0 (prev v2.51.11)
- supabase/storage-api:v1.28.1 (prev v1.28.0)
- supabase/postgres-meta:v0.93.0 (prev v0.91.6)
- supabase/edge-runtime:v1.69.14 (prev v1.69.6)
- supabase/supavisor:2.7.3 (prev 2.7.0)
## 2025-10-13
- supabase/logflare:1.22.6 (prev 1.22.4)
## 2025-10-08
- supabase/studio:2025.10.01-sha-8460121 (prev 2025.06.30-sha-6f5982d)
- supabase/gotrue:v2.180.0 (prev v2.177.0)
- postgrest/postgrest:v13.0.7 (prev v12.2.12)
- supabase/realtime:v2.51.11 (prev v2.34.47)
- supabase/storage-api:v1.28.0 (prev v1.25.7)
- supabase/postgres-meta:v0.91.6 (prev v0.91.0)
- supabase/logflare:1.22.4 (prev 1.14.2)
- supabase/postgres:15.8.1.085 (prev 15.8.1.060)
- supabase/supavisor:2.7.0 (prev 2.5.7)
## 2025-07-15
- supabase/gotrue:v2.177.0 (prev v2.176.1)
- supabase/storage-api:v1.25.7 (prev v1.24.7)
- supabase/postgres-meta:v0.91.0 (prev v0.89.3)
- supabase/supavisor:2.5.7 (prev 2.5.6)
## 2025-07-02
- supabase/studio:2025.06.30-sha-6f5982d (prev 2025.06.02-sha-8f2993d)
- supabase/gotrue:v2.176.1 (prev v2.174.0)
- supabase/storage-api:v1.24.7 (prev v1.23.0)
- supabase/supavisor:2.5.6 (prev 2.5.1)
## 2025-06-03
- supabase/studio:2025.06.02-sha-8f2993d (prev 2025.05.19-sha-3487831)
- supabase/gotrue:v2.174.0 (prev v2.172.1)
- supabase/storage-api:v1.23.0 (prev v1.22.17)
- supabase/postgres-meta:v0.89.3 (prev v0.89.0)
+10 -67
View File
@@ -27,8 +27,8 @@ acls:
### ###
basicauth_credentials: basicauth_credentials:
- consumer: DASHBOARD - consumer: DASHBOARD
username: '$DASHBOARD_USERNAME' username: $DASHBOARD_USERNAME
password: '$DASHBOARD_PASSWORD' password: $DASHBOARD_PASSWORD
### ###
### API Routes ### API Routes
@@ -197,29 +197,14 @@ services:
- name: cors - name: cors
## Analytics routes ## Analytics routes
## Not used - Studio and Vector talk directly to analytics via Docker networking. - name: analytics-v1
## If external access is needed, add routes with key-auth matching Logflare's x-api-key auth. _comment: 'Analytics: /analytics/v1/* -> http://logflare:4000/*'
# - name: analytics-v1-api url: http://analytics:4000/
# _comment: 'Analytics: /analytics/v1/api/endpoints/* -> http://logflare:4000/api/endpoints/*' routes:
# url: http://analytics:4000/api/endpoints - name: analytics-v1-all
# routes: strip_path: true
# - name: analytics-v1-api paths:
# strip_path: true - /analytics/v1/
# paths:
# - /analytics/v1/api/endpoints/
# - name: analytics-v1
# _comment: 'Analytics: /analytics/v1/* -> http://logflare:4000/*'
# url: http://analytics:4000/
# routes:
# - name: dashboard-v1-all
# strip_path: true
# paths:
# - /analytics/v1
# plugins:
# - name: cors
# - name: basic-auth
# config:
# hide_credentials: true
## Secure Database routes ## Secure Database routes
- name: meta - name: meta
@@ -240,48 +225,6 @@ services:
allow: allow:
- admin - admin
## Block access to /api/mcp
- name: mcp-blocker
_comment: 'Block direct access to /api/mcp'
url: http://studio:3000/api/mcp
routes:
- name: mcp-blocker-route
strip_path: true
paths:
- /api/mcp
plugins:
- name: request-termination
config:
status_code: 403
message: "Access is forbidden."
## MCP endpoint - local access
- name: mcp
_comment: 'MCP: /mcp -> http://studio:3000/api/mcp (local access)'
url: http://studio:3000/api/mcp
routes:
- name: mcp
strip_path: true
paths:
- /mcp
plugins:
# Block access to /mcp by default
- name: request-termination
config:
status_code: 403
message: "Access is forbidden."
# Enable local access (danger zone!)
# 1. Comment out the 'request-termination' section above
# 2. Uncomment the entire section below, including 'deny'
# 3. Add your local IPs to the 'allow' list
#- name: cors
#- name: ip-restriction
# config:
# allow:
# - 127.0.0.1
# - ::1
# deny: []
## Protected Dashboard - catch all remaining routes ## Protected Dashboard - catch all remaining routes
- name: dashboard - name: dashboard
_comment: 'Studio: /* -> http://studio:3000/*' _comment: 'Studio: /* -> http://studio:3000/*'
@@ -2,7 +2,9 @@
// https://deno.land/manual/getting_started/setup_your_environment // https://deno.land/manual/getting_started/setup_your_environment
// This enables autocomplete, go to definition, etc. // This enables autocomplete, go to definition, etc.
Deno.serve(async () => { import { serve } from "https://deno.land/std@0.177.1/http/server.ts"
serve(async () => {
return new Response( return new Response(
`"Hello from Edge Functions!"`, `"Hello from Edge Functions!"`,
{ headers: { "Content-Type": "application/json" } }, { headers: { "Content-Type": "application/json" } },
@@ -1,3 +1,4 @@
import { serve } from 'https://deno.land/std@0.131.0/http/server.ts'
import * as jose from 'https://deno.land/x/jose@v4.14.4/index.ts' import * as jose from 'https://deno.land/x/jose@v4.14.4/index.ts'
console.log('main function started') console.log('main function started')
@@ -29,7 +30,7 @@ async function verifyJWT(jwt: string): Promise<boolean> {
return true return true
} }
Deno.serve(async (req: Request) => { serve(async (req: Request) => {
if (req.method !== 'OPTIONS' && VERIFY_JWT) { if (req.method !== 'OPTIONS' && VERIFY_JWT) {
try { try {
const token = getAuthToken(req) const token = getAuthToken(req)
+26 -62
View File
@@ -33,9 +33,9 @@ transforms:
kong: '.appname == "supabase-kong"' kong: '.appname == "supabase-kong"'
auth: '.appname == "supabase-auth"' auth: '.appname == "supabase-auth"'
rest: '.appname == "supabase-rest"' rest: '.appname == "supabase-rest"'
realtime: '.appname == "realtime-dev.supabase-realtime"' realtime: '.appname == "supabase-realtime"'
storage: '.appname == "supabase-storage"' storage: '.appname == "supabase-storage"'
functions: '.appname == "supabase-edge-functions"' functions: '.appname == "supabase-functions"'
db: '.appname == "supabase-db"' db: '.appname == "supabase-db"'
# Ignores non nginx errors since they are related with kong booting up # Ignores non nginx errors since they are related with kong booting up
kong_logs: kong_logs:
@@ -49,13 +49,10 @@ transforms:
.metadata.request.headers.referer = req.referer .metadata.request.headers.referer = req.referer
.metadata.request.headers.user_agent = req.agent .metadata.request.headers.user_agent = req.agent
.metadata.request.headers.cf_connecting_ip = req.client .metadata.request.headers.cf_connecting_ip = req.client
.metadata.request.method = req.method
.metadata.request.path = req.path
.metadata.request.protocol = req.protocol
.metadata.response.status_code = req.status .metadata.response.status_code = req.status
url, split_err = split(req.request, " ")
if split_err == null {
.metadata.request.method = url[0]
.metadata.request.path = url[1]
.metadata.request.protocol = url[2]
}
} }
if err != null { if err != null {
abort abort
@@ -104,20 +101,14 @@ transforms:
parsed, err = parse_regex(.event_message, r'^(?P<time>.*): (?P<msg>.*)$') parsed, err = parse_regex(.event_message, r'^(?P<time>.*): (?P<msg>.*)$')
if err == null { if err == null {
.event_message = parsed.msg .event_message = parsed.msg
.timestamp = parse_timestamp!(value: parsed.time,format: "%d/%b/%Y:%H:%M:%S %z") .timestamp = to_timestamp!(parsed.time)
.metadata.host = .project .metadata.host = .project
} }
# Filter out healthcheck logs from Realtime
realtime_logs_filtered:
type: filter
inputs:
- router.realtime
condition: '!contains(string!(.event_message), "/health")'
# Realtime logs are structured so we parse the severity level using regex (ignore time because it has no date) # Realtime logs are structured so we parse the severity level using regex (ignore time because it has no date)
realtime_logs: realtime_logs:
type: remap type: remap
inputs: inputs:
- realtime_logs_filtered - router.realtime
source: |- source: |-
.metadata.project = del(.project) .metadata.project = del(.project)
.metadata.external_id = .metadata.project .metadata.external_id = .metadata.project
@@ -126,13 +117,6 @@ transforms:
.event_message = parsed.msg .event_message = parsed.msg
.metadata.level = parsed.level .metadata.level = parsed.level
} }
# Function logs are unstructured messages on stderr
functions_logs:
type: remap
inputs:
- router.functions
source: |-
.metadata.project_ref = del(.project)
# Storage logs may contain json objects so we parse them for completeness # Storage logs may contain json objects so we parse them for completeness
storage_logs: storage_logs:
type: remap type: remap
@@ -163,7 +147,7 @@ transforms:
if err != null || parsed == null { if err != null || parsed == null {
.metadata.parsed.error_severity = "info" .metadata.parsed.error_severity = "info"
} }
if parsed.level != null { if parsed != null {
.metadata.parsed.error_severity = parsed.level .metadata.parsed.error_severity = parsed.level
} }
if .metadata.parsed.error_severity == "info" { if .metadata.parsed.error_severity == "info" {
@@ -180,11 +164,8 @@ sinks:
codec: 'json' codec: 'json'
method: 'post' method: 'post'
request: request:
retry_max_duration_secs: 30 retry_max_duration_secs: 10
retry_initial_backoff_secs: 1 uri: 'http://analytics:4000/api/logs?source_name=gotrue.logs.prod&api_key=${LOGFLARE_API_KEY?LOGFLARE_API_KEY is required}'
headers:
x-api-key: ${LOGFLARE_PUBLIC_ACCESS_TOKEN?LOGFLARE_PUBLIC_ACCESS_TOKEN is required}
uri: 'http://analytics:4000/api/logs?source_name=gotrue.logs.prod'
logflare_realtime: logflare_realtime:
type: 'http' type: 'http'
inputs: inputs:
@@ -193,11 +174,8 @@ sinks:
codec: 'json' codec: 'json'
method: 'post' method: 'post'
request: request:
retry_max_duration_secs: 30 retry_max_duration_secs: 10
retry_initial_backoff_secs: 1 uri: 'http://analytics:4000/api/logs?source_name=realtime.logs.prod&api_key=${LOGFLARE_API_KEY?LOGFLARE_API_KEY is required}'
headers:
x-api-key: ${LOGFLARE_PUBLIC_ACCESS_TOKEN?LOGFLARE_PUBLIC_ACCESS_TOKEN is required}
uri: 'http://analytics:4000/api/logs?source_name=realtime.logs.prod'
logflare_rest: logflare_rest:
type: 'http' type: 'http'
inputs: inputs:
@@ -206,11 +184,8 @@ sinks:
codec: 'json' codec: 'json'
method: 'post' method: 'post'
request: request:
retry_max_duration_secs: 30 retry_max_duration_secs: 10
retry_initial_backoff_secs: 1 uri: 'http://analytics:4000/api/logs?source_name=postgREST.logs.prod&api_key=${LOGFLARE_API_KEY?LOGFLARE_API_KEY is required}'
headers:
x-api-key: ${LOGFLARE_PUBLIC_ACCESS_TOKEN?LOGFLARE_PUBLIC_ACCESS_TOKEN is required}
uri: 'http://analytics:4000/api/logs?source_name=postgREST.logs.prod'
logflare_db: logflare_db:
type: 'http' type: 'http'
inputs: inputs:
@@ -219,26 +194,21 @@ sinks:
codec: 'json' codec: 'json'
method: 'post' method: 'post'
request: request:
retry_max_duration_secs: 30 retry_max_duration_secs: 10
retry_initial_backoff_secs: 1 # We must route the sink through kong because ingesting logs before logflare is fully initialised will
headers: # lead to broken queries from studio. This works by the assumption that containers are started in the
x-api-key: ${LOGFLARE_PUBLIC_ACCESS_TOKEN?LOGFLARE_PUBLIC_ACCESS_TOKEN is required} # following order: vector > db > logflare > kong
# Route directly to analytics like other sinks. Retry handles the startup uri: 'http://kong:8000/analytics/v1/api/logs?source_name=postgres.logs&api_key=${LOGFLARE_API_KEY?LOGFLARE_API_KEY is required}'
# race where analytics may not be ready yet when early DB logs arrive.
uri: 'http://analytics:4000/api/logs?source_name=postgres.logs'
logflare_functions: logflare_functions:
type: 'http' type: 'http'
inputs: inputs:
- functions_logs - router.functions
encoding: encoding:
codec: 'json' codec: 'json'
method: 'post' method: 'post'
request: request:
retry_max_duration_secs: 30 retry_max_duration_secs: 10
retry_initial_backoff_secs: 1 uri: 'http://analytics:4000/api/logs?source_name=deno-relay-logs&api_key=${LOGFLARE_API_KEY?LOGFLARE_API_KEY is required}'
headers:
x-api-key: ${LOGFLARE_PUBLIC_ACCESS_TOKEN?LOGFLARE_PUBLIC_ACCESS_TOKEN is required}
uri: 'http://analytics:4000/api/logs?source_name=deno-relay-logs'
logflare_storage: logflare_storage:
type: 'http' type: 'http'
inputs: inputs:
@@ -247,11 +217,8 @@ sinks:
codec: 'json' codec: 'json'
method: 'post' method: 'post'
request: request:
retry_max_duration_secs: 30 retry_max_duration_secs: 10
retry_initial_backoff_secs: 1 uri: 'http://analytics:4000/api/logs?source_name=storage.logs.prod.2&api_key=${LOGFLARE_API_KEY?LOGFLARE_API_KEY is required}'
headers:
x-api-key: ${LOGFLARE_PUBLIC_ACCESS_TOKEN?LOGFLARE_PUBLIC_ACCESS_TOKEN is required}
uri: 'http://analytics:4000/api/logs?source_name=storage.logs.prod.2'
logflare_kong: logflare_kong:
type: 'http' type: 'http'
inputs: inputs:
@@ -261,8 +228,5 @@ sinks:
codec: 'json' codec: 'json'
method: 'post' method: 'post'
request: request:
retry_max_duration_secs: 30 retry_max_duration_secs: 10
retry_initial_backoff_secs: 1 uri: 'http://analytics:4000/api/logs?source_name=cloudflare.logs.prod&api_key=${LOGFLARE_API_KEY?LOGFLARE_API_KEY is required}'
headers:
x-api-key: ${LOGFLARE_PUBLIC_ACCESS_TOKEN?LOGFLARE_PUBLIC_ACCESS_TOKEN is required}
uri: 'http://analytics:4000/api/logs?source_name=cloudflare.logs.prod'
@@ -1,36 +0,0 @@
{$PROXY_DOMAIN} {
@supabase_api path /auth/v1/* /rest/v1/* /graphql/v1/* /realtime/v1/* /functions/v1/* /mcp
handle @supabase_api {
reverse_proxy kong:8000
}
handle_path /storage/v1/* {
# CORS headers for Storage (bypasses Kong, which normally handles CORS)
@cors_preflight method OPTIONS
handle @cors_preflight {
header Access-Control-Allow-Origin *
header Access-Control-Allow-Methods "GET, HEAD, PUT, PATCH, POST, DELETE, OPTIONS"
header Access-Control-Allow-Headers *
respond 204
}
header Access-Control-Allow-Origin *
reverse_proxy storage:5000 {
# Required for TUS resumable upload Location headers and S3 signature verification.
header_up X-Forwarded-Prefix /{http.request.orig_uri.path.0}/{http.request.orig_uri.path.1}
}
}
handle {
basic_auth {
# PROXY_AUTH_PASSWORD is overwritten with the bcrypt on startup
{$PROXY_AUTH_USERNAME} {$PROXY_AUTH_PASSWORD}
}
reverse_proxy studio:3000
}
header -server
}
@@ -1,109 +0,0 @@
upstream kong_upstream {
server kong:8000;
keepalive 2;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name ${PROXY_DOMAIN};
server_tokens off;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Forwarded-Port $server_port;
ssl_certificate /etc/letsencrypt/live/${PROXY_DOMAIN}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/${PROXY_DOMAIN}/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/${PROXY_DOMAIN}/chain.pem;
ssl_dhparam /etc/letsencrypt/dhparams/dhparam.pem;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# Prevent 502 errors from large Supabase auth cookies
large_client_header_buffers 4 16k;
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
location / {
auth_basic "supabase";
auth_basic_user_file /etc/nginx/user_conf.d/dashboard-passwd;
proxy_pass http://studio:3000;
}
location /auth {
proxy_pass http://kong_upstream;
}
location /rest {
proxy_pass http://kong_upstream;
}
location /realtime/v1/ {
proxy_pass http://kong_upstream;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 3600s;
}
location /storage/v1/ {
proxy_pass http://storage:5000/;
proxy_buffering off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Forwarded-Port $server_port;
# Required for TUS resumable upload Location headers and S3 signature verification.
proxy_set_header X-Forwarded-Prefix /storage/v1;
client_max_body_size 0;
# CORS headers for Storage (bypasses Kong, which normally handles CORS)
if ($request_method = OPTIONS) {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, HEAD, PUT, PATCH, POST, DELETE, OPTIONS';
add_header 'Access-Control-Allow-Headers' '*';
add_header 'Content-Length' 0;
add_header 'Content-Type' 'text/plain charset=UTF-8';
return 204;
}
add_header 'Access-Control-Allow-Origin' '*';
}
location /functions {
proxy_pass http://kong_upstream;
}
location /graphql {
proxy_pass http://kong_upstream;
}
location /mcp {
proxy_pass http://kong_upstream;
}
}
+1 -7
View File
@@ -1,13 +1,7 @@
import utils from "../utils.js"; import utils from "../utils.js";
await utils.cloneOrPullRepo({ repo: "https://github.com/supabase/supabase", branch: "master" }); await utils.cloneOrPullRepo({ repo: "https://github.com/supabase/supabase" });
await utils.copyDir("./repo/docker", "./code"); await utils.copyDir("./repo/docker", "./code");
await utils.removeContainerNames("./code/docker-compose.yml"); await utils.removeContainerNames("./code/docker-compose.yml");
await utils.removePorts("./code/docker-compose.yml"); await utils.removePorts("./code/docker-compose.yml");
await utils.searchReplace(
"./code/.env.example",
"SITE_URL=http://localhost:3000",
"SITE_URL=https://$(PRIMARY_DOMAIN)"
);
+11
View File
@@ -0,0 +1,11 @@
#!/bin/bash
if [ ! -d "./repo" ]; then
git clone --depth 1 --branch master --single-branch https://github.com/supabase/supabase repo
else
cd repo
git pull
cd ..
fi
cp -r ./repo/docker/. ./code
+4
View File
@@ -0,0 +1,4 @@
# Twenty
- copied from https://github.com/twentyhq/twenty
- removed `ports`
+19
View File
@@ -0,0 +1,19 @@
TAG=latest
#PG_DATABASE_USER=postgres
#PG_DATABASE_PASSWORD=replace_me_with_a_strong_password_without_special_characters
#PG_DATABASE_HOST=db
#PG_DATABASE_PORT=5432
REDIS_URL=redis://redis:6379
SERVER_URL=https://$(PRIMARY_DOMAIN)
SIGN_IN_PREFILLED=false
# Use openssl rand -base64 32 for each secret
APP_SECRET=replace_me_with_a_random_string
STORAGE_TYPE=local
# STORAGE_S3_REGION=eu-west3
# STORAGE_S3_NAME=my-bucket
# STORAGE_S3_ENDPOINT=
+27
View File
@@ -0,0 +1,27 @@
# Makefile for building Twenty CRM docker images.
# Set the tag and/or target build platform using make command-line variables assignments.
#
# Optional make variables:
# PLATFORM - defaults to 'linux/amd64'
# TAG - defaults to 'latest'
#
# Example: make
# Example: make PLATFORM=linux/aarch64 TAG=my-tag
PLATFORM ?= linux/amd64
TAG ?= latest
prod-build:
@cd ../.. && docker build -f ./packages/twenty-docker/twenty/Dockerfile --platform $(PLATFORM) --tag twenty:$(TAG) . && cd -
prod-run:
@docker run -d -p 3000:3000 --name twenty twenty:$(TAG)
prod-postgres-run:
@docker run -d -p 5432:5432 -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres --name twenty-postgres twenty-postgres:$(TAG)
prod-website-build:
@cd ../.. && docker build -f ./packages/twenty-docker/twenty-website/Dockerfile --platform $(PLATFORM) --tag twenty-website:$(TAG) . && cd -
prod-website-run:
@docker run -d -p 3000:3000 --name twenty-website twenty-website:$(TAG)
+123
View File
@@ -0,0 +1,123 @@
name: twenty
services:
server:
image: twentycrm/twenty:${TAG:-latest}
volumes:
- server-local-data:/app/packages/twenty-server/.local-storage
environment:
NODE_PORT: 3000
PG_DATABASE_URL: postgres://${PG_DATABASE_USER:-postgres}:${PG_DATABASE_PASSWORD:-postgres}@${PG_DATABASE_HOST:-db}:${PG_DATABASE_PORT:-5432}/default
SERVER_URL: ${SERVER_URL}
REDIS_URL: ${REDIS_URL:-redis://redis:6379}
STORAGE_TYPE: ${STORAGE_TYPE}
STORAGE_S3_REGION: ${STORAGE_S3_REGION}
STORAGE_S3_NAME: ${STORAGE_S3_NAME}
STORAGE_S3_ENDPOINT: ${STORAGE_S3_ENDPOINT}
APP_SECRET: ${APP_SECRET:-replace_me_with_a_random_string}
# MESSAGING_PROVIDER_GMAIL_ENABLED: ${MESSAGING_PROVIDER_GMAIL_ENABLED}
# CALENDAR_PROVIDER_GOOGLE_ENABLED: ${CALENDAR_PROVIDER_GOOGLE_ENABLED}
# AUTH_GOOGLE_CLIENT_ID: ${AUTH_GOOGLE_CLIENT_ID}
# AUTH_GOOGLE_CLIENT_SECRET: ${AUTH_GOOGLE_CLIENT_SECRET}
# AUTH_GOOGLE_CALLBACK_URL: ${AUTH_GOOGLE_CALLBACK_URL}
# AUTH_GOOGLE_APIS_CALLBACK_URL: ${AUTH_GOOGLE_APIS_CALLBACK_URL}
# CALENDAR_PROVIDER_MICROSOFT_ENABLED: ${CALENDAR_PROVIDER_MICROSOFT_ENABLED}
# MESSAGING_PROVIDER_MICROSOFT_ENABLED: ${MESSAGING_PROVIDER_MICROSOFT_ENABLED}
# AUTH_MICROSOFT_ENABLED: ${AUTH_MICROSOFT_ENABLED}
# AUTH_MICROSOFT_CLIENT_ID: ${AUTH_MICROSOFT_CLIENT_ID}
# AUTH_MICROSOFT_CLIENT_SECRET: ${AUTH_MICROSOFT_CLIENT_SECRET}
# AUTH_MICROSOFT_CALLBACK_URL: ${AUTH_MICROSOFT_CALLBACK_URL}
# AUTH_MICROSOFT_APIS_CALLBACK_URL: ${AUTH_MICROSOFT_APIS_CALLBACK_URL}
# EMAIL_FROM_ADDRESS: ${EMAIL_FROM_ADDRESS:-contact@yourdomain.com}
# EMAIL_FROM_NAME: ${EMAIL_FROM_NAME:-"John from YourDomain"}
# EMAIL_SYSTEM_ADDRESS: ${EMAIL_SYSTEM_ADDRESS:-system@yourdomain.com}
# EMAIL_DRIVER: ${EMAIL_DRIVER:-smtp}
# EMAIL_SMTP_HOST: ${EMAIL_SMTP_HOST:-smtp.gmail.com}
# EMAIL_SMTP_PORT: ${EMAIL_SMTP_PORT:-465}
# EMAIL_SMTP_USER: ${EMAIL_SMTP_USER:-}
# EMAIL_SMTP_PASSWORD: ${EMAIL_SMTP_PASSWORD:-}
depends_on:
db:
condition: service_healthy
healthcheck:
test: curl --fail http://localhost:3000/healthz
interval: 5s
timeout: 5s
retries: 20
restart: always
worker:
image: twentycrm/twenty:${TAG:-latest}
volumes:
- server-local-data:/app/packages/twenty-server/${STORAGE_LOCAL_PATH:-.local-storage}
command: [ "yarn", "worker:prod" ]
environment:
PG_DATABASE_URL: postgres://${PG_DATABASE_USER:-postgres}:${PG_DATABASE_PASSWORD:-postgres}@${PG_DATABASE_HOST:-db}:${PG_DATABASE_PORT:-5432}/default
SERVER_URL: ${SERVER_URL}
REDIS_URL: ${REDIS_URL:-redis://redis:6379}
DISABLE_DB_MIGRATIONS: "true" # it already runs on the server
STORAGE_TYPE: ${STORAGE_TYPE}
STORAGE_S3_REGION: ${STORAGE_S3_REGION}
STORAGE_S3_NAME: ${STORAGE_S3_NAME}
STORAGE_S3_ENDPOINT: ${STORAGE_S3_ENDPOINT}
APP_SECRET: ${APP_SECRET:-replace_me_with_a_random_string}
# MESSAGING_PROVIDER_GMAIL_ENABLED: ${MESSAGING_PROVIDER_GMAIL_ENABLED}
# CALENDAR_PROVIDER_GOOGLE_ENABLED: ${CALENDAR_PROVIDER_GOOGLE_ENABLED}
# AUTH_GOOGLE_CLIENT_ID: ${AUTH_GOOGLE_CLIENT_ID}
# AUTH_GOOGLE_CLIENT_SECRET: ${AUTH_GOOGLE_CLIENT_SECRET}
# AUTH_GOOGLE_CALLBACK_URL: ${AUTH_GOOGLE_CALLBACK_URL}
# AUTH_GOOGLE_APIS_CALLBACK_URL: ${AUTH_GOOGLE_APIS_CALLBACK_URL}
# CALENDAR_PROVIDER_MICROSOFT_ENABLED: ${CALENDAR_PROVIDER_MICROSOFT_ENABLED}
# MESSAGING_PROVIDER_MICROSOFT_ENABLED: ${MESSAGING_PROVIDER_MICROSOFT_ENABLED}
# AUTH_MICROSOFT_ENABLED: ${AUTH_MICROSOFT_ENABLED}
# AUTH_MICROSOFT_CLIENT_ID: ${AUTH_MICROSOFT_CLIENT_ID}
# AUTH_MICROSOFT_CLIENT_SECRET: ${AUTH_MICROSOFT_CLIENT_SECRET}
# AUTH_MICROSOFT_CALLBACK_URL: ${AUTH_MICROSOFT_CALLBACK_URL}
# AUTH_MICROSOFT_APIS_CALLBACK_URL: ${AUTH_MICROSOFT_APIS_CALLBACK_URL}
# EMAIL_FROM_ADDRESS: ${EMAIL_FROM_ADDRESS:-contact@yourdomain.com}
# EMAIL_FROM_NAME: ${EMAIL_FROM_NAME:-"John from YourDomain"}
# EMAIL_SYSTEM_ADDRESS: ${EMAIL_SYSTEM_ADDRESS:-system@yourdomain.com}
# EMAIL_DRIVER: ${EMAIL_DRIVER:-smtp}
# EMAIL_SMTP_HOST: ${EMAIL_SMTP_HOST:-smtp.gmail.com}
# EMAIL_SMTP_PORT: ${EMAIL_SMTP_PORT:-465}
# EMAIL_SMTP_USER: ${EMAIL_SMTP_USER:-}
# EMAIL_SMTP_PASSWORD: ${EMAIL_SMTP_PASSWORD:-}
depends_on:
db:
condition: service_healthy
server:
condition: service_healthy
restart: always
db:
image: postgres:16
volumes:
- db-data:/var/lib/postgresql/data
environment:
POSTGRES_USER: ${PG_DATABASE_USER:-postgres}
POSTGRES_PASSWORD: ${PG_DATABASE_PASSWORD:-postgres}
healthcheck:
test: pg_isready -U ${PG_DATABASE_USER:-postgres} -h localhost -d postgres
interval: 5s
timeout: 5s
retries: 10
restart: always
redis:
image: redis
restart: always
command: [ "--maxmemory-policy", "noeviction" ]
volumes:
db-data:
server-local-data:
+116
View File
@@ -0,0 +1,116 @@
# README
DISCLAIMER: The k8s and podman deployments are not maintained by the core team.
These files are provided and maintained by the community. Twenty core team
maintains support for docker deployment.
## Overview
This repository contains Kubernetes manifests and Terraform files to help you deploy and manage the TwentyCRM application. The files are located in the `packages/twenty-docker/k8s` directory.
## Prerequisites
Before using these files, ensure you have the following installed and configured on your system:
- Kubernetes cluster (e.g., Minikube, EKS, GKE)
- kubectl
- Terraform
- Docker
## Setup Instructions
### Step 1: Clone the Repository
Clone the repository to your local machine:
``` bash
git clone https://github.com/twentyhq/twenty.git
cd twentycrm/packages/twenty-docker/k8s
```
### Step 2: Customize the Manifests and Terraform Files
**Important:** These files require customization for your specific implementation. Update the placeholders and configurations according to your environment and requirements.
### Step 3: Deploy with Terraform
1. Navigate to the Terraform directory:
```bash
cd terraform
```
2. Initialize Terraform:
```bash
terraform init
```
3. Plan the deployment:
```bash
terraform plan
```
4. Apply the deployment:
```bash
terraform apply
```
## OR
### Step 3: Deploy with Kubernetes Manifests
1. Navigate to the Kubernetes manifests directory:
```bash
cd ../k8s
```
2. Create Server Secret
``` bash
kubectl create secret generic -n twentycrm tokens --from-literal accessToken=changeme --from-literal loginToken="changeme" --from-literal refreshToken="changeme" --from-literal fileToken="changeme"
```
3. Apply the manifests:
```bash
kubectl apply -f .
```
## Customization
### Kubernetes Manifests
- **Namespace:** Update the `namespace` in the manifests as needed.
- **Resource Limits:** Adjust the resource limits and requests according to your application's requirements.
- **Environment Variables:** Configure server tokens in the `Secret` command above.
### Terraform Files
- **Variables:** Update the variables in the `variables.tf` file to match your environment.
- **Locals:** Update the locals in the `main.tf` file to match your environment.
- **Providers:** Ensure the provider configurations (e.g., AWS, GCP) are correct for your setup.
- **Resources:** Modify the resource definitions as needed to fit your infrastructure.
## Troubleshooting
### Common Issues
- **Connectivity:** Ensure your Kubernetes cluster is accessible and configured correctly.
- **Permissions:** Verify that you have the necessary permissions to deploy resources in your cloud provider.
- **Resource Limits:** Adjust resource limits if you encounter issues related to insufficient resources.
### Logs and Debugging
- Use `kubectl logs` to check the logs of your Kubernetes pods.
- Use `terraform show` and `terraform state` to inspect your Terraform state and configurations.
## Conclusion
This setup provides a basic structure for deploying the TwentyCRM application using Kubernetes and Terraform. Ensure you thoroughly customize the manifests and Terraform files to suit your specific needs. For any issues or questions, please refer to the official documentation of Kubernetes and Terraform or seek support from your cloud provider.
---
Feel free to contribute and improve this repository by submitting pull requests or opening issues. Happy deploying!
@@ -0,0 +1,58 @@
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: twentycrm-db
name: twentycrm-db
namespace: twentycrm
spec:
progressDeadlineSeconds: 600
replicas: 1
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
type: RollingUpdate
selector:
matchLabels:
app: twentycrm-db
template:
metadata:
labels:
app: twentycrm-db
spec:
volumes:
- name: twentycrm-db-data
persistentVolumeClaim:
claimName: twentycrm-db-pvc
containers:
- name: twentycrm
image: twentycrm/twenty-postgres-spilo:latest
imagePullPolicy: Always
env:
- name: PGUSER_SUPERUSER
value: "postgres"
- name: PGPASSWORD_SUPERUSER
value: "postgres"
- name: SPILO_PROVIDER
value: "local"
- name: ALLOW_NOSSL
value: "true"
ports:
- containerPort: 5432
name: tcp
protocol: TCP
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "1024Mi"
cpu: "1000m"
stdin: true
tty: true
volumeMounts:
- mountPath: /home/postgres/pgdata
name: twentycrm-db-data
dnsPolicy: ClusterFirst
restartPolicy: Always
@@ -0,0 +1,45 @@
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: twentycrm-redis
name: twentycrm-redis
namespace: twentycrm
spec:
progressDeadlineSeconds: 600
replicas: 1
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
type: RollingUpdate
selector:
matchLabels:
app: twentycrm-redis
template:
metadata:
labels:
app: twentycrm-redis
spec:
containers:
- name: redis
image: redis/redis-stack-server:latest
imagePullPolicy: Always
args: ["--maxmemory-policy", "noeviction"]
env:
- name: PORT
value: "6379"
ports:
- containerPort: 6379
name: redis
protocol: TCP
resources:
requests:
memory: "1024Mi"
cpu: "250m"
limits:
memory: "2048Mi"
cpu: "500m"
dnsPolicy: ClusterFirst
restartPolicy: Always
@@ -0,0 +1,76 @@
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: twentycrm-server
name: twentycrm-server
namespace: twentycrm
spec:
progressDeadlineSeconds: 600
replicas: 1
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
type: RollingUpdate
selector:
matchLabels:
app: twentycrm-server
template:
metadata:
labels:
app: twentycrm-server
spec:
volumes:
- name: twentycrm-server-data
persistentVolumeClaim:
claimName: twentycrm-server-pvc
- name: twentycrm-docker-data
persistentVolumeClaim:
claimName: twentycrm-docker-data-pvc
containers:
- name: twentycrm
image: twentycrm/twenty:latest
imagePullPolicy: Always
env:
- name: NODE_PORT
value: 3000
- name: SERVER_URL
value: "https://crm.example.com:443"
- name: "PG_DATABASE_URL"
value: "postgres://postgres:postgres@twentycrm-db.twentycrm.svc.cluster.local/default"
- name: "REDIS_URL"
value: "redis://twentycrm-redis.twentycrm.svc.cluster.local:6379"
- name: SIGN_IN_PREFILLED
value: "false"
- name: STORAGE_TYPE
value: "local"
- name: "ACCESS_TOKEN_EXPIRES_IN"
value: "7d"
- name: "LOGIN_TOKEN_EXPIRES_IN"
value: "1h"
- name: APP_SECRET
valueFrom:
secretKeyRef:
name: tokens
key: accessToken
ports:
- containerPort: 3000
name: http-tcp
protocol: TCP
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "1024Mi"
cpu: "1000m"
stdin: true
tty: true
volumeMounts:
- mountPath: /app/docker-data
name: twentycrm-docker-data
- mountPath: /app/packages/twenty-server/.local-storage
name: twentycrm-server-data
dnsPolicy: ClusterFirst
restartPolicy: Always
@@ -0,0 +1,57 @@
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: twentycrm-worker
name: twentycrm-worker
namespace: twentycrm
spec:
progressDeadlineSeconds: 600
replicas: 1
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
type: RollingUpdate
selector:
matchLabels:
app: twentycrm-worker
template:
metadata:
labels:
app: twentycrm-worker
spec:
containers:
- name: twentycrm
image: twentycrm/twenty:latest
imagePullPolicy: Always
env:
- name: SERVER_URL
value: "https://crm.example.com:443"
- name: PG_DATABASE_URL
value: "postgres://postgres:postgres@twentycrm-db.twentycrm.svc.cluster.local/default"
- name: DISABLE_DB_MIGRATIONS
value: "false" # it already runs on the server
- name: STORAGE_TYPE
value: "local"
- name: "REDIS_URL"
value: "redis://twentycrm-redis.twentycrm.svc.cluster.local:6379"
- name: APP_SECRET
valueFrom:
secretKeyRef:
name: tokens
key: accessToken
command:
- yarn
- worker:prod
resources:
requests:
memory: "1024Mi"
cpu: "250m"
limits:
memory: "2048Mi"
cpu: "1000m"
stdin: true
tty: true
dnsPolicy: ClusterFirst
restartPolicy: Always
+24
View File
@@ -0,0 +1,24 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: twentycrm
namespace: twentycrm
annotations:
nginx.ingress.kubernetes.io/configuration-snippet: |
more_set_headers "X-Forwarded-For $http_x_forwarded_for";
nginx.ingress.kubernetes.io/force-ssl-redirect: "false"
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
spec:
ingressClassName: nginx
rules:
- host: crm.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: twentycrm-server
port:
name: http-tcp
+11
View File
@@ -0,0 +1,11 @@
apiVersion: v1
kind: PersistentVolume
metadata:
name: twentycrm-db-pv
spec:
storageClassName: default
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
@@ -0,0 +1,11 @@
apiVersion: v1
kind: PersistentVolume
metadata:
name: twentycrm-docker-data-pv
spec:
storageClassName: default
capacity:
storage: 100Mi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
+12
View File
@@ -0,0 +1,12 @@
apiVersion: v1
kind: PersistentVolume
metadata:
name: twentycrm-server-pv
namespace: twentycrm
spec:
storageClassName: default
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
+13
View File
@@ -0,0 +1,13 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: twentycrm-db-pvc
namespace: twentycrm
spec:
storageClassName: default
volumeName: twentycrm-db-pv
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
@@ -0,0 +1,13 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: twentycrm-docker-data-pvc
namespace: twentycrm
spec:
storageClassName: default
volumeName: twentycrm-docker-data-pv
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 100Mi
+13
View File
@@ -0,0 +1,13 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: twentycrm-server-pvc
namespace: twentycrm
spec:
storageClassName: default
volumeName: twentycrm-server-pv
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
+18
View File
@@ -0,0 +1,18 @@
apiVersion: v1
kind: Service
metadata:
name: twentycrm-db
namespace: twentycrm
spec:
internalTrafficPolicy: Cluster
ports:
- port: 5432
protocol: TCP
targetPort: 5432
selector:
app: twentycrm-db
sessionAffinity: ClientIP
sessionAffinityConfig:
clientIP:
timeoutSeconds: 10800
type: ClusterIP
@@ -0,0 +1,18 @@
apiVersion: v1
kind: Service
metadata:
name: twentycrm-redis
namespace: twentycrm
spec:
internalTrafficPolicy: Cluster
ports:
- port: 6379
protocol: TCP
targetPort: 6379
selector:
app: twentycrm-redis
sessionAffinity: ClientIP
sessionAffinityConfig:
clientIP:
timeoutSeconds: 10800
type: ClusterIP
@@ -0,0 +1,19 @@
apiVersion: v1
kind: Service
metadata:
name: twentycrm-server
namespace: twentycrm
spec:
internalTrafficPolicy: Cluster
ports:
- name: http-tcp
port: 3000
protocol: TCP
targetPort: 3000
selector:
app: twentycrm-server
sessionAffinity: ClientIP
sessionAffinityConfig:
clientIP:
timeoutSeconds: 10800
type: ClusterIP
@@ -0,0 +1,48 @@
formatter: "markdown table" # this is required
version: ""
header-from: main.tf
recursive:
enabled: false
path: modules
output:
file: "README.md"
mode: inject
template: |-
<!-- BEGIN_TF_DOCS -->
# TwentyCRM Terraform Docs
This file was generated by [terraform-docs](https://terraform-docs.io/), for more information on how to install, configure, and use visit their website.
To update this `README.md` after changes to the Terraform code in this folder, run: `terraform-docs -c `./.terraform-docs.yml .`
To make configuration changes to how this doc is generated, see `./.terraform-docs.yml`
{{ .Content }}
<!-- END_TF_DOCS -->
output-values:
enabled: false
from: "outputs.tf"
sort:
enabled: true
by: required
settings:
anchor: true
color: true
default: true
description: true
escape: true
hide-empty: true
html: true
indent: 2
lockfile: true
read-comments: true
required: true
sensitive: true
type: true
+73
View File
@@ -0,0 +1,73 @@
<!-- BEGIN_TF_DOCS -->
# TwentyCRM Terraform Docs
This file was generated by [terraform-docs](https://terraform-docs.io/), for more information on how to install, configure, and use visit their website.
To update this `README.md` after changes to the Terraform code in this folder, run: `terraform-docs -c `./.terraform-docs.yml .`
To make configuration changes to how this doc is generated, see `./.terraform-docs.yml`
## Requirements
| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.9.2 |
| <a name="requirement_kubernetes"></a> [kubernetes](#requirement\_kubernetes) | >= 2.32.0 |
| <a name="requirement_random"></a> [random](#requirement\_random) | >= 3.6.3 |
## Providers
| Name | Version |
|------|---------|
| <a name="provider_kubernetes"></a> [kubernetes](#provider\_kubernetes) | >= 2.32.0 |
| <a name="provider_random"></a> [random](#provider\_random) | >= 3.6.3 |
## Resources
| Name | Type |
|------|------|
| [kubernetes_deployment.twentycrm_db](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/deployment) | resource |
| [kubernetes_deployment.twentycrm_redis](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/deployment) | resource |
| [kubernetes_deployment.twentycrm_server](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/deployment) | resource |
| [kubernetes_deployment.twentycrm_worker](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/deployment) | resource |
| [kubernetes_ingress.twentycrm](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/ingress) | resource |
| [kubernetes_namespace.twentycrm](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/namespace) | resource |
| [kubernetes_persistent_volume.db](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/persistent_volume) | resource |
| [kubernetes_persistent_volume.docker_data](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/persistent_volume) | resource |
| [kubernetes_persistent_volume.server](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/persistent_volume) | resource |
| [kubernetes_persistent_volume_claim.db](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/persistent_volume_claim) | resource |
| [kubernetes_persistent_volume_claim.docker_data](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/persistent_volume_claim) | resource |
| [kubernetes_persistent_volume_claim.server](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/persistent_volume_claim) | resource |
| [kubernetes_secret.twentycrm_tokens](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/secret) | resource |
| [kubernetes_service.twentycrm_db](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/service) | resource |
| [kubernetes_service.twentycrm_redis](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/service) | resource |
| [kubernetes_service.twentycrm_server](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/service) | resource |
| [random_bytes.this](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/bytes) | resource |
## Inputs
| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_twentycrm_app_hostname"></a> [twentycrm\_app\_hostname](#input\_twentycrm\_app\_hostname) | The protocol, DNS fully qualified hostname, and port used to access TwentyCRM in your environment. Ex: https://crm.example.com:443 | `string` | n/a | yes |
| <a name="input_twentycrm_pgdb_admin_password"></a> [twentycrm\_pgdb\_admin\_password](#input\_twentycrm\_pgdb\_admin\_password) | TwentyCRM password for postgres database. | `string` | n/a | yes |
| <a name="input_twentycrm_app_name"></a> [twentycrm\_app\_name](#input\_twentycrm\_app\_name) | A friendly name prefix to use for every component deployed. | `string` | `"twentycrm"` | no |
| <a name="input_twentycrm_db_image"></a> [twentycrm\_db\_image](#input\_twentycrm\_db\_image) | TwentyCRM image for database deployment. This defaults to latest. | `string` | `"twentycrm/twenty-postgres-spilo:latest"` | no |
| <a name="input_twentycrm_db_pv_capacity"></a> [twentycrm\_db\_pv\_capacity](#input\_twentycrm\_db\_pv\_capacity) | Storage capacity provisioned for database persistent volume. | `string` | `"10Gi"` | no |
| <a name="input_twentycrm_db_pv_path"></a> [twentycrm\_db\_pv\_path](#input\_twentycrm\_db\_pv\_path) | Local path to use to store the physical volume if using local storage on nodes. | `string` | `""` | no |
| <a name="input_twentycrm_db_pvc_requests"></a> [twentycrm\_db\_pvc\_requests](#input\_twentycrm\_db\_pvc\_requests) | Storage capacity reservation for database persistent volume claim. | `string` | `"10Gi"` | no |
| <a name="input_twentycrm_db_replicas"></a> [twentycrm\_db\_replicas](#input\_twentycrm\_db\_replicas) | Number of replicas for the TwentyCRM database deployment. This defaults to 1. | `number` | `1` | no |
| <a name="input_twentycrm_docker_data_mount_path"></a> [twentycrm\_docker\_data\_mount\_path](#input\_twentycrm\_docker\_data\_mount\_path) | TwentyCRM mount path for servers application data. Defaults to '/app/docker-data'. | `string` | `"/app/docker-data"` | no |
| <a name="input_twentycrm_docker_data_pv_capacity"></a> [twentycrm\_docker\_data\_pv\_capacity](#input\_twentycrm\_docker\_data\_pv\_capacity) | Storage capacity provisioned for server persistent volume. | `string` | `"10Gi"` | no |
| <a name="input_twentycrm_docker_data_pv_path"></a> [twentycrm\_docker\_data\_pv\_path](#input\_twentycrm\_docker\_data\_pv\_path) | Local path to use to store the physical volume if using local storage on nodes. | `string` | `""` | no |
| <a name="input_twentycrm_docker_data_pvc_requests"></a> [twentycrm\_docker\_data\_pvc\_requests](#input\_twentycrm\_docker\_data\_pvc\_requests) | Storage capacity reservation for server persistent volume claim. | `string` | `"10Gi"` | no |
| <a name="input_twentycrm_namespace"></a> [twentycrm\_namespace](#input\_twentycrm\_namespace) | Namespace for all TwentyCRM resources | `string` | `"twentycrm"` | no |
| <a name="input_twentycrm_redis_image"></a> [twentycrm\_redis\_image](#input\_twentycrm\_redis\_image) | TwentyCRM image for Redis deployment. This defaults to latest. | `string` | `"redis/redis-stack-server:latest"` | no |
| <a name="input_twentycrm_redis_replicas"></a> [twentycrm\_redis\_replicas](#input\_twentycrm\_redis\_replicas) | Number of replicas for the TwentyCRM Redis deployment. This defaults to 1. | `number` | `1` | no |
| <a name="input_twentycrm_server_data_mount_path"></a> [twentycrm\_server\_data\_mount\_path](#input\_twentycrm\_server\_data\_mount\_path) | TwentyCRM mount path for servers application data. Defaults to '/app/packages/twenty-server/.local-storage'. | `string` | `"/app/packages/twenty-server/.local-storage"` | no |
| <a name="input_twentycrm_server_image"></a> [twentycrm\_server\_image](#input\_twentycrm\_server\_image) | TwentyCRM server image for the server deployment. This defaults to latest. This value is also used for the workers image. | `string` | `"twentycrm/twenty:latest"` | no |
| <a name="input_twentycrm_server_pv_capacity"></a> [twentycrm\_server\_pv\_capacity](#input\_twentycrm\_server\_pv\_capacity) | Storage capacity provisioned for server persistent volume. | `string` | `"10Gi"` | no |
| <a name="input_twentycrm_server_pv_path"></a> [twentycrm\_server\_pv\_path](#input\_twentycrm\_server\_pv\_path) | Local path to use to store the physical volume if using local storage on nodes. | `string` | `""` | no |
| <a name="input_twentycrm_server_pvc_requests"></a> [twentycrm\_server\_pvc\_requests](#input\_twentycrm\_server\_pvc\_requests) | Storage capacity reservation for server persistent volume claim. | `string` | `"10Gi"` | no |
| <a name="input_twentycrm_server_replicas"></a> [twentycrm\_server\_replicas](#input\_twentycrm\_server\_replicas) | Number of replicas for the TwentyCRM server deployment. This defaults to 1. | `number` | `1` | no |
| <a name="input_twentycrm_worker_replicas"></a> [twentycrm\_worker\_replicas](#input\_twentycrm\_worker\_replicas) | Number of replicas for the TwentyCRM worker deployment. This defaults to 1. | `number` | `1` | no |
<!-- END_TF_DOCS -->
@@ -0,0 +1,87 @@
resource "kubernetes_deployment" "twentycrm_db" {
metadata {
name = "${var.twentycrm_app_name}-db"
namespace = kubernetes_namespace.twentycrm.metadata.0.name
labels = {
app = "${var.twentycrm_app_name}-db"
}
}
spec {
replicas = var.twentycrm_db_replicas
selector {
match_labels = {
app = "${var.twentycrm_app_name}-db"
}
}
strategy {
type = "RollingUpdate"
rolling_update {
max_surge = "1"
max_unavailable = "1"
}
}
template {
metadata {
labels = {
app = "${var.twentycrm_app_name}-db"
}
}
spec {
container {
image = var.twentycrm_db_image
name = var.twentycrm_app_name
stdin = true
tty = true
security_context {
allow_privilege_escalation = true
}
env {
name = "POSTGRES_PASSWORD"
value = var.twentycrm_pgdb_admin_password
}
env {
name = "BITNAMI_DEBUG"
value = true
}
port {
container_port = 5432
protocol = "TCP"
}
resources {
requests = {
cpu = "250m"
memory = "256Mi"
}
limits = {
cpu = "1000m"
memory = "1024Mi"
}
}
volume_mount {
name = "db-data"
mount_path = "/bitnami/postgresql"
}
}
volume {
name = "db-data"
persistent_volume_claim {
claim_name = kubernetes_persistent_volume_claim.db.metadata.0.name
}
}
dns_policy = "ClusterFirst"
restart_policy = "Always"
}
}
}
}
@@ -0,0 +1,60 @@
resource "kubernetes_deployment" "twentycrm_redis" {
metadata {
name = "${var.twentycrm_app_name}-redis"
namespace = kubernetes_namespace.twentycrm.metadata.0.name
labels = {
app = "${var.twentycrm_app_name}-redis"
}
}
spec {
replicas = var.twentycrm_redis_replicas
selector {
match_labels = {
app = "${var.twentycrm_app_name}-redis"
}
}
strategy {
type = "RollingUpdate"
rolling_update {
max_surge = "1"
max_unavailable = "1"
}
}
template {
metadata {
labels = {
app = "${var.twentycrm_app_name}-redis"
}
}
spec {
container {
image = var.twentycrm_redis_image
name = "redis"
port {
container_port = 6379
protocol = "TCP"
}
resources {
requests = {
cpu = "250m"
memory = "1024Mi"
}
limits = {
cpu = "500m"
memory = "2048Mi"
}
}
}
dns_policy = "ClusterFirst"
restart_policy = "Always"
}
}
}
}
@@ -0,0 +1,138 @@
resource "kubernetes_deployment" "twentycrm_server" {
metadata {
name = "${var.twentycrm_app_name}-server"
namespace = kubernetes_namespace.twentycrm.metadata.0.name
labels = {
app = "${var.twentycrm_app_name}-server"
}
}
spec {
replicas = var.twentycrm_server_replicas
selector {
match_labels = {
app = "${var.twentycrm_app_name}-server"
}
}
strategy {
type = "RollingUpdate"
rolling_update {
max_surge = "1"
max_unavailable = "1"
}
}
template {
metadata {
labels = {
app = "${var.twentycrm_app_name}-server"
}
}
spec {
container {
image = var.twentycrm_server_image
name = var.twentycrm_app_name
stdin = true
tty = true
env {
name = "NODE_PORT"
value = "3000"
}
env {
name = "SERVER_URL"
value = var.twentycrm_app_hostname
}
env {
name = "PG_DATABASE_URL"
value = "postgres://twenty:${var.twentycrm_pgdb_admin_password}@${kubernetes_service.twentycrm_db.metadata.0.name}.${kubernetes_namespace.twentycrm.metadata.0.name}.svc.cluster.local/default"
}
env {
name = "REDIS_URL"
value = "redis://${kubernetes_service.twentycrm_redis.metadata.0.name}.${kubernetes_namespace.twentycrm.metadata.0.name}.svc.cluster.local:6379"
}
env {
name = "DISABLE_DB_MIGRATIONS"
value = "false"
}
env {
name = "STORAGE_TYPE"
value = "local"
}
env {
name = "ACCESS_TOKEN_EXPIRES_IN"
value = "7d"
}
env {
name = "LOGIN_TOKEN_EXPIRES_IN"
value = "1h"
}
env {
name = "APP_SECRET"
value_from {
secret_key_ref {
name = "tokens"
key = "accessToken"
}
}
}
port {
container_port = 3000
protocol = "TCP"
}
resources {
requests = {
cpu = "250m"
memory = "256Mi"
}
limits = {
cpu = "1000m"
memory = "1024Mi"
}
}
volume_mount {
name = "server-data"
mount_path = var.twentycrm_server_data_mount_path
}
volume_mount {
name = "docker-data"
mount_path = var.twentycrm_docker_data_mount_path
}
}
volume {
name = "server-data"
persistent_volume_claim {
claim_name = kubernetes_persistent_volume_claim.server.metadata.0.name
}
}
volume {
name = "docker-data"
persistent_volume_claim {
claim_name = kubernetes_persistent_volume_claim.docker_data.metadata.0.name
}
}
dns_policy = "ClusterFirst"
restart_policy = "Always"
}
}
}
depends_on = [
kubernetes_deployment.twentycrm_db,
kubernetes_deployment.twentycrm_redis,
kubernetes_secret.twentycrm_tokens
]
}
@@ -0,0 +1,99 @@
resource "kubernetes_deployment" "twentycrm_worker" {
metadata {
name = "${var.twentycrm_app_name}-worker"
namespace = kubernetes_namespace.twentycrm.metadata.0.name
labels = {
app = "${var.twentycrm_app_name}-worker"
}
}
spec {
replicas = var.twentycrm_worker_replicas
selector {
match_labels = {
app = "${var.twentycrm_app_name}-worker"
}
}
strategy {
type = "RollingUpdate"
rolling_update {
max_surge = "1"
max_unavailable = "1"
}
}
template {
metadata {
labels = {
app = "${var.twentycrm_app_name}-worker"
}
}
spec {
container {
image = var.twentycrm_server_image
name = var.twentycrm_app_name
stdin = true
tty = true
command = ["yarn", "worker:prod"]
env {
name = "SERVER_URL"
value = var.twentycrm_app_hostname
}
env {
name = "PG_DATABASE_URL"
value = "postgres://twenty:${var.twentycrm_pgdb_admin_password}@${kubernetes_service.twentycrm_db.metadata.0.name}.${kubernetes_namespace.twentycrm.metadata.0.name}.svc.cluster.local/default"
}
env {
name = "REDIS_URL"
value = "redis://${kubernetes_service.twentycrm_redis.metadata.0.name}.${kubernetes_namespace.twentycrm.metadata.0.name}.svc.cluster.local:6379"
}
env {
name = "DISABLE_DB_MIGRATIONS"
value = "true" #it already runs on the server
}
env {
name = "STORAGE_TYPE"
value = "local"
}
env {
name = "APP_SECRET"
value_from {
secret_key_ref {
name = "tokens"
key = "accessToken"
}
}
}
resources {
requests = {
cpu = "250m"
memory = "1024Mi"
}
limits = {
cpu = "1000m"
memory = "2048Mi"
}
}
}
dns_policy = "ClusterFirst"
restart_policy = "Always"
}
}
}
depends_on = [
kubernetes_deployment.twentycrm_db,
kubernetes_deployment.twentycrm_redis,
kubernetes_deployment.twentycrm_server,
kubernetes_secret.twentycrm_tokens,
]
}
+30
View File
@@ -0,0 +1,30 @@
resource "kubernetes_ingress" "twentycrm" {
wait_for_load_balancer = true
metadata {
name = "${var.twentycrm_app_name}-ingress"
namespace = kubernetes_namespace.twentycrm.metadata.0.name
annotations = {
"kubernetes.io/ingress.class" = "nginx"
"nginx.ingress.kubernetes.io/configuration-snippet" = <<EOF
more_set_headers "X-Forwarded-For $http_x_forwarded_for";
EOF
"nginx.ingress.kubernetes.io/force-ssl-redirect" = "false"
"nginx.ingress.kubernetes.io/backend-protocol" = "HTTP"
}
}
spec {
ingress_class_name = "nginx"
rule {
host = var.twentycrm_app_hostname
http {
path {
path = "/*"
backend {
service_name = kubernetes_service.twentycrm_server.metadata.0.name
service_port = kubernetes_service.twentycrm_server.spec.0.port.0.port
}
}
}
}
}
}
+23
View File
@@ -0,0 +1,23 @@
#############
# Providers #
#############
provider "kubernetes" {
config_path = "~/.kube/config"
}
####################
# Terraform Config #
####################
terraform {
required_version = ">= 1.9.2"
required_providers {
kubernetes = {
source = "hashicorp/kubernetes"
version = ">= 2.32.0"
}
random = {
source = "hashicorp/random"
version = ">= 3.6.3"
}
}
}
+9
View File
@@ -0,0 +1,9 @@
resource "kubernetes_namespace" "twentycrm" {
metadata {
annotations = {
name = var.twentycrm_namespace
}
name = var.twentycrm_namespace
}
}
+19
View File
@@ -0,0 +1,19 @@
resource "kubernetes_persistent_volume" "db" {
metadata {
name = "${var.twentycrm_app_name}-db-pv"
}
spec {
storage_class_name = "default"
capacity = {
storage = var.twentycrm_db_pv_capacity
}
access_modes = ["ReadWriteOnce"]
# refer to Terraform Docs for your specific implementation requirements
# https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/persistent_volume
persistent_volume_source {
local {
path = var.twentycrm_db_pv_path
}
}
}
}
@@ -0,0 +1,19 @@
resource "kubernetes_persistent_volume" "docker_data" {
metadata {
name = "${var.twentycrm_app_name}-docker-data-pv"
}
spec {
storage_class_name = "default"
capacity = {
storage = var.twentycrm_docker_data_pv_capacity
}
access_modes = ["ReadWriteOnce"]
# refer to Terraform Docs for your specific implementation requirements
# https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/persistent_volume
persistent_volume_source {
local {
path = var.twentycrm_docker_data_pv_path
}
}
}
}
+19
View File
@@ -0,0 +1,19 @@
resource "kubernetes_persistent_volume" "server" {
metadata {
name = "${var.twentycrm_app_name}-server-pv"
}
spec {
storage_class_name = "default"
capacity = {
storage = var.twentycrm_server_pv_capacity
}
access_modes = ["ReadWriteOnce"]
# refer to Terraform Docs for your specific implementation requirements
# https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/persistent_volume
persistent_volume_source {
local {
path = var.twentycrm_server_pv_path
}
}
}
}
+15
View File
@@ -0,0 +1,15 @@
resource "kubernetes_persistent_volume_claim" "db" {
metadata {
name = "${var.twentycrm_app_name}-db-pvc"
namespace = kubernetes_namespace.twentycrm.metadata.0.name
}
spec {
access_modes = ["ReadWriteOnce"]
resources {
requests = {
storage = var.twentycrm_db_pvc_requests
}
}
volume_name = kubernetes_persistent_volume.db.metadata.0.name
}
}
@@ -0,0 +1,15 @@
resource "kubernetes_persistent_volume_claim" "docker_data" {
metadata {
name = "${var.twentycrm_app_name}-docker-data-pvc"
namespace = kubernetes_namespace.twentycrm.metadata.0.name
}
spec {
access_modes = ["ReadWriteOnce"]
resources {
requests = {
storage = var.twentycrm_docker_data_pvc_requests
}
}
volume_name = kubernetes_persistent_volume.docker_data.metadata.0.name
}
}
+15
View File
@@ -0,0 +1,15 @@
resource "kubernetes_persistent_volume_claim" "server" {
metadata {
name = "${var.twentycrm_app_name}-server-pvc"
namespace = kubernetes_namespace.twentycrm.metadata.0.name
}
spec {
access_modes = ["ReadWriteOnce"]
resources {
requests = {
storage = var.twentycrm_server_pvc_requests
}
}
volume_name = kubernetes_persistent_volume.server.metadata.0.name
}
}
+28
View File
@@ -0,0 +1,28 @@
locals {
tokens = [
"accessToken",
"loginToken",
"refreshToken",
"fileToken"
]
}
resource "random_bytes" "this" {
for_each = toset(local.tokens)
length = 32
}
resource "kubernetes_secret" "twentycrm_tokens" {
metadata {
name = "tokens"
namespace = kubernetes_namespace.twentycrm.metadata.0.name
}
data = {
accessToken = random_bytes.this["accessToken"].base64
loginToken = random_bytes.this["loginToken"].base64
refreshToken = random_bytes.this["refreshToken"].base64
fileToken = random_bytes.this["fileToken"].base64
}
}
+18
View File
@@ -0,0 +1,18 @@
resource "kubernetes_service" "twentycrm_db" {
metadata {
name = "${var.twentycrm_app_name}-db"
namespace = kubernetes_namespace.twentycrm.metadata.0.name
}
spec {
selector = {
app = "${var.twentycrm_app_name}-db"
}
session_affinity = "ClientIP"
port {
port = 5432
target_port = 5432
}
type = "ClusterIP"
}
}
@@ -0,0 +1,18 @@
resource "kubernetes_service" "twentycrm_redis" {
metadata {
name = "${var.twentycrm_app_name}-redis"
namespace = kubernetes_namespace.twentycrm.metadata.0.name
}
spec {
selector = {
app = "${var.twentycrm_app_name}-redis"
}
session_affinity = "ClientIP"
port {
port = 6379
target_port = 6379
}
type = "ClusterIP"
}
}
@@ -0,0 +1,19 @@
resource "kubernetes_service" "twentycrm_server" {
metadata {
name = "${var.twentycrm_app_name}-server"
namespace = kubernetes_namespace.twentycrm.metadata.0.name
}
spec {
selector = {
app = "${var.twentycrm_app_name}-server"
}
session_affinity = "ClientIP"
port {
name = "http-tcp"
port = 3000
target_port = 3000
}
type = "ClusterIP"
}
}
+136
View File
@@ -0,0 +1,136 @@
######################
# Required Variables #
######################
variable "twentycrm_pgdb_admin_password" {
type = string
description = "TwentyCRM password for postgres database."
sensitive = true
}
variable "twentycrm_app_hostname" {
type = string
description = "The protocol, DNS fully qualified hostname, and port used to access TwentyCRM in your environment. Ex: https://crm.example.com:443"
}
######################
# Optional Variables #
######################
variable "twentycrm_app_name" {
type = string
default = "twentycrm"
description = "A friendly name prefix to use for every component deployed."
}
variable "twentycrm_server_image" {
type = string
default = "twentycrm/twenty:latest"
description = "TwentyCRM server image for the server deployment. This defaults to latest. This value is also used for the workers image."
}
variable "twentycrm_db_image" {
type = string
default = "twentycrm/twenty-postgres-spilo:latest"
description = "TwentyCRM image for database deployment. This defaults to latest."
}
variable "twentycrm_server_replicas" {
type = number
default = 1
description = "Number of replicas for the TwentyCRM server deployment. This defaults to 1."
}
variable "twentycrm_worker_replicas" {
type = number
default = 1
description = "Number of replicas for the TwentyCRM worker deployment. This defaults to 1."
}
variable "twentycrm_db_replicas" {
type = number
default = 1
description = "Number of replicas for the TwentyCRM database deployment. This defaults to 1."
}
variable "twentycrm_server_data_mount_path" {
type = string
default = "/app/packages/twenty-server/.local-storage"
description = "TwentyCRM mount path for servers application data. Defaults to '/app/packages/twenty-server/.local-storage'."
}
variable "twentycrm_db_pv_path" {
type = string
default = ""
description = "Local path to use to store the physical volume if using local storage on nodes."
}
variable "twentycrm_server_pv_path" {
type = string
default = ""
description = "Local path to use to store the physical volume if using local storage on nodes."
}
variable "twentycrm_db_pv_capacity" {
type = string
default = "10Gi"
description = "Storage capacity provisioned for database persistent volume."
}
variable "twentycrm_db_pvc_requests" {
type = string
default = "10Gi"
description = "Storage capacity reservation for database persistent volume claim."
}
variable "twentycrm_server_pv_capacity" {
type = string
default = "10Gi"
description = "Storage capacity provisioned for server persistent volume."
}
variable "twentycrm_server_pvc_requests" {
type = string
default = "10Gi"
description = "Storage capacity reservation for server persistent volume claim."
}
variable "twentycrm_namespace" {
type = string
default = "twentycrm"
description = "Namespace for all TwentyCRM resources"
}
variable "twentycrm_redis_replicas" {
type = number
default = 1
description = "Number of replicas for the TwentyCRM Redis deployment. This defaults to 1."
}
variable "twentycrm_redis_image" {
type = string
default = "redis/redis-stack-server:latest"
description = "TwentyCRM image for Redis deployment. This defaults to latest."
}
variable "twentycrm_docker_data_mount_path" {
type = string
default = "/app/docker-data"
description = "TwentyCRM mount path for servers application data. Defaults to '/app/docker-data'."
}
variable "twentycrm_docker_data_pv_path" {
type = string
default = ""
description = "Local path to use to store the physical volume if using local storage on nodes."
}
variable "twentycrm_docker_data_pv_capacity" {
type = string
default = "100Mi"
description = "Storage capacity provisioned for server persistent volume."
}
variable "twentycrm_docker_data_pvc_requests" {
type = string
default = "100Mi"
description = "Storage capacity reservation for server persistent volume claim."
}
+48
View File
@@ -0,0 +1,48 @@
# How to deploy twenty on podman
DISCLAIMER: The k8s and podman deployments are not maintained by the core team.
These files are provided and maintained by the community. Twenty core team
maintains support for docker deployment.
## How to use
1. Edit `.env` file. At the minimum set `POSTGRES_PASSWORD`, `SERVER_URL`, and `APP_SECRET`.
2. Start twenty by running `podman-compose up -d`.
If you need to stop twenty, you can do so by running `podman-compose down`.
### Install systemd service (optional)
If you want to install a systemd service to run twenty, you can use the provided systemd service.
Edit `twentycrm.service` and change these two variables:
WorkingDirectory=/opt/apps/twenty
EnvironmentFile=/opt/apps/twenty/.env
`WorkingDirectory` should be changed to the path in which `podman-compose.yml` is located.
`EnvironmentFile` should be changed to the path in which your `.env`file is located.
You can run the script `install-systemd-user-service` to install the systemd service under the current user.
./install-systemd-user-service
Note: this script will enable the service and also start it. So it will assume that twenty is not currently running.
If you started it previously, bring it down using:
podman-compose down
## Compatibility
These files should be compatible with podman 4.3+.
I have tested this on Debian GNU/Linux 12 (bookworm) and with the podman that is distributed with the official Debian stable mirrors (podman v4.3.1+ds1-8+deb12u1, podman-compose v1.0.3-3).
+11
View File
@@ -0,0 +1,11 @@
#!/bin/bash
set -e
mkdir -p ~/.config/systemd/user
[ -f twentycrm.service ] || { echo "Error: twentycrm.service not found"; exit 1; }
cp twentycrm.service ~/.config/systemd/user
systemctl --user daemon-reload
systemctl --user enable twentycrm.service
systemctl --user start twentycrm.service

Some files were not shown because too many files have changed in this diff Show More