Compare commits

..

15 Commits

Author SHA1 Message Date
Isaac_Aracena f0b2fad63e Enable Google OAuth for Supabase Auth 2026-05-30 15:59:51 +00:00
Andrei Canta 0381268589 Merge pull request #65 from Ahson-Shaikh/19-01-2026
COMPOSE_TEMPLATE_UPDATES_2026
2026-01-20 12:37:35 +02:00
Ahson Shaikh 527c097c61 Updated Dify 2026-01-20 14:14:54 +05:00
Ahson Shaikh 61e436a151 Updated Appwrite 2026-01-20 14:06:39 +05:00
Ahson Shaikh 988bcb7223 Updated Supabase 2026-01-19 20:05:13 +05:00
Andrei Canta a0b5bb0c2a Merge pull request #64 from Ahson-Shaikh/29-12-2025
Plane Compose Template - Updated to v1.2.1
2025-12-30 17:45:24 +02:00
Ahson Shaikh 128651d310 Updated Dify & Appwrite 2025-12-30 20:30:42 +05:00
Ahson Shaikh 6f07307229 Updated Plane Template 2025-12-30 19:20:43 +05:00
Andrei Canta f32d48a271 Merge pull request #53 from Ahson-Shaikh/28-08-2025
Removed Twenty, Updated Plane
2025-08-28 20:08:04 +03:00
Ahson Shaikh c6b41076ea Updated Appwrite Env 2025-08-28 22:03:39 +05:00
Ahson Shaikh 854efbcff0 Removed Twenty, Updated Plane 2025-08-28 18:49:17 +05:00
Andrei Canta ee335fa22e remove secret key 2025-08-28 16:05:36 +03:00
Andrei Canta fa0b9127f1 run updates 2025-08-28 15:52:36 +03:00
Andrei Canta e0e7cbeeef update 2025-07-03 16:01:58 +03:00
Andrei Canta 405fd49534 update 2025-05-21 20:09:48 +03:00
109 changed files with 4011 additions and 3299 deletions
+24 -1
View File
@@ -3,11 +3,19 @@ _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=localhost _APP_DOMAIN=$(PRIMARY_DOMAIN)
_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=
@@ -27,6 +35,8 @@ _APP_USAGE_TIMESERIES_INTERVAL=30
_APP_USAGE_DATABASE_INTERVAL=900 _APP_USAGE_DATABASE_INTERVAL=900
_APP_WORKER_PER_CORE=6 _APP_WORKER_PER_CORE=6
_APP_CONSOLE_SESSION_ALERTS=disabled _APP_CONSOLE_SESSION_ALERTS=disabled
_APP_COMPRESSION_ENABLED=enabled
_APP_COMPRESSION_MIN_SIZE_BYTES=1024
_APP_REDIS_HOST=redis _APP_REDIS_HOST=redis
_APP_REDIS_PORT=6379 _APP_REDIS_PORT=6379
_APP_REDIS_USER= _APP_REDIS_USER=
@@ -58,6 +68,7 @@ _APP_STORAGE_S3_ACCESS_KEY=
_APP_STORAGE_S3_SECRET= _APP_STORAGE_S3_SECRET=
_APP_STORAGE_S3_REGION=us-east-1 _APP_STORAGE_S3_REGION=us-east-1
_APP_STORAGE_S3_BUCKET= _APP_STORAGE_S3_BUCKET=
_APP_STORAGE_S3_ENDPOINT=
_APP_STORAGE_DO_SPACES_ACCESS_KEY= _APP_STORAGE_DO_SPACES_ACCESS_KEY=
_APP_STORAGE_DO_SPACES_SECRET= _APP_STORAGE_DO_SPACES_SECRET=
_APP_STORAGE_DO_SPACES_REGION=us-east-1 _APP_STORAGE_DO_SPACES_REGION=us-east-1
@@ -75,27 +86,37 @@ _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=
@@ -104,9 +125,11 @@ _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
_APP_MAINTENANCE_RETENTION_AUDIT_CONSOLE=15778800
_APP_MAINTENANCE_RETENTION_ABUSE=86400 _APP_MAINTENANCE_RETENTION_ABUSE=86400
_APP_MAINTENANCE_RETENTION_USAGE_HOURLY=8640000 _APP_MAINTENANCE_RETENTION_USAGE_HOURLY=8640000
_APP_MAINTENANCE_RETENTION_SCHEDULES=86400 _APP_MAINTENANCE_RETENTION_SCHEDULES=86400
+131 -48
View File
@@ -28,7 +28,7 @@ services:
- appwrite - appwrite
appwrite: appwrite:
image: appwrite/appwrite:1.6.0 image: appwrite/appwrite:1.8.1
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
networks: networks:
@@ -49,10 +49,13 @@ 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
@@ -61,6 +64,7 @@ services:
- _APP_ENV - _APP_ENV
- _APP_WORKER_PER_CORE - _APP_WORKER_PER_CORE
- _APP_LOCALE - _APP_LOCALE
- _APP_COMPRESSION_MIN_SIZE_BYTES
- _APP_CONSOLE_WHITELIST_ROOT - _APP_CONSOLE_WHITELIST_ROOT
- _APP_CONSOLE_WHITELIST_EMAILS - _APP_CONSOLE_WHITELIST_EMAILS
- _APP_CONSOLE_SESSION_ALERTS - _APP_CONSOLE_SESSION_ALERTS
@@ -73,10 +77,14 @@ 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_FUNCTIONS_FORCE_HTTPS - _APP_OPTIONS_ROUTER_FORCE_HTTPS
- _APP_OPENSSL_KEY_V1 - _APP_OPENSSL_KEY_V1
- _APP_DOMAIN - _APP_DOMAIN
- _APP_DOMAIN_TARGET - _APP_DOMAIN_TARGET_CNAME
- _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
@@ -103,6 +111,7 @@ services:
- _APP_STORAGE_S3_SECRET - _APP_STORAGE_S3_SECRET
- _APP_STORAGE_S3_REGION - _APP_STORAGE_S3_REGION
- _APP_STORAGE_S3_BUCKET - _APP_STORAGE_S3_BUCKET
- _APP_STORAGE_S3_ENDPOINT
- _APP_STORAGE_DO_SPACES_ACCESS_KEY - _APP_STORAGE_DO_SPACES_ACCESS_KEY
- _APP_STORAGE_DO_SPACES_SECRET - _APP_STORAGE_DO_SPACES_SECRET
- _APP_STORAGE_DO_SPACES_REGION - _APP_STORAGE_DO_SPACES_REGION
@@ -119,21 +128,26 @@ 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_FUNCTIONS_SIZE_LIMIT - _APP_COMPUTE_SIZE_LIMIT
- _APP_FUNCTIONS_TIMEOUT - _APP_FUNCTIONS_TIMEOUT
- _APP_FUNCTIONS_BUILD_TIMEOUT - _APP_SITES_TIMEOUT
- _APP_FUNCTIONS_CPUS - _APP_COMPUTE_BUILD_TIMEOUT
- _APP_FUNCTIONS_MEMORY - _APP_COMPUTE_CPUS
- _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
- _APP_MAINTENANCE_RETENTION_AUDIT - _APP_MAINTENANCE_RETENTION_AUDIT
- _APP_MAINTENANCE_RETENTION_AUDIT_CONSOLE
- _APP_MAINTENANCE_RETENTION_USAGE_HOURLY - _APP_MAINTENANCE_RETENTION_USAGE_HOURLY
- _APP_MAINTENANCE_RETENTION_SCHEDULES - _APP_MAINTENANCE_RETENTION_SCHEDULES
- _APP_SMS_PROVIDER - _APP_SMS_PROVIDER
@@ -150,10 +164,9 @@ services:
- _APP_MIGRATIONS_FIREBASE_CLIENT_ID - _APP_MIGRATIONS_FIREBASE_CLIENT_ID
- _APP_MIGRATIONS_FIREBASE_CLIENT_SECRET - _APP_MIGRATIONS_FIREBASE_CLIENT_SECRET
- _APP_ASSISTANT_OPENAI_API_KEY - _APP_ASSISTANT_OPENAI_API_KEY
appwrite-console: appwrite-console:
<<: *x-logging <<: *x-logging
image: appwrite/console:5.0.12 image: appwrite/console:7.5.7
restart: unless-stopped restart: unless-stopped
networks: networks:
- appwrite - appwrite
@@ -173,7 +186,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.6.0 image: appwrite/appwrite:1.8.1
entrypoint: realtime entrypoint: realtime
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
@@ -215,7 +228,7 @@ services:
- _APP_LOGGING_CONFIG - _APP_LOGGING_CONFIG
appwrite-worker-audits: appwrite-worker-audits:
image: appwrite/appwrite:1.6.0 image: appwrite/appwrite:1.8.1
entrypoint: worker-audits entrypoint: worker-audits
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
@@ -240,7 +253,7 @@ services:
- _APP_LOGGING_CONFIG - _APP_LOGGING_CONFIG
appwrite-worker-webhooks: appwrite-worker-webhooks:
image: appwrite/appwrite:1.6.0 image: appwrite/appwrite:1.8.1
entrypoint: worker-webhooks entrypoint: worker-webhooks
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
@@ -267,7 +280,7 @@ services:
- _APP_LOGGING_CONFIG - _APP_LOGGING_CONFIG
appwrite-worker-deletes: appwrite-worker-deletes:
image: appwrite/appwrite:1.6.0 image: appwrite/appwrite:1.8.1
entrypoint: worker-deletes entrypoint: worker-deletes
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
@@ -280,6 +293,7 @@ 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:
@@ -300,6 +314,7 @@ services:
- _APP_STORAGE_S3_SECRET - _APP_STORAGE_S3_SECRET
- _APP_STORAGE_S3_REGION - _APP_STORAGE_S3_REGION
- _APP_STORAGE_S3_BUCKET - _APP_STORAGE_S3_BUCKET
- _APP_STORAGE_S3_ENDPOINT
- _APP_STORAGE_DO_SPACES_ACCESS_KEY - _APP_STORAGE_DO_SPACES_ACCESS_KEY
- _APP_STORAGE_DO_SPACES_SECRET - _APP_STORAGE_DO_SPACES_SECRET
- _APP_STORAGE_DO_SPACES_REGION - _APP_STORAGE_DO_SPACES_REGION
@@ -321,10 +336,13 @@ services:
- _APP_EXECUTOR_HOST - _APP_EXECUTOR_HOST
- _APP_MAINTENANCE_RETENTION_ABUSE - _APP_MAINTENANCE_RETENTION_ABUSE
- _APP_MAINTENANCE_RETENTION_AUDIT - _APP_MAINTENANCE_RETENTION_AUDIT
- _APP_MAINTENANCE_RETENTION_AUDIT_CONSOLE
- _APP_MAINTENANCE_RETENTION_EXECUTION - _APP_MAINTENANCE_RETENTION_EXECUTION
- _APP_SYSTEM_SECURITY_EMAIL_ADDRESS
- _APP_EMAIL_CERTIFICATES
appwrite-worker-databases: appwrite-worker-databases:
image: appwrite/appwrite:1.6.0 image: appwrite/appwrite:1.8.1
entrypoint: worker-databases entrypoint: worker-databases
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
@@ -349,7 +367,7 @@ services:
- _APP_LOGGING_CONFIG - _APP_LOGGING_CONFIG
appwrite-worker-builds: appwrite-worker-builds:
image: appwrite/appwrite:1.6.0 image: appwrite/appwrite:1.8.1
entrypoint: worker-builds entrypoint: worker-builds
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
@@ -360,7 +378,9 @@ 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
@@ -381,18 +401,20 @@ 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_FUNCTIONS_BUILD_TIMEOUT - _APP_SITES_TIMEOUT
- _APP_FUNCTIONS_CPUS - _APP_COMPUTE_BUILD_TIMEOUT
- _APP_FUNCTIONS_MEMORY - _APP_COMPUTE_CPUS
- _APP_FUNCTIONS_SIZE_LIMIT - _APP_COMPUTE_MEMORY
- _APP_COMPUTE_SIZE_LIMIT
- _APP_OPTIONS_FORCE_HTTPS - _APP_OPTIONS_FORCE_HTTPS
- _APP_OPTIONS_FUNCTIONS_FORCE_HTTPS - _APP_OPTIONS_ROUTER_FORCE_HTTPS
- _APP_DOMAIN - _APP_DOMAIN
- _APP_STORAGE_DEVICE - _APP_STORAGE_DEVICE
- _APP_STORAGE_S3_ACCESS_KEY - _APP_STORAGE_S3_ACCESS_KEY
- _APP_STORAGE_S3_SECRET - _APP_STORAGE_S3_SECRET
- _APP_STORAGE_S3_REGION - _APP_STORAGE_S3_REGION
- _APP_STORAGE_S3_BUCKET - _APP_STORAGE_S3_BUCKET
- _APP_STORAGE_S3_ENDPOINT
- _APP_STORAGE_DO_SPACES_ACCESS_KEY - _APP_STORAGE_DO_SPACES_ACCESS_KEY
- _APP_STORAGE_DO_SPACES_SECRET - _APP_STORAGE_DO_SPACES_SECRET
- _APP_STORAGE_DO_SPACES_REGION - _APP_STORAGE_DO_SPACES_REGION
@@ -409,9 +431,10 @@ 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.6.0 image: appwrite/appwrite:1.8.1
entrypoint: worker-certificates entrypoint: worker-certificates
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
@@ -428,7 +451,11 @@ services:
- _APP_WORKER_PER_CORE - _APP_WORKER_PER_CORE
- _APP_OPENSSL_KEY_V1 - _APP_OPENSSL_KEY_V1
- _APP_DOMAIN - _APP_DOMAIN
- _APP_DOMAIN_TARGET - _APP_DOMAIN_TARGET_CNAME
- _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
@@ -443,7 +470,7 @@ services:
- _APP_LOGGING_CONFIG - _APP_LOGGING_CONFIG
appwrite-worker-functions: appwrite-worker-functions:
image: appwrite/appwrite:1.6.0 image: appwrite/appwrite:1.8.1
entrypoint: worker-functions entrypoint: worker-functions
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
@@ -469,9 +496,10 @@ services:
- _APP_DB_USER - _APP_DB_USER
- _APP_DB_PASS - _APP_DB_PASS
- _APP_FUNCTIONS_TIMEOUT - _APP_FUNCTIONS_TIMEOUT
- _APP_FUNCTIONS_BUILD_TIMEOUT - _APP_SITES_TIMEOUT
- _APP_FUNCTIONS_CPUS - _APP_COMPUTE_BUILD_TIMEOUT
- _APP_FUNCTIONS_MEMORY - _APP_COMPUTE_CPUS
- _APP_COMPUTE_MEMORY
- _APP_EXECUTOR_SECRET - _APP_EXECUTOR_SECRET
- _APP_EXECUTOR_HOST - _APP_EXECUTOR_HOST
- _APP_USAGE_STATS - _APP_USAGE_STATS
@@ -480,7 +508,7 @@ services:
- _APP_LOGGING_CONFIG - _APP_LOGGING_CONFIG
appwrite-worker-mails: appwrite-worker-mails:
image: appwrite/appwrite:1.6.0 image: appwrite/appwrite:1.8.1
entrypoint: worker-mails entrypoint: worker-mails
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
@@ -509,9 +537,11 @@ services:
- _APP_SMTP_USERNAME - _APP_SMTP_USERNAME
- _APP_SMTP_PASSWORD - _APP_SMTP_PASSWORD
- _APP_LOGGING_CONFIG - _APP_LOGGING_CONFIG
- _APP_DOMAIN
- _APP_OPTIONS_FORCE_HTTPS
appwrite-worker-messaging: appwrite-worker-messaging:
image: appwrite/appwrite:1.6.0 image: appwrite/appwrite:1.8.1
entrypoint: worker-messaging entrypoint: worker-messaging
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
@@ -542,6 +572,7 @@ services:
- _APP_STORAGE_S3_SECRET - _APP_STORAGE_S3_SECRET
- _APP_STORAGE_S3_REGION - _APP_STORAGE_S3_REGION
- _APP_STORAGE_S3_BUCKET - _APP_STORAGE_S3_BUCKET
- _APP_STORAGE_S3_ENDPOINT
- _APP_STORAGE_DO_SPACES_ACCESS_KEY - _APP_STORAGE_DO_SPACES_ACCESS_KEY
- _APP_STORAGE_DO_SPACES_SECRET - _APP_STORAGE_DO_SPACES_SECRET
- _APP_STORAGE_DO_SPACES_REGION - _APP_STORAGE_DO_SPACES_REGION
@@ -560,12 +591,14 @@ services:
- _APP_STORAGE_WASABI_BUCKET - _APP_STORAGE_WASABI_BUCKET
appwrite-worker-migrations: appwrite-worker-migrations:
image: appwrite/appwrite:1.6.0 image: appwrite/appwrite:1.8.1
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:
@@ -573,7 +606,11 @@ services:
- _APP_WORKER_PER_CORE - _APP_WORKER_PER_CORE
- _APP_OPENSSL_KEY_V1 - _APP_OPENSSL_KEY_V1
- _APP_DOMAIN - _APP_DOMAIN
- _APP_DOMAIN_TARGET - _APP_DOMAIN_TARGET_CNAME
- _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
@@ -589,7 +626,7 @@ services:
- _APP_MIGRATIONS_FIREBASE_CLIENT_SECRET - _APP_MIGRATIONS_FIREBASE_CLIENT_SECRET
appwrite-task-maintenance: appwrite-task-maintenance:
image: appwrite/appwrite:1.6.0 image: appwrite/appwrite:1.8.1
entrypoint: maintenance entrypoint: maintenance
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
@@ -601,7 +638,11 @@ services:
- _APP_ENV - _APP_ENV
- _APP_WORKER_PER_CORE - _APP_WORKER_PER_CORE
- _APP_DOMAIN - _APP_DOMAIN
- _APP_DOMAIN_TARGET - _APP_DOMAIN_TARGET_CNAME
- _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
@@ -618,12 +659,13 @@ services:
- _APP_MAINTENANCE_RETENTION_CACHE - _APP_MAINTENANCE_RETENTION_CACHE
- _APP_MAINTENANCE_RETENTION_ABUSE - _APP_MAINTENANCE_RETENTION_ABUSE
- _APP_MAINTENANCE_RETENTION_AUDIT - _APP_MAINTENANCE_RETENTION_AUDIT
- _APP_MAINTENANCE_RETENTION_AUDIT_CONSOLE
- _APP_MAINTENANCE_RETENTION_USAGE_HOURLY - _APP_MAINTENANCE_RETENTION_USAGE_HOURLY
- _APP_MAINTENANCE_RETENTION_SCHEDULES - _APP_MAINTENANCE_RETENTION_SCHEDULES
appwrite-worker-usage: appwrite-task-stats-resources:
image: appwrite/appwrite:1.6.0 image: appwrite/appwrite:1.8.1
entrypoint: worker-usage entrypoint: stats-resources
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
networks: networks:
@@ -646,12 +688,41 @@ services:
- _APP_REDIS_PASS - _APP_REDIS_PASS
- _APP_USAGE_STATS - _APP_USAGE_STATS
- _APP_LOGGING_CONFIG - _APP_LOGGING_CONFIG
- _APP_USAGE_AGGREGATION_INTERVAL - _APP_DATABASE_SHARED_TABLES
- _APP_STATS_RESOURCES_INTERVAL
appwrite-worker-usage-dump: appwrite-worker-stats-resources:
image: appwrite/appwrite:1.6.0 image: appwrite/appwrite:1.8.1
entrypoint: worker-usage-dump entrypoint: worker-stats-resources
<<: *x-logging <<: *x-logging
restart: unless-stopped
networks:
- appwrite
depends_on:
- redis
- mariadb
environment:
- _APP_ENV
- _APP_WORKER_PER_CORE
- _APP_OPENSSL_KEY_V1
- _APP_DB_HOST
- _APP_DB_PORT
- _APP_DB_SCHEMA
- _APP_DB_USER
- _APP_DB_PASS
- _APP_REDIS_HOST
- _APP_REDIS_PORT
- _APP_REDIS_USER
- _APP_REDIS_PASS
- _APP_USAGE_STATS
- _APP_LOGGING_CONFIG
- _APP_STATS_RESOURCES_INTERVAL
appwrite-worker-stats-usage:
image: appwrite/appwrite:1.8.1
entrypoint: worker-stats-usage
<<: *x-logging
restart: unless-stopped
networks: networks:
- appwrite - appwrite
depends_on: depends_on:
@@ -675,7 +746,7 @@ services:
- _APP_USAGE_AGGREGATION_INTERVAL - _APP_USAGE_AGGREGATION_INTERVAL
appwrite-task-scheduler-functions: appwrite-task-scheduler-functions:
image: appwrite/appwrite:1.6.0 image: appwrite/appwrite:1.8.1
entrypoint: schedule-functions entrypoint: schedule-functions
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
@@ -699,7 +770,7 @@ services:
- _APP_DB_PASS - _APP_DB_PASS
appwrite-task-scheduler-executions: appwrite-task-scheduler-executions:
image: appwrite/appwrite:1.6.0 image: appwrite/appwrite:1.8.1
entrypoint: schedule-executions entrypoint: schedule-executions
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
@@ -723,7 +794,7 @@ services:
- _APP_DB_PASS - _APP_DB_PASS
appwrite-task-scheduler-messages: appwrite-task-scheduler-messages:
image: appwrite/appwrite:1.6.0 image: appwrite/appwrite:1.8.1
entrypoint: schedule-messages entrypoint: schedule-messages
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
@@ -747,7 +818,7 @@ services:
- _APP_DB_PASS - _APP_DB_PASS
appwrite-assistant: appwrite-assistant:
image: appwrite/assistant:0.4.0 image: appwrite/assistant:0.8.4
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
networks: networks:
@@ -755,12 +826,19 @@ 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.6.11 image: openruntimes/executor:0.7.22
networks: networks:
- appwrite - appwrite
- runtimes - runtimes
@@ -768,24 +846,27 @@ 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_FUNCTIONS_INACTIVE_THRESHOLD - OPR_EXECUTOR_INACTIVE_TRESHOLD=$_APP_COMPUTE_INACTIVE_THRESHOLD
- OPR_EXECUTOR_MAINTENANCE_INTERVAL=$_APP_FUNCTIONS_MAINTENANCE_INTERVAL - OPR_EXECUTOR_MAINTENANCE_INTERVAL=$_APP_COMPUTE_MAINTENANCE_INTERVAL
- OPR_EXECUTOR_NETWORK=$_APP_FUNCTIONS_RUNTIMES_NETWORK - OPR_EXECUTOR_NETWORK=$_APP_COMPUTE_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 - OPR_EXECUTOR_RUNTIMES=$_APP_FUNCTIONS_RUNTIMES,$_APP_SITES_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
- OPR_EXECUTOR_STORAGE_S3_SECRET=$_APP_STORAGE_S3_SECRET - OPR_EXECUTOR_STORAGE_S3_SECRET=$_APP_STORAGE_S3_SECRET
- OPR_EXECUTOR_STORAGE_S3_REGION=$_APP_STORAGE_S3_REGION - OPR_EXECUTOR_STORAGE_S3_REGION=$_APP_STORAGE_S3_REGION
- OPR_EXECUTOR_STORAGE_S3_BUCKET=$_APP_STORAGE_S3_BUCKET - OPR_EXECUTOR_STORAGE_S3_BUCKET=$_APP_STORAGE_S3_BUCKET
- OPR_EXECUTOR_STORAGE_S3_ENDPOINT=$_APP_STORAGE_S3_ENDPOINT
- OPR_EXECUTOR_STORAGE_DO_SPACES_ACCESS_KEY=$_APP_STORAGE_DO_SPACES_ACCESS_KEY - OPR_EXECUTOR_STORAGE_DO_SPACES_ACCESS_KEY=$_APP_STORAGE_DO_SPACES_ACCESS_KEY
- OPR_EXECUTOR_STORAGE_DO_SPACES_SECRET=$_APP_STORAGE_DO_SPACES_SECRET - OPR_EXECUTOR_STORAGE_DO_SPACES_SECRET=$_APP_STORAGE_DO_SPACES_SECRET
- OPR_EXECUTOR_STORAGE_DO_SPACES_REGION=$_APP_STORAGE_DO_SPACES_REGION - OPR_EXECUTOR_STORAGE_DO_SPACES_REGION=$_APP_STORAGE_DO_SPACES_REGION
@@ -852,7 +933,9 @@ 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,3 +11,9 @@ 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
@@ -1,14 +0,0 @@
#!/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
+606 -51
View File
File diff suppressed because it is too large Load Diff
+84 -19
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,21 +13,28 @@ 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.
- **Legacy Support**: Previous deployment files are now located in the `docker-legacy` directory and will no longer be maintained.
### 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.
2. **Environment Setup**: 1. **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.
3. **Running the Services**: - **Optional (Recommended for upgrades)**:
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.
This is especially useful when upgrading Dify or managing a large, customized `.env` file.
See the [Environment Variables Synchronization](#environment-variables-synchronization) section below.
1. **Running the Services**:
- Execute `docker compose up` from the `docker` directory to start the services. - Execute `docker compose up` from the `docker` directory to start the services.
- 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`. - 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`.
4. **SSL Certificate Setup**: 1. **SSL Certificate Setup**:
- Rrefer `docker/certbot/README.md` to set up SSL certificates using Certbot. - Refer `docker/certbot/README.md` to set up SSL certificates using Certbot.
1. **OpenTelemetry Collector Setup**:
- Change `ENABLE_OTEL` to `true` in `.env`.
- Configure `OTLP_BASE_ENDPOINT` properly.
### How to Deploy Middleware for Developing Dify ### How to Deploy Middleware for Developing Dify
@@ -35,17 +42,20 @@ Welcome to the new `docker` directory for deploying Dify using Docker Compose. T
- 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).
2. **Running Middleware Services**: 1. **Running Middleware Services**:
- Execute `docker-compose -f docker-compose.middleware.yaml up --env-file middleware.env -d` to start the middleware services. - 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.
> 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.
2. **Transfer Customizations**: 1. **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.
3. **Data Migration**: 1. **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`
@@ -54,43 +64,98 @@ For users migrating from the `docker-legacy` setup:
- **Vector Database Services**: Depending on the type of vector database used (`VECTOR_STORE`), users can set specific endpoints, ports, and authentication details. - **Vector Database Services**: Depending on the type of vector database used (`VECTOR_STORE`), users can set specific endpoints, ports, and authentication details.
- **Storage Services**: Depending on the storage type (`STORAGE_TYPE`), users can configure specific settings for S3, Azure Blob, Google Storage, etc. - **Storage Services**: Depending on the storage type (`STORAGE_TYPE`), users can configure specific settings for S3, Azure Blob, Google Storage, etc.
- **API and Web Services**: Users can define URLs and other settings that affect how the API and web frontends operate. - **API and Web Services**: Users can define URLs and other settings that affect how the API and web frontend operate.
#### Other notable variables #### Other notable 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: 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. - `CONSOLE_API_URL`, `SERVICE_API_URL`: URLs for different API services.
- `APP_WEB_URL`: Frontend application URL. - `APP_WEB_URL`: Frontend application URL.
- `FILES_URL`: Base URL for file downloads and previews. - `FILES_URL`: Base URL for file downloads and previews.
2. **Server Configuration**: 1. **Server Configuration**:
- `LOG_LEVEL`, `DEBUG`, `FLASK_DEBUG`: Logging and debug settings. - `LOG_LEVEL`, `DEBUG`, `FLASK_DEBUG`: Logging and debug settings.
- `SECRET_KEY`: A key for encrypting session cookies and other sensitive data. - `SECRET_KEY`: A key for encrypting session cookies and other sensitive data.
3. **Database Configuration**: 1. **Database Configuration**:
- `DB_USERNAME`, `DB_PASSWORD`, `DB_HOST`, `DB_PORT`, `DB_DATABASE`: PostgreSQL database credentials and connection details. - `DB_USERNAME`, `DB_PASSWORD`, `DB_HOST`, `DB_PORT`, `DB_DATABASE`: PostgreSQL database credentials and connection details.
4. **Redis Configuration**: 1. **Redis Configuration**:
- `REDIS_HOST`, `REDIS_PORT`, `REDIS_PASSWORD`: Redis server connection settings. - `REDIS_HOST`, `REDIS_PORT`, `REDIS_PASSWORD`: Redis server connection settings.
5. **Celery Configuration**: 1. **Celery Configuration**:
- `CELERY_BROKER_URL`: Configuration for Celery message broker. - `CELERY_BROKER_URL`: Configuration for Celery message broker.
6. **Storage Configuration**: 1. **Storage Configuration**:
- `STORAGE_TYPE`, `S3_BUCKET_NAME`, `AZURE_BLOB_ACCOUNT_NAME`: Settings for file storage options like local, S3, Azure Blob, etc. - `STORAGE_TYPE`, `S3_BUCKET_NAME`, `AZURE_BLOB_ACCOUNT_NAME`: Settings for file storage options like local, S3, Azure Blob, etc.
7. **Vector Database Configuration**: 1. **Vector Database Configuration**:
- `VECTOR_STORE`: Type of vector database (e.g., `weaviate`, `milvus`). - `VECTOR_STORE`: Type of vector database (e.g., `weaviate`, `milvus`).
- Specific settings for each vector store like `WEAVIATE_ENDPOINT`, `MILVUS_URI`. - Specific settings for each vector store like `WEAVIATE_ENDPOINT`, `MILVUS_URI`.
8. **CORS Configuration**: 1. **CORS Configuration**:
- `WEB_API_CORS_ALLOW_ORIGINS`, `CONSOLE_CORS_ALLOW_ORIGINS`: Settings for cross-origin resource sharing. - `WEB_API_CORS_ALLOW_ORIGINS`, `CONSOLE_CORS_ALLOW_ORIGINS`: Settings for cross-origin resource sharing.
9. **Other Service-Specific Environment Variables**: 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`. - 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
- **Continuous Improvement Phase**: We are actively seeking feedback from the community to refine and enhance the deployment process. As more users adopt this new method, we will continue to make improvements based on your experiences and suggestions. - **Continuous Improvement Phase**: We are actively seeking feedback from the community to refine and enhance the deployment process. As more users adopt this new method, we will continue to make improvements based on your experiences and suggestions.
+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
``` ```
2. Edit `.env` file and `docker compose --profile certbot up` again. 1. 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
@@ -0,0 +1,465 @@
#!/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
+398 -68
View File
@@ -1,8 +1,27 @@
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:0.15.3 image: langgenius/dify-api:1.11.4
restart: always restart: always
environment: environment:
# Use the shared environment variables. # Use the shared environment variables.
@@ -12,11 +31,28 @@ services:
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}
SENTRY_PROFILES_SAMPLE_RATE: ${API_SENTRY_PROFILES_SAMPLE_RATE:-1.0} SENTRY_PROFILES_SAMPLE_RATE: ${API_SENTRY_PROFILES_SAMPLE_RATE:-1.0}
PLUGIN_REMOTE_INSTALL_HOST: ${EXPOSE_PLUGIN_DEBUGGING_HOST:-localhost}
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:
- db init_permissions:
- redis 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
volumes: volumes:
# Mount the storage directory to the container, for storing user files. # Mount the storage directory to the container, for storing user files.
- ./volumes/app/storage:/app/api/storage - ./volumes/app/storage:/app/api/storage
@@ -25,14 +61,14 @@ services:
- default - default
# worker service # worker service
# The Celery worker for processing the queue. # The Celery worker for processing all queues (dataset, workflow, mail, etc.)
worker: worker:
image: langgenius/dify-api:0.15.3 image: langgenius/dify-api:1.11.4
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 the queue. # Startup mode, 'worker' starts the Celery worker for processing all queues.
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}
@@ -40,8 +76,22 @@ 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:
- db init_permissions:
- redis 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
volumes: volumes:
# Mount the storage directory to the container, for storing user files. # Mount the storage directory to the container, for storing user files.
- ./volumes/app/storage:/app/api/storage - ./volumes/app/storage:/app/api/storage
@@ -49,31 +99,76 @@ 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.11.4
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:0.15.3 image: langgenius/dify-web:1.11.4
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_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} PM2_INSTANCES: ${PM2_INSTANCES:-2}
LOOP_NODE_MAX_COUNT: ${LOOP_NODE_MAX_COUNT:-100}
MAX_TOOLS_NUM: ${MAX_TOOLS_NUM:-10}
MAX_PARALLEL_LIMIT: ${MAX_PARALLEL_LIMIT:-10}
MAX_ITERATIONS_NUM: ${MAX_ITERATIONS_NUM:-99}
MAX_TREE_DEPTH: ${MAX_TREE_DEPTH:-50}
ENABLE_WEBSITE_JINAREADER: ${ENABLE_WEBSITE_JINAREADER:-true}
ENABLE_WEBSITE_FIRECRAWL: ${ENABLE_WEBSITE_FIRECRAWL:-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:
PGUSER: ${PGUSER:-postgres} POSTGRES_USER: ${DB_USERNAME:-postgres}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-difyai123456} POSTGRES_PASSWORD: ${DB_PASSWORD:-difyai123456}
POSTGRES_DB: ${POSTGRES_DB:-dify} POSTGRES_DB: ${DB_DATABASE:-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}'
@@ -81,15 +176,55 @@ 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: [ 'CMD', 'pg_isready' ] test:
[
"CMD",
"pg_isready",
"-h",
"db_postgres",
"-U",
"${DB_USERNAME:-postgres}",
"-d",
"${DB_DATABASE:-dify}",
]
interval: 1s
timeout: 3s
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 interval: 1s
timeout: 3s timeout: 3s
retries: 30 retries: 30
ports:
- '${EXPOSE_DB_PORT:-5432}:5432'
# The redis cache. # The redis cache.
redis: redis:
@@ -103,11 +238,15 @@ 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: [ 'CMD', 'redis-cli', 'ping' ] test:
[
"CMD-SHELL",
"redis-cli -a ${REDIS_PASSWORD:-difyai123456} ping | grep -q PONG",
]
# The DifySandbox # The DifySandbox
sandbox: sandbox:
image: langgenius/dify-sandbox:0.2.10 image: langgenius/dify-sandbox:0.2.12
restart: always restart: always
environment: environment:
# The DifySandbox configurations # The DifySandbox configurations
@@ -120,16 +259,18 @@ services:
HTTP_PROXY: ${SANDBOX_HTTP_PROXY:-http://ssrf_proxy:3128} HTTP_PROXY: ${SANDBOX_HTTP_PROXY:-http://ssrf_proxy:3128}
HTTPS_PROXY: ${SANDBOX_HTTPS_PROXY:-http://ssrf_proxy:3128} HTTPS_PROXY: ${SANDBOX_HTTPS_PROXY:-http://ssrf_proxy:3128}
SANDBOX_PORT: ${SANDBOX_PORT:-8194} SANDBOX_PORT: ${SANDBOX_PORT:-8194}
PIP_MIRROR_URL: ${PIP_MIRROR_URL:-}
volumes: volumes:
- ./volumes/sandbox/dependencies:/dependencies - ./volumes/sandbox/dependencies:/dependencies
- ./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.0.2-local image: langgenius/dify-plugin-daemon:0.5.2-local
restart: always restart: always
environment: environment:
# Use the shared environment variables. # Use the shared environment variables.
@@ -140,27 +281,79 @@ services:
MAX_PLUGIN_PACKAGE_SIZE: ${PLUGIN_MAX_PACKAGE_SIZE:-52428800} MAX_PLUGIN_PACKAGE_SIZE: ${PLUGIN_MAX_PACKAGE_SIZE:-52428800}
PPROF_ENABLED: ${PLUGIN_PPROF_ENABLED:-false} PPROF_ENABLED: ${PLUGIN_PPROF_ENABLED:-false}
DIFY_INNER_API_URL: ${PLUGIN_DIFY_INNER_API_URL:-http://api:5001} DIFY_INNER_API_URL: ${PLUGIN_DIFY_INNER_API_URL:-http://api:5001}
DIFY_INNER_API_KEY: ${INNER_API_KEY_FOR_PLUGIN:-QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1} DIFY_INNER_API_KEY: ${PLUGIN_DIFY_INNER_API_KEY:-QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1}
PLUGIN_REMOTE_INSTALLING_HOST: ${PLUGIN_REMOTE_INSTALL_HOST:-0.0.0.0} PLUGIN_REMOTE_INSTALLING_HOST: ${PLUGIN_DEBUGGING_HOST:-0.0.0.0}
PLUGIN_REMOTE_INSTALLING_PORT: ${PLUGIN_REMOTE_INSTALL_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} FORCE_VERIFYING_SIGNATURE: ${FORCE_VERIFYING_SIGNATURE:-true}
PYTHON_ENV_INIT_TIMEOUT: ${PLUGIN_PYTHON_ENV_INIT_TIMEOUT:-120}
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:-}
PLUGIN_STORAGE_TYPE: ${PLUGIN_STORAGE_TYPE:-local}
PLUGIN_STORAGE_LOCAL_ROOT: ${PLUGIN_STORAGE_LOCAL_ROOT:-/app/storage}
PLUGIN_INSTALLED_PATH: ${PLUGIN_INSTALLED_PATH:-plugin}
PLUGIN_PACKAGE_CACHE_PATH: ${PLUGIN_PACKAGE_CACHE_PATH:-plugin_packages}
PLUGIN_MEDIA_CACHE_PATH: ${PLUGIN_MEDIA_CACHE_PATH:-assets}
PLUGIN_STORAGE_OSS_BUCKET: ${PLUGIN_STORAGE_OSS_BUCKET:-}
S3_USE_AWS_MANAGED_IAM: ${PLUGIN_S3_USE_AWS_MANAGED_IAM:-false}
S3_USE_AWS: ${PLUGIN_S3_USE_AWS:-false}
S3_ENDPOINT: ${PLUGIN_S3_ENDPOINT:-}
S3_USE_PATH_STYLE: ${PLUGIN_S3_USE_PATH_STYLE:-false}
AWS_ACCESS_KEY: ${PLUGIN_AWS_ACCESS_KEY:-}
AWS_SECRET_KEY: ${PLUGIN_AWS_SECRET_KEY:-}
AWS_REGION: ${PLUGIN_AWS_REGION:-}
AZURE_BLOB_STORAGE_CONNECTION_STRING: ${PLUGIN_AZURE_BLOB_STORAGE_CONNECTION_STRING:-}
AZURE_BLOB_STORAGE_CONTAINER_NAME: ${PLUGIN_AZURE_BLOB_STORAGE_CONTAINER_NAME:-}
TENCENT_COS_SECRET_KEY: ${PLUGIN_TENCENT_COS_SECRET_KEY:-}
TENCENT_COS_SECRET_ID: ${PLUGIN_TENCENT_COS_SECRET_ID:-}
TENCENT_COS_REGION: ${PLUGIN_TENCENT_COS_REGION:-}
ALIYUN_OSS_REGION: ${PLUGIN_ALIYUN_OSS_REGION:-}
ALIYUN_OSS_ENDPOINT: ${PLUGIN_ALIYUN_OSS_ENDPOINT:-}
ALIYUN_OSS_ACCESS_KEY_ID: ${PLUGIN_ALIYUN_OSS_ACCESS_KEY_ID:-}
ALIYUN_OSS_ACCESS_KEY_SECRET: ${PLUGIN_ALIYUN_OSS_ACCESS_KEY_SECRET:-}
ALIYUN_OSS_AUTH_VERSION: ${PLUGIN_ALIYUN_OSS_AUTH_VERSION:-v4}
ALIYUN_OSS_PATH: ${PLUGIN_ALIYUN_OSS_PATH:-}
VOLCENGINE_TOS_ENDPOINT: ${PLUGIN_VOLCENGINE_TOS_ENDPOINT:-}
VOLCENGINE_TOS_ACCESS_KEY: ${PLUGIN_VOLCENGINE_TOS_ACCESS_KEY:-}
VOLCENGINE_TOS_SECRET_KEY: ${PLUGIN_VOLCENGINE_TOS_SECRET_KEY:-}
VOLCENGINE_TOS_REGION: ${PLUGIN_VOLCENGINE_TOS_REGION:-}
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:
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
# ssrf_proxy server # ssrf_proxy server
# for more information, please refer to # for more information, please refer to
# https://docs.dify.ai/learn-more/faq/install-faq#id-18.-why-is-ssrf_proxy-needed # https://docs.dify.ai/learn-more/faq/install-faq#18-why-is-ssrf-proxy-needed%3F
ssrf_proxy: ssrf_proxy:
image: ubuntu/squid:latest image: ubuntu/squid:latest
restart: always restart: always
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: [ '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" ] 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",
]
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}
@@ -189,8 +382,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.
@@ -207,7 +400,12 @@ 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: [ '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" ] 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",
]
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}
@@ -217,9 +415,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.1 TLSv1.2 TLSv1.3} NGINX_SSL_PROTOCOLS: ${NGINX_SSL_PROTOCOLS:-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:-15M} NGINX_CLIENT_MAX_BODY_SIZE: ${NGINX_CLIENT_MAX_BODY_SIZE:-100M}
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}
@@ -229,14 +427,13 @@ 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.19.0 image: semitechnologies/weaviate:1.27.0
profiles: profiles:
- ''
- weaviate - weaviate
restart: always restart: always
volumes: volumes:
@@ -255,11 +452,73 @@ 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.7.3 image: langgenius/qdrant:v1.8.3
profiles: profiles:
- qdrant - qdrant
restart: always restart: always
@@ -295,7 +554,11 @@ services:
- ./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: [ "CMD-SHELL", "curl -s -f -u Administrator:password http://localhost:8091/pools/default/buckets | grep -q '\\[{' || exit 1" ] test:
[
"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
@@ -315,10 +578,39 @@ services:
POSTGRES_DB: ${PGVECTOR_POSTGRES_DB:-dify} POSTGRES_DB: ${PGVECTOR_POSTGRES_DB:-dify}
# postgres data directory # postgres data directory
PGDATA: ${PGVECTOR_PGDATA:-/var/lib/postgresql/data/pgdata} PGDATA: ${PGVECTOR_PGDATA:-/var/lib/postgresql/data/pgdata}
# pg_bigm module for full text search
PG_BIGM: ${PGVECTOR_PG_BIGM:-false}
PG_BIGM_VERSION: ${PGVECTOR_PG_BIGM_VERSION:-1.2-20240606}
volumes: volumes:
- ./volumes/pgvector/data:/var/lib/postgresql/data - ./volumes/pgvector/data:/var/lib/postgresql/data
- ./pgvector/docker-entrypoint.sh:/docker-entrypoint.sh
entrypoint: ["/docker-entrypoint.sh"]
healthcheck: healthcheck:
test: [ 'CMD', 'pg_isready' ] test: ["CMD", "pg_isready"]
interval: 1s
timeout: 3s
retries: 30
# get image from https://www.vastdata.com.cn/
vastbase:
image: vastdata/vastbase-vector
profiles:
- vastbase
restart: always
environment:
- VB_DBCOMPATIBILITY=PG
- VB_DB=dify
- VB_USERNAME=dify
- VB_PASSWORD=Difyai123456
ports:
- "5434:5432"
volumes:
- ./vastbase/lic:/home/vastbase/vastbase/lic
- ./vastbase/data:/home/vastbase/data
- ./vastbase/backup:/home/vastbase/backup
- ./vastbase/backup_log:/home/vastbase/backup_log
healthcheck:
test: ["CMD", "pg_isready"]
interval: 1s interval: 1s
timeout: 3s timeout: 3s
retries: 30 retries: 30
@@ -340,7 +632,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
@@ -358,22 +650,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}
# OceanBase vector database # InterSystems IRIS vector database
oceanbase: iris:
image: quay.io/oceanbase/oceanbase-ce:4.3.3.0-100000142024101215 image: containers.intersystems.com/intersystems/iris-community:2025.3
profiles: profiles:
- oceanbase - iris
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/oceanbase/data:/root/ob - ./volumes/iris:/opt/iris
- ./volumes/oceanbase/conf:/root/.obd/cluster - ./iris/iris-init.script:/iris-init.script
- ./volumes/oceanbase/init.d:/root/boot/init.d - ./iris/docker-entrypoint.sh:/custom-entrypoint.sh
entrypoint: ["/custom-entrypoint.sh"]
tty: true
environment: environment:
OB_MEMORY_LIMIT: ${OCEANBASE_MEMORY_LIMIT:-6G} TZ: ${IRIS_TIMEZONE:-UTC}
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'
# Oracle vector database # Oracle vector database
oracle: oracle:
@@ -405,7 +700,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
@@ -424,7 +719,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
@@ -433,10 +728,10 @@ services:
milvus-standalone: milvus-standalone:
container_name: milvus-standalone container_name: milvus-standalone
image: milvusdb/milvus:v2.5.0-beta image: milvusdb/milvus:v2.6.3
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}
@@ -444,7 +739,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
@@ -495,6 +790,28 @@ services:
depends_on: depends_on:
- opensearch - opensearch
# opengauss vector database.
opengauss:
image: opengauss/opengauss:7.0.0-RC1
profiles:
- opengauss
privileged: true
restart: always
environment:
GS_USERNAME: ${OPENGAUSS_USER:-postgres}
GS_PASSWORD: ${OPENGAUSS_PASSWORD:-Dify@123}
GS_PORT: ${OPENGAUSS_PORT:-6600}
GS_DB: ${OPENGAUSS_DATABASE:-dify}
volumes:
- ./volumes/opengauss/data:/var/lib/opengauss/data
healthcheck:
test: ["CMD-SHELL", "netstat -lntp | grep tcp6 > /dev/null 2>&1"]
interval: 10s
timeout: 10s
retries: 10
ports:
- ${OPENGAUSS_PORT:-6600}:${OPENGAUSS_PORT:-6600}
# MyScale vector database # MyScale vector database
myscale: myscale:
container_name: myscale container_name: myscale
@@ -510,6 +827,18 @@ 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:
@@ -529,18 +858,19 @@ 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: [ 'CMD', 'curl', '-s', 'http://localhost:9200/_cluster/health?pretty' ] test:
["CMD", "curl", "-s", "http://localhost:9200/_cluster/health?pretty"]
interval: 30s interval: 30s
timeout: 10s timeout: 10s
retries: 50 retries: 50
@@ -558,17 +888,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
+113 -15
View File
@@ -1,13 +1,16 @@
services: services:
# The postgres database. # The postgres database.
db: db_postgres:
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: ${POSTGRES_PASSWORD:-difyai123456} POSTGRES_PASSWORD: ${DB_PASSWORD:-difyai123456}
POSTGRES_DB: ${POSTGRES_DB:-dify} POSTGRES_DB: ${DB_DATABASE:-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}'
@@ -15,12 +18,57 @@ 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: [ "CMD", "pg_isready" ] test:
[
"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
@@ -29,6 +77,8 @@ services:
redis: redis:
image: redis:6-alpine image: redis:6-alpine
restart: always restart: always
env_file:
- ./middleware.env
environment: environment:
REDISCLI_AUTH: ${REDIS_PASSWORD:-difyai123456} REDISCLI_AUTH: ${REDIS_PASSWORD:-difyai123456}
volumes: volumes:
@@ -39,12 +89,18 @@ services:
ports: ports:
- "${EXPOSE_REDIS_PORT:-6379}:6379" - "${EXPOSE_REDIS_PORT:-6379}:6379"
healthcheck: healthcheck:
test: [ "CMD", "redis-cli", "ping" ] test:
[
"CMD-SHELL",
"redis-cli -a ${REDIS_PASSWORD:-difyai123456} ping | grep -q PONG",
]
# The DifySandbox # The DifySandbox
sandbox: sandbox:
image: langgenius/dify-sandbox:0.2.10 image: langgenius/dify-sandbox:0.2.12
restart: always restart: always
env_file:
- ./middleware.env
environment: environment:
# The DifySandbox configurations # The DifySandbox configurations
# Make sure you are changing this key for your deployment with a strong key. # Make sure you are changing this key for your deployment with a strong key.
@@ -56,6 +112,7 @@ services:
HTTP_PROXY: ${SANDBOX_HTTP_PROXY:-http://ssrf_proxy:3128} HTTP_PROXY: ${SANDBOX_HTTP_PROXY:-http://ssrf_proxy:3128}
HTTPS_PROXY: ${SANDBOX_HTTPS_PROXY:-http://ssrf_proxy:3128} HTTPS_PROXY: ${SANDBOX_HTTPS_PROXY:-http://ssrf_proxy:3128}
SANDBOX_PORT: ${SANDBOX_PORT:-8194} SANDBOX_PORT: ${SANDBOX_PORT:-8194}
PIP_MIRROR_URL: ${PIP_MIRROR_URL:-}
volumes: volumes:
- ./volumes/sandbox/dependencies:/dependencies - ./volumes/sandbox/dependencies:/dependencies
- ./volumes/sandbox/conf:/conf - ./volumes/sandbox/conf:/conf
@@ -66,14 +123,13 @@ services:
# plugin daemon # plugin daemon
plugin_daemon: plugin_daemon:
image: langgenius/dify-plugin-daemon:0.0.2-local image: langgenius/dify-plugin-daemon:0.5.2-local
restart: always restart: always
env_file:
- ./middleware.env
environment: environment:
# Use the shared environment variables. # Use the shared environment variables.
DB_HOST: ${DB_HOST:-db} LOG_OUTPUT_FORMAT: ${LOG_OUTPUT_FORMAT:-text}
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}
@@ -87,7 +143,40 @@ 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}
PLUGIN_MAX_EXECUTION_TIMEOUT: ${PLUGIN_MAX_EXECUTION_TIMEOUT:-600}
PIP_MIRROR_URL: ${PIP_MIRROR_URL:-}
PLUGIN_STORAGE_TYPE: ${PLUGIN_STORAGE_TYPE:-local}
PLUGIN_STORAGE_LOCAL_ROOT: ${PLUGIN_STORAGE_LOCAL_ROOT:-/app/storage}
PLUGIN_INSTALLED_PATH: ${PLUGIN_INSTALLED_PATH:-plugin}
PLUGIN_PACKAGE_CACHE_PATH: ${PLUGIN_PACKAGE_CACHE_PATH:-plugin_packages}
PLUGIN_MEDIA_CACHE_PATH: ${PLUGIN_MEDIA_CACHE_PATH:-assets}
PLUGIN_STORAGE_OSS_BUCKET: ${PLUGIN_STORAGE_OSS_BUCKET:-}
S3_USE_AWS: ${PLUGIN_S3_USE_AWS:-false}
S3_USE_AWS_MANAGED_IAM: ${PLUGIN_S3_USE_AWS_MANAGED_IAM:-false}
S3_ENDPOINT: ${PLUGIN_S3_ENDPOINT:-}
S3_USE_PATH_STYLE: ${PLUGIN_S3_USE_PATH_STYLE:-false}
AWS_ACCESS_KEY: ${PLUGIN_AWS_ACCESS_KEY:-}
AWS_SECRET_KEY: ${PLUGIN_AWS_SECRET_KEY:-}
AWS_REGION: ${PLUGIN_AWS_REGION:-}
AZURE_BLOB_STORAGE_CONNECTION_STRING: ${PLUGIN_AZURE_BLOB_STORAGE_CONNECTION_STRING:-}
AZURE_BLOB_STORAGE_CONTAINER_NAME: ${PLUGIN_AZURE_BLOB_STORAGE_CONTAINER_NAME:-}
TENCENT_COS_SECRET_KEY: ${PLUGIN_TENCENT_COS_SECRET_KEY:-}
TENCENT_COS_SECRET_ID: ${PLUGIN_TENCENT_COS_SECRET_ID:-}
TENCENT_COS_REGION: ${PLUGIN_TENCENT_COS_REGION:-}
ALIYUN_OSS_REGION: ${PLUGIN_ALIYUN_OSS_REGION:-}
ALIYUN_OSS_ENDPOINT: ${PLUGIN_ALIYUN_OSS_ENDPOINT:-}
ALIYUN_OSS_ACCESS_KEY_ID: ${PLUGIN_ALIYUN_OSS_ACCESS_KEY_ID:-}
ALIYUN_OSS_ACCESS_KEY_SECRET: ${PLUGIN_ALIYUN_OSS_ACCESS_KEY_SECRET:-}
ALIYUN_OSS_AUTH_VERSION: ${PLUGIN_ALIYUN_OSS_AUTH_VERSION:-v4}
ALIYUN_OSS_PATH: ${PLUGIN_ALIYUN_OSS_PATH:-}
VOLCENGINE_TOS_ENDPOINT: ${PLUGIN_VOLCENGINE_TOS_ENDPOINT:-}
VOLCENGINE_TOS_ACCESS_KEY: ${PLUGIN_VOLCENGINE_TOS_ACCESS_KEY:-}
VOLCENGINE_TOS_SECRET_KEY: ${PLUGIN_VOLCENGINE_TOS_SECRET_KEY:-}
VOLCENGINE_TOS_REGION: ${PLUGIN_VOLCENGINE_TOS_REGION:-}
THIRD_PARTY_SIGNATURE_VERIFICATION_ENABLED: true
THIRD_PARTY_SIGNATURE_VERIFICATION_PUBLIC_KEYS: /app/keys/publickey.pem
FORCE_VERIFYING_SIGNATURE: false
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}"
@@ -96,14 +185,21 @@ services:
# ssrf_proxy server # ssrf_proxy server
# for more information, please refer to # for more information, please refer to
# https://docs.dify.ai/learn-more/faq/install-faq#id-18.-why-is-ssrf_proxy-needed # https://docs.dify.ai/learn-more/faq/install-faq#18-why-is-ssrf-proxy-needed%3F
ssrf_proxy: ssrf_proxy:
image: ubuntu/squid:latest image: ubuntu/squid:latest
restart: always restart: always
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: [ "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" ] entrypoint:
[
"sh",
"-c",
"cp /docker-entrypoint-mount.sh /docker-entrypoint.sh && sed -i 's/\r$$//' /docker-entrypoint.sh && chmod +x /docker-entrypoint.sh && /docker-entrypoint.sh",
]
env_file:
- ./middleware.env
environment: 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}
@@ -120,7 +216,7 @@ services:
# The Weaviate vector store. # The Weaviate vector store.
weaviate: weaviate:
image: semitechnologies/weaviate:1.19.0 image: semitechnologies/weaviate:1.27.0
profiles: profiles:
- "" - ""
- weaviate - weaviate
@@ -143,8 +239,10 @@ 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.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 170 KiB

File diff suppressed because it is too large Load Diff
+38
View File
@@ -0,0 +1,38 @@
#!/bin/bash
set -e
# IRIS configuration flag file
IRIS_CONFIG_DONE="/opt/iris/.iris-configured"
# Function to configure IRIS
configure_iris() {
echo "Configuring IRIS for first-time setup..."
# Wait for IRIS to be fully started
sleep 5
# 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
@@ -0,0 +1,11 @@
// 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")
+129 -6
View File
@@ -1,11 +1,17 @@
# ------------------------------ # ------------------------------
# Environment Variables for db Service # Environment Variables for db Service
# ------------------------------ # ------------------------------
PGUSER=postgres # Database Configuration
# The password for the default postgres user. # Database type, supported values are `postgresql` and `mysql`
POSTGRES_PASSWORD=difyai123456 DB_TYPE=postgresql
# The name of the default postgres database. # For MySQL, only `root` user is supported for now
POSTGRES_DB=dify DB_USERNAME=postgres
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
@@ -40,6 +46,46 @@ 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
# ----------------------------- # -----------------------------
@@ -77,12 +123,21 @@ 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
@@ -109,9 +164,77 @@ 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://api:5001 PLUGIN_DIFY_INNER_API_URL=http://host.docker.internal:5001
MARKETPLACE_ENABLED=true 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
PLUGIN_PYTHON_ENV_INIT_TIMEOUT=120
PLUGIN_MAX_EXECUTION_TIMEOUT=600
# PIP_MIRROR_URL=https://pypi.tuna.tsinghua.edu.cn/simple
PIP_MIRROR_URL=
# https://github.com/langgenius/dify-plugin-daemon/blob/main/.env.example
# Plugin storage type, local aws_s3 tencent_cos azure_blob
PLUGIN_STORAGE_TYPE=local
PLUGIN_STORAGE_LOCAL_ROOT=/app/storage
PLUGIN_WORKING_PATH=/app/storage/cwd
PLUGIN_INSTALLED_PATH=plugin
PLUGIN_PACKAGE_CACHE_PATH=plugin_packages
PLUGIN_MEDIA_CACHE_PATH=assets
# Plugin oss bucket
PLUGIN_STORAGE_OSS_BUCKET=
# Plugin oss s3 credentials
PLUGIN_S3_USE_AWS_MANAGED_IAM=false
PLUGIN_S3_USE_AWS=false
PLUGIN_S3_ENDPOINT=
PLUGIN_S3_USE_PATH_STYLE=false
PLUGIN_AWS_ACCESS_KEY=
PLUGIN_AWS_SECRET_KEY=
PLUGIN_AWS_REGION=
# Plugin oss azure blob
PLUGIN_AZURE_BLOB_STORAGE_CONTAINER_NAME=
PLUGIN_AZURE_BLOB_STORAGE_CONNECTION_STRING=
# Plugin oss tencent cos
PLUGIN_TENCENT_COS_SECRET_KEY=
PLUGIN_TENCENT_COS_SECRET_ID=
PLUGIN_TENCENT_COS_REGION=
# Plugin oss aliyun oss
PLUGIN_ALIYUN_OSS_REGION=
PLUGIN_ALIYUN_OSS_ENDPOINT=
PLUGIN_ALIYUN_OSS_ACCESS_KEY_ID=
PLUGIN_ALIYUN_OSS_ACCESS_KEY_SECRET=
PLUGIN_ALIYUN_OSS_AUTH_VERSION=v4
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
+11 -1
View File
@@ -29,7 +29,7 @@ server {
include proxy.conf; include proxy.conf;
} }
location /e { location /e/ {
proxy_pass http://plugin_daemon:5002; proxy_pass http://plugin_daemon:5002;
proxy_set_header Dify-Hook-Url $scheme://$host$request_uri; proxy_set_header Dify-Hook-Url $scheme://$host$request_uri;
include proxy.conf; include proxy.conf;
@@ -40,6 +40,16 @@ 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}
+4 -1
View File
@@ -1,5 +1,7 @@
#!/bin/bash #!/bin/bash
HTTPS_CONFIG=''
if [ "${NGINX_HTTPS_ENABLED}" = "true" ]; then if [ "${NGINX_HTTPS_ENABLED}" = "true" ]; then
# Check if the certificate and key files for the specified domain exist # Check if the certificate and key files for the specified domain exist
if [ -n "${CERTBOT_DOMAIN}" ] && \ if [ -n "${CERTBOT_DOMAIN}" ] && \
@@ -20,6 +22,7 @@ if [ "${NGINX_HTTPS_ENABLED}" = "true" ]; then
# Substitute the HTTPS_CONFIG in the default.conf.template with content from https.conf.template # Substitute the HTTPS_CONFIG in the default.conf.template with content from https.conf.template
envsubst '${HTTPS_CONFIG}' < /etc/nginx/conf.d/default.conf.template > /etc/nginx/conf.d/default.conf envsubst '${HTTPS_CONFIG}' < /etc/nginx/conf.d/default.conf.template > /etc/nginx/conf.d/default.conf
fi fi
export HTTPS_CONFIG
if [ "${NGINX_ENABLE_CERTBOT_CHALLENGE}" = "true" ]; then if [ "${NGINX_ENABLE_CERTBOT_CHALLENGE}" = "true" ]; then
ACME_CHALLENGE_LOCATION='location /.well-known/acme-challenge/ { root /var/www/html; }' ACME_CHALLENGE_LOCATION='location /.well-known/acme-challenge/ { root /var/www/html; }'
@@ -33,7 +36,7 @@ env_vars=$(printenv | cut -d= -f1 | sed 's/^/$/g' | paste -sd, -)
envsubst "$env_vars" < /etc/nginx/nginx.conf.template > /etc/nginx/nginx.conf envsubst "$env_vars" < /etc/nginx/nginx.conf.template > /etc/nginx/nginx.conf
envsubst "$env_vars" < /etc/nginx/proxy.conf.template > /etc/nginx/proxy.conf envsubst "$env_vars" < /etc/nginx/proxy.conf.template > /etc/nginx/proxy.conf
envsubst < /etc/nginx/conf.d/default.conf.template > /etc/nginx/conf.d/default.conf envsubst "$env_vars" < /etc/nginx/conf.d/default.conf.template > /etc/nginx/conf.d/default.conf
# Start Nginx using the default entrypoint # Start Nginx using the default entrypoint
exec nginx -g 'daemon off;' exec nginx -g 'daemon off;'
+24
View File
@@ -0,0 +1,24 @@
#!/bin/bash
PG_MAJOR=16
if [ "${PG_BIGM}" = "true" ]; then
# install pg_bigm
apt-get update
apt-get install -y curl make gcc postgresql-server-dev-${PG_MAJOR}
curl -LO https://github.com/pgbigm/pg_bigm/archive/refs/tags/v${PG_BIGM_VERSION}.tar.gz
tar xf v${PG_BIGM_VERSION}.tar.gz
cd pg_bigm-${PG_BIGM_VERSION} || exit 1
make USE_PGXS=1 PG_CONFIG=/usr/bin/pg_config
make USE_PGXS=1 PG_CONFIG=/usr/bin/pg_config install
cd - || exit 1
rm -rf v${PG_BIGM_VERSION}.tar.gz pg_bigm-${PG_BIGM_VERSION}
# enable pg_bigm
sed -i -e 's/^#\s*shared_preload_libraries.*/shared_preload_libraries = '\''pg_bigm'\''/' /var/lib/postgresql/data/pgdata/postgresql.conf
fi
# Run the original entrypoint script
exec /usr/local/bin/docker-entrypoint.sh postgres
+54
View File
@@ -19,6 +19,8 @@ acl Safe_ports port 488 # gss-http
acl Safe_ports port 591 # filemaker acl Safe_ports port 591 # filemaker
acl Safe_ports port 777 # multiling http acl Safe_ports port 777 # multiling http
acl CONNECT method CONNECT acl CONNECT method CONNECT
acl allowed_domains dstdomain .marketplace.dify.ai
http_access allow allowed_domains
http_access deny !Safe_ports http_access deny !Safe_ports
http_access deny CONNECT !SSL_ports http_access deny CONNECT !SSL_ports
http_access allow localhost manager http_access allow localhost manager
@@ -49,3 +51,55 @@ http_port ${REVERSE_PROXY_PORT} accel vhost
cache_peer ${SANDBOX_HOST} parent ${SANDBOX_PORT} 0 no-query originserver cache_peer ${SANDBOX_HOST} parent ${SANDBOX_PORT} 0 no-query originserver
acl src_all src all acl src_all src all
http_access allow src_all http_access allow src_all
# Unless the option's size is increased, an error will occur when uploading more than two files.
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 -1
View File
@@ -5,6 +5,6 @@ create user dify identified by dify DEFAULT TABLESPACE users quota unlimited on
grant DB_DEVELOPER_ROLE to dify; grant DB_DEVELOPER_ROLE to dify;
BEGIN BEGIN
CTX_DDL.CREATE_PREFERENCE('my_chinese_vgram_lexer','CHINESE_VGRAM_LEXER'); CTX_DDL.CREATE_PREFERENCE('dify.world_lexer','WORLD_LEXER');
END; END;
/ /
+2 -1
View File
@@ -55,7 +55,8 @@ services:
- ./volumes/data:/data - ./volumes/data:/data
- ./volumes/logs:/logs - ./volumes/logs:/logs
command: command:
- --config=/tiflash.toml - server
- --config-file=/tiflash.toml
depends_on: depends_on:
- "tikv" - "tikv"
- "tidb" - "tidb"
+12
View File
@@ -4,3 +4,15 @@ 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
@@ -1,13 +0,0 @@
#!/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
+41 -3
View File
@@ -1,4 +1,42 @@
# Plane # Plane - Project Management Script
- copied from https://github.com/makeplane/plane This directory contains the Plane project management tool deployment for Easypanel.
- 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
+35 -7
View File
@@ -1,17 +1,20 @@
APP_DOMAIN=localhost APP_DOMAIN=$(PRIMARY_DOMAIN)
APP_RELEASE=stable APP_RELEASE=v1.2.1
WEB_REPLICAS=1 WEB_REPLICAS=1
SPACE_REPLICAS=1 SPACE_REPLICAS=1
ADMIN_REPLICAS=1 ADMIN_REPLICAS=1
API_REPLICAS=1 API_REPLICAS=1
WORKER_REPLICAS=1
BEAT_WORKER_REPLICAS=1
LIVE_REPLICAS=1
NGINX_PORT=80 LISTEN_HTTP_PORT=80
WEB_URL=http://${APP_DOMAIN} LISTEN_HTTPS_PORT=443
WEB_URL=https://$(PRIMARY_DOMAIN)
DEBUG=0 DEBUG=0
SENTRY_DSN= CORS_ALLOWED_ORIGINS=https://$(PRIMARY_DOMAIN)
SENTRY_ENVIRONMENT=production
CORS_ALLOWED_ORIGINS=http://${APP_DOMAIN}
API_BASE_URL=http://api:8000 API_BASE_URL=http://api:8000
#DB SETTINGS #DB SETTINGS
@@ -37,6 +40,19 @@ 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
@@ -55,3 +71,15 @@ GUNICORN_WORKERS=1
# UNCOMMENT `DOCKER_PLATFORM` IF YOU ARE ON `ARM64` AND DOCKER IMAGE IS NOT AVAILABLE FOR RESPECTIVE `APP_RELEASE` # UNCOMMENT `DOCKER_PLATFORM` IF YOU ARE ON `ARM64` AND DOCKER IMAGE IS NOT AVAILABLE FOR RESPECTIVE `APP_RELEASE`
# DOCKER_PLATFORM=linux/amd64 # DOCKER_PLATFORM=linux/amd64
# Force HTTPS for handling SSL Termination
MINIO_ENDPOINT_SSL=0
# API key rate limit
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
-483
View File
@@ -1,483 +0,0 @@
# 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 Stable Release
```
mkdir plane-selfhost
cd plane-selfhost
curl -fsSL -o setup.sh https://github.com/makeplane/plane/releases/latest/download/setup.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.
```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]: 1
```
For the 1st time setup, type "1" as action input.
This will create a create a folder `plane-app` or `plane-app-preview` (in case of preview deployment) 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.
---
### 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
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
In case you want to make changes to `.env` variables, we suggest you to stop the services before doing that.
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)
---
### Restarting the Server
In case you want to make changes to `.env` variables, without stopping the server or you noticed some abnormalies in services, you can restart the services with RESTART 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
```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)
---
### 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.
```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`
---
### 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.
```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
```
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
0) Back to Main Menu
Service:
```
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
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
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
@@ -1,30 +0,0 @@
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
+74 -57
View File
@@ -24,9 +24,15 @@ 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
NGINX_PORT: ${NGINX_PORT:-80} APP_DOMAIN: ${APP_DOMAIN:-localhost}
BUCKET_NAME: ${AWS_S3_BUCKET_NAME:-uploads}
FILE_SIZE_LIMIT: ${FILE_SIZE_LIMIT:-5242880} 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}
SITE_ADDRESS: ${SITE_ADDRESS:-:80}
x-mq-env: x-mq-env:
# RabbitMQ Settings # RabbitMQ Settings
@@ -40,82 +46,72 @@ 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}
DEBUG: ${DEBUG:-0} DEBUG: ${DEBUG:-0}
SENTRY_DSN: ${SENTRY_DSN}
SENTRY_ENVIRONMENT: ${SENTRY_ENVIRONMENT:-production}
CORS_ALLOWED_ORIGINS: ${CORS_ALLOWED_ORIGINS} CORS_ALLOWED_ORIGINS: ${CORS_ALLOWED_ORIGINS}
GUNICORN_WORKERS: 1 GUNICORN_WORKERS: 1
USE_MINIO: ${USE_MINIO:-1} USE_MINIO: ${USE_MINIO:-1}
DATABASE_URL: ${DATABASE_URL:-postgresql://plane:plane@plane-db/plane} DATABASE_URL: ${DATABASE_URL:-postgresql://plane:plane@plane-db/plane}
SECRET_KEY: ${SECRET_KEY:-60gp0byfz2dvffa45cxl20p1scy9xbpf6d8c5y0geejgkyp1b5} SECRET_KEY: ${SECRET_KEY:-60gp0byfz2dvffa45cxl20p1scy9xbpf6d8c5y0geejgkyp1b5}
ADMIN_BASE_URL: ${ADMIN_BASE_URL}
SPACE_BASE_URL: ${SPACE_BASE_URL}
APP_BASE_URL: ${APP_BASE_URL}
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}
MINIO_ENDPOINT_SSL: ${MINIO_ENDPOINT_SSL:-0}
LIVE_SERVER_SECRET_KEY: ${LIVE_SERVER_SECRET_KEY:-2FiJk1U2aiVPEQtzLehYGlTSnTnrs7LW}
services: services:
web: web:
image: ${DOCKERHUB_USER:-makeplane}/plane-frontend:${APP_RELEASE:-stable} image: artifacts.plane.so/makeplane/plane-frontend:${APP_RELEASE:-v1.2.1}
platform: ${DOCKER_PLATFORM:-}
pull_policy: if_not_present
restart: unless-stopped
command: node web/server.js web
deploy: deploy:
replicas: ${WEB_REPLICAS:-1} replicas: ${WEB_REPLICAS:-1}
restart_policy:
condition: any
depends_on: depends_on:
- api - api
- worker - worker
space: space:
image: ${DOCKERHUB_USER:-makeplane}/plane-space:${APP_RELEASE:-stable} image: artifacts.plane.so/makeplane/plane-space:${APP_RELEASE:-v1.2.1}
platform: ${DOCKER_PLATFORM:-}
pull_policy: if_not_present
restart: unless-stopped
command: node space/server.js space
deploy: deploy:
replicas: ${SPACE_REPLICAS:-1} replicas: ${SPACE_REPLICAS:-1}
restart_policy:
condition: any
depends_on: depends_on:
- api - api
- worker - worker
- web - web
admin: admin:
image: ${DOCKERHUB_USER:-makeplane}/plane-admin:${APP_RELEASE:-stable} image: artifacts.plane.so/makeplane/plane-admin:${APP_RELEASE:-v1.2.1}
platform: ${DOCKER_PLATFORM:-}
pull_policy: if_not_present
restart: unless-stopped
command: node admin/server.js admin
deploy: deploy:
replicas: ${ADMIN_REPLICAS:-1} replicas: ${ADMIN_REPLICAS:-1}
restart_policy:
condition: any
depends_on: depends_on:
- api - api
- web - web
live: live:
image: ${DOCKERHUB_USER:-makeplane}/plane-live:${APP_RELEASE:-stable} image: artifacts.plane.so/makeplane/plane-live:${APP_RELEASE:-v1.2.1}
platform: ${DOCKER_PLATFORM:-}
pull_policy: if_not_present
restart: unless-stopped
command: node live/dist/server.js live
environment: environment:
<<: [ *live-env ] <<: [ *live-env, *redis-env ]
deploy: deploy:
replicas: ${LIVE_REPLICAS:-1} replicas: ${LIVE_REPLICAS:-1}
restart_policy:
condition: any
depends_on: depends_on:
- api - api
- web - web
api: api:
image: ${DOCKERHUB_USER:-makeplane}/plane-backend:${APP_RELEASE:-stable} image: artifacts.plane.so/makeplane/plane-backend:${APP_RELEASE:-v1.2.1}
platform: ${DOCKER_PLATFORM:-}
pull_policy: if_not_present
restart: unless-stopped
command: ./bin/docker-entrypoint-api.sh command: ./bin/docker-entrypoint-api.sh
deploy: deploy:
replicas: ${API_REPLICAS:-1} replicas: ${API_REPLICAS:-1}
restart_policy:
condition: any
volumes: volumes:
- logs_api:/code/plane/logs - logs_api:/code/plane/logs
environment: environment:
@@ -126,11 +122,12 @@ services:
- plane-mq - plane-mq
worker: worker:
image: ${DOCKERHUB_USER:-makeplane}/plane-backend:${APP_RELEASE:-stable} image: artifacts.plane.so/makeplane/plane-backend:${APP_RELEASE:-v1.2.1}
platform: ${DOCKER_PLATFORM:-}
pull_policy: if_not_present
restart: unless-stopped
command: ./bin/docker-entrypoint-worker.sh command: ./bin/docker-entrypoint-worker.sh
deploy:
replicas: ${WORKER_REPLICAS:-1}
restart_policy:
condition: any
volumes: volumes:
- logs_worker:/code/plane/logs - logs_worker:/code/plane/logs
environment: environment:
@@ -142,11 +139,12 @@ services:
- plane-mq - plane-mq
beat-worker: beat-worker:
image: ${DOCKERHUB_USER:-makeplane}/plane-backend:${APP_RELEASE:-stable} image: artifacts.plane.so/makeplane/plane-backend:${APP_RELEASE:-v1.2.1}
platform: ${DOCKER_PLATFORM:-}
pull_policy: if_not_present
restart: unless-stopped
command: ./bin/docker-entrypoint-beat.sh command: ./bin/docker-entrypoint-beat.sh
deploy:
replicas: ${BEAT_WORKER_REPLICAS:-1}
restart_policy:
condition: any
volumes: volumes:
- logs_beat-worker:/code/plane/logs - logs_beat-worker:/code/plane/logs
environment: environment:
@@ -158,11 +156,12 @@ services:
- plane-mq - plane-mq
migrator: migrator:
image: ${DOCKERHUB_USER:-makeplane}/plane-backend:${APP_RELEASE:-stable} image: artifacts.plane.so/makeplane/plane-backend:${APP_RELEASE:-v1.2.1}
platform: ${DOCKER_PLATFORM:-}
pull_policy: if_not_present
restart: "no"
command: ./bin/docker-entrypoint-migrator.sh command: ./bin/docker-entrypoint-migrator.sh
deploy:
replicas: 1
restart_policy:
condition: on-failure
volumes: volumes:
- logs_migrator:/code/plane/logs - logs_migrator:/code/plane/logs
environment: environment:
@@ -171,36 +170,47 @@ services:
- plane-db - plane-db
- plane-redis - plane-redis
# Comment this if you already have a database running
plane-db: plane-db:
image: postgres:15.7-alpine image: postgres:15.7-alpine
pull_policy: if_not_present
restart: unless-stopped
command: postgres -c 'max_connections=1000' command: postgres -c 'max_connections=1000'
deploy:
replicas: 1
restart_policy:
condition: any
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.5-alpine image: valkey/valkey:7.2.11-alpine
pull_policy: if_not_present deploy:
restart: unless-stopped replicas: 1
restart_policy:
condition: any
volumes: volumes:
- redisdata:/data - redisdata:/data
plane-mq: plane-mq:
image: rabbitmq:3.13.6-management-alpine image: rabbitmq:3.13.6-management-alpine
restart: always deploy:
replicas: 1
restart_policy:
condition: any
environment: environment:
<<: *mq-env <<: *mq-env
volumes: volumes:
- rabbitmq_data:/var/lib/rabbitmq - rabbitmq_data:/var/lib/rabbitmq
# Comment this if you using any external s3 compatible storage
plane-minio: plane-minio:
image: minio/minio:latest image: minio/minio:latest
pull_policy: if_not_present
restart: unless-stopped
command: server /export --console-address ":9090" command: server /export --console-address ":9090"
deploy:
replicas: 1
restart_policy:
condition: any
environment: environment:
<<: *minio-env <<: *minio-env
volumes: volumes:
@@ -208,24 +218,31 @@ services:
# Comment this if you already have a reverse proxy running # Comment this if you already have a reverse proxy running
proxy: proxy:
image: ${DOCKERHUB_USER:-makeplane}/plane-proxy:${APP_RELEASE:-stable} image: artifacts.plane.so/makeplane/plane-proxy:${APP_RELEASE:-v1.2.1}
platform: ${DOCKER_PLATFORM:-} deploy:
pull_policy: if_not_present replicas: 1
restart: unless-stopped restart_policy:
condition: any
environment: environment:
<<: *proxy-env <<: *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:
redisdata: redisdata:
uploads: uploads:
logs_api: logs_api:
logs_worker: logs_worker:
logs_beat-worker: logs_beat-worker:
logs_migrator: logs_migrator:
rabbitmq_data: rabbitmq_data:
proxy_config:
proxy_data:
Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

-118
View File
@@ -1,118 +0,0 @@
#!/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
-121
View File
@@ -1,121 +0,0 @@
#!/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 volumes
volumes=$(docker volume ls -f "name=plane-app" --format "{{.Name}}" | grep -E "_pgdata|_redisdata|_uploads")
# 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 "_pgdata|_redisdata|_uploads")
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 "$@"
+64 -35
View File
@@ -2,14 +2,14 @@
BRANCH=${BRANCH:-master} BRANCH=${BRANCH:-master}
SCRIPT_DIR=$PWD SCRIPT_DIR=$PWD
SERVICE_FOLDER=plane-app SERVICE_FOLDER=plane-code
PLANE_INSTALL_DIR=$PWD/$SERVICE_FOLDER PLANE_INSTALL_DIR=$PWD/$SERVICE_FOLDER
export APP_RELEASE=stable export APP_RELEASE=stable
export DOCKERHUB_USER=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/deploy/selfhost" export FALLBACK_DOWNLOAD_URL="https://raw.githubusercontent.com/$GH_REPO/$BRANCH/deployments/cli/community"
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 -s https://api.github.com/repos/$GH_REPO/releases/latest | grep -o '"tag_name": "[^"]*"' | sed 's/"tag_name": "//;s/"//g') local latest_release=$(curl -fsSL 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/deploy/selfhost/build.yml" "$PLANE_TEMP_CODE_DIR/build.yml" cp "$PLANE_TEMP_CODE_DIR/deployments/cli/community/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 -H 'Cache-Control: no-cache, no-store' -s -w "HTTPSTATUS:%{http_code}" "$RELEASE_DOWNLOAD_URL/$APP_RELEASE/docker-compose.yml?$(date +%s)") 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)")
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 -H 'Cache-Control: no-cache, no-store' -s -w "HTTPSTATUS:%{http_code}" "$FALLBACK_DOWNLOAD_URL/docker-compose.yml?$(date +%s)") RESPONSE=$(curl -fsSL -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 -H 'Cache-Control: no-cache, no-store' -s -w "HTTPSTATUS:%{http_code}" "$RELEASE_DOWNLOAD_URL/$APP_RELEASE/variables.env?$(date +%s)") RESPONSE=$(curl -fsSL -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 -H 'Cache-Control: no-cache, no-store' -s -w "HTTPSTATUS:%{http_code}" "$FALLBACK_DOWNLOAD_URL/variables.env?$(date +%s)") RESPONSE=$(curl -fsSL -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://')
@@ -366,7 +366,7 @@ function startServices() {
local api_container_id=$(docker container ls -q -f "name=$SERVICE_FOLDER-api") local api_container_id=$(docker container ls -q -f "name=$SERVICE_FOLDER-api")
local idx2=0 local idx2=0
while ! docker logs $api_container_id 2>&1 | grep -m 1 -i "Application startup complete" | grep -q "."; while ! docker exec $api_container_id python3 -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/')" > /dev/null 2>&1;
do do
local message=">> Waiting for API Service to Start" local message=">> Waiting for API Service to Start"
local dots=$(printf '%*s' $idx2 | tr ' ' '.') local dots=$(printf '%*s' $idx2 | tr ' ' '.')
@@ -457,12 +457,13 @@ function viewLogs(){
echo " 8) Redis" echo " 8) Redis"
echo " 9) Postgres" echo " 9) Postgres"
echo " 10) Minio" echo " 10) Minio"
echo " 11) RabbitMQ"
echo " 0) Back to Main Menu" echo " 0) Back to Main Menu"
echo echo
read -p "Service: " DOCKER_SERVICE_NAME read -p "Service: " DOCKER_SERVICE_NAME
until (( DOCKER_SERVICE_NAME >= 0 && DOCKER_SERVICE_NAME <= 10 )); do until (( DOCKER_SERVICE_NAME >= 0 && DOCKER_SERVICE_NAME <= 11 )); do
echo "Invalid selection. Please enter a number between 1 and 11." echo "Invalid selection. Please enter a number between 0 and 11."
read -p "Service: " DOCKER_SERVICE_NAME read -p "Service: " DOCKER_SERVICE_NAME
done done
@@ -481,6 +482,7 @@ function viewLogs(){
8) viewSpecificLogs "plane-redis";; 8) viewSpecificLogs "plane-redis";;
9) viewSpecificLogs "plane-db";; 9) viewSpecificLogs "plane-db";;
10) viewSpecificLogs "plane-minio";; 10) viewSpecificLogs "plane-minio";;
11) viewSpecificLogs "plane-mq";;
0) askForAction;; 0) askForAction;;
*) echo "INVALID SERVICE NAME SUPPLIED";; *) echo "INVALID SERVICE NAME SUPPLIED";;
esac esac
@@ -499,49 +501,76 @@ function viewLogs(){
redis) viewSpecificLogs "plane-redis";; redis) viewSpecificLogs "plane-redis";;
postgres) viewSpecificLogs "plane-db";; postgres) viewSpecificLogs "plane-db";;
minio) viewSpecificLogs "plane-minio";; minio) viewSpecificLogs "plane-minio";;
rabbitmq) viewSpecificLogs "plane-mq";;
*) echo "INVALID SERVICE NAME SUPPLIED";; *) echo "INVALID SERVICE NAME SUPPLIED";;
esac esac
else else
echo "INVALID SERVICE NAME SUPPLIED" echo "INVALID SERVICE NAME SUPPLIED"
fi fi
} }
function backupSingleVolume() { function backup_container_dir() {
backupFolder=$1 local BACKUP_FOLDER=$1
selectedVolume=$2 local CONTAINER_NAME=$2
# Backup data from Docker volume to the backup folder local CONTAINER_DATA_DIR=$3
# docker run --rm -v "$selectedVolume":/source -v "$backupFolder":/backup busybox sh -c 'cp -r /source/* /backup/' local SERVICE_FOLDER=$4
local tobereplaced="plane-app_"
local replacewith=""
local svcName="${selectedVolume//$tobereplaced/$replacewith}" echo "Backing up $CONTAINER_NAME data..."
local CONTAINER_ID=$(/bin/bash -c "$COMPOSE_CMD -f $DOCKER_FILE_PATH ps -q $CONTAINER_NAME")
if [ -z "$CONTAINER_ID" ]; then
echo "Error: $CONTAINER_NAME container not found. Make sure the services are running."
return 1
fi
docker run --rm \ # Create a temporary directory for the backup
-e TAR_NAME="$svcName" \ mkdir -p "$BACKUP_FOLDER/$SERVICE_FOLDER"
-v "$selectedVolume":/"$svcName" \
-v "$backupFolder":/backup \ # Copy the data directory from the running container
busybox sh -c 'tar -czf "/backup/${TAR_NAME}.tar.gz" /${TAR_NAME}' echo "Copying $CONTAINER_NAME data directory..."
docker cp -q "$CONTAINER_ID:$CONTAINER_DATA_DIR/." "$BACKUP_FOLDER/$SERVICE_FOLDER/"
local cp_status=$?
if [ $cp_status -ne 0 ]; then
echo "Error: Failed to copy $SERVICE_FOLDER data"
rm -rf $BACKUP_FOLDER/$SERVICE_FOLDER
return 1
fi
# Create tar.gz of the data
cd "$BACKUP_FOLDER"
tar -czf "${SERVICE_FOLDER}.tar.gz" "$SERVICE_FOLDER/"
local tar_status=$?
if [ $tar_status -eq 0 ]; then
rm -rf "$SERVICE_FOLDER/"
fi
cd - > /dev/null
if [ $tar_status -ne 0 ]; then
echo "Error: Failed to create tar archive"
return 1
fi
echo "Successfully backed up $SERVICE_FOLDER data"
} }
function backupData() { function backupData() {
local datetime=$(date +"%Y%m%d-%H%M") local datetime=$(date +"%Y%m%d-%H%M")
local BACKUP_FOLDER=$PLANE_INSTALL_DIR/backup/$datetime local BACKUP_FOLDER=$PLANE_INSTALL_DIR/backup/$datetime
mkdir -p "$BACKUP_FOLDER" mkdir -p "$BACKUP_FOLDER"
volumes=$(docker volume ls -f "name=$SERVICE_FOLDER" --format "{{.Name}}" | grep -E "_pgdata|_redisdata|_uploads") # Check if docker-compose.yml exists
# Check if there are any matching volumes if [ ! -f "$DOCKER_FILE_PATH" ]; then
if [ -z "$volumes" ]; then echo "Error: docker-compose.yml not found at $DOCKER_FILE_PATH"
echo "No volumes found starting with '$SERVICE_FOLDER'"
exit 1 exit 1
fi fi
for vol in $volumes; do backup_container_dir "$BACKUP_FOLDER" "plane-db" "/var/lib/postgresql/data" "pgdata" || exit 1
echo "Backing Up $vol" backup_container_dir "$BACKUP_FOLDER" "plane-minio" "/export" "uploads" || exit 1
backupSingleVolume "$BACKUP_FOLDER" "$vol" backup_container_dir "$BACKUP_FOLDER" "plane-mq" "/var/lib/rabbitmq" "rabbitmq_data" || exit 1
done backup_container_dir "$BACKUP_FOLDER" "plane-redis" "/data" "redisdata" || exit 1
echo "" echo ""
echo "Backup completed successfully. Backup files are stored in $BACKUP_FOLDER" echo "Backup completed successfully. Backup files are stored in $BACKUP_FOLDER"
echo "" echo ""
} }
function askForAction() { function askForAction() {
local DEFAULT_ACTION=$1 local DEFAULT_ACTION=$1
@@ -628,7 +657,7 @@ if [ -f "$DOCKER_ENV_PATH" ]; then
CUSTOM_BUILD=$(getEnvValue "CUSTOM_BUILD" "$DOCKER_ENV_PATH") CUSTOM_BUILD=$(getEnvValue "CUSTOM_BUILD" "$DOCKER_ENV_PATH")
if [ -z "$DOCKERHUB_USER" ]; then if [ -z "$DOCKERHUB_USER" ]; then
DOCKERHUB_USER=makeplane DOCKERHUB_USER=artifacts.plane.so/makeplane
updateEnvFile "DOCKERHUB_USER" "$DOCKERHUB_USER" "$DOCKER_ENV_PATH" updateEnvFile "DOCKERHUB_USER" "$DOCKERHUB_USER" "$DOCKER_ENV_PATH"
fi fi
+23 -8
View File
@@ -1,13 +1,28 @@
import utils from "../utils.js"; import utils from "../utils.js";
await utils.cloneOrPullRepo({ await utils.removeDir("./code");
repo: "https://github.com/makeplane/plane.git", await utils.renameDir("./plane-code", "./code");
path: "./repo", await utils.removeDir("./code/archive");
branch: "preview", await utils.renameFile("./code/plane.env", "./code/.env.example");
}); 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
@@ -1,14 +0,0 @@
#!/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
+14 -7
View File
@@ -10,7 +10,8 @@ SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJzZX
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
SECRET_KEY_BASE=UpNVntn3cDxHJpq99YMc1T1AQgQpc8kfYTuRgBiYa15BLrx8etQoXz3gZv1/u2oq SECRET_KEY_BASE=UpNVntn3cDxHJpq99YMc1T1AQgQpc8kfYTuRgBiYa15BLrx8etQoXz3gZv1/u2oq
VAULT_ENC_KEY=your-encryption-key-32-chars-min VAULT_ENC_KEY=your-32-character-encryption-key
PG_META_CRYPTO_KEY=your-encryption-key-32-chars-min
############ ############
@@ -26,10 +27,17 @@ POSTGRES_PORT=5432
############ ############
# Supavisor -- Database pooler # Supavisor -- Database pooler
############ ############
# Port Supavisor listens on for transaction 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 tenant identifier
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
############ ############
@@ -52,7 +60,7 @@ PGRST_DB_SCHEMAS=public,storage,graphql_public
############ ############
## General ## General
SITE_URL=http://localhost:3000 SITE_URL=https://$(PRIMARY_DOMAIN)
ADDITIONAL_REDIRECT_URLS= ADDITIONAL_REDIRECT_URLS=
JWT_EXPIRY=3600 JWT_EXPIRY=3600
DISABLE_SIGNUP=false DISABLE_SIGNUP=false
@@ -87,7 +95,6 @@ ENABLE_PHONE_AUTOCONFIRM=true
STUDIO_DEFAULT_ORGANIZATION=Default Organization STUDIO_DEFAULT_ORGANIZATION=Default Organization
STUDIO_DEFAULT_PROJECT=Default Project STUDIO_DEFAULT_PROJECT=Default Project
STUDIO_PORT=3000
# replace if you intend to use Studio outside of localhost # replace if you intend to use Studio outside of localhost
SUPABASE_PUBLIC_URL=http://localhost:8000 SUPABASE_PUBLIC_URL=http://localhost:8000
@@ -106,14 +113,14 @@ FUNCTIONS_VERIFY_JWT=false
############ ############
# Logs - Configuration for Logflare # Logs - Configuration for Analytics
# Please refer to https://supabase.com/docs/reference/self-hosting-analytics/introduction # Please refer to https://supabase.com/docs/reference/self-hosting-analytics/introduction
############ ############
LOGFLARE_LOGGER_BACKEND_API_KEY=your-super-secret-and-long-logflare-key
# Change vector.toml sinks to reflect this change # Change vector.toml sinks to reflect this change
LOGFLARE_API_KEY=your-super-secret-and-long-logflare-key # these cannot be the same value
LOGFLARE_PUBLIC_ACCESS_TOKEN=your-super-secret-and-long-logflare-key-public
LOGFLARE_PRIVATE_ACCESS_TOKEN=your-super-secret-and-long-logflare-key-private
# 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
+272
View File
@@ -0,0 +1,272 @@
# 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
---
## [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 potential 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 potential 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)
---
+86 -2
View File
@@ -1,3 +1,87 @@
# Supabase Docker # Self-Hosted Supabase with Docker
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. 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.
## 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.
+11 -1
View File
@@ -4,10 +4,20 @@ services:
studio: studio:
build: build:
context: .. context: ..
dockerfile: studio/Dockerfile dockerfile: apps/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
+47 -34
View File
@@ -10,7 +10,7 @@ name: supabase
services: services:
studio: studio:
image: supabase/studio:20250113-83c9420 image: supabase/studio:2025.12.17-sha-43f4f7f
restart: unless-stopped restart: unless-stopped
healthcheck: healthcheck:
test: test:
@@ -18,8 +18,8 @@ services:
"CMD", "CMD",
"node", "node",
"-e", "-e",
"fetch('http://studio:3000/api/profile').then((r) => {if (r.status "fetch('http://studio:3000/api/platform/profile').then((r) => {if
!== 200) throw new Error(r.status)})" (r.status !== 200) throw new Error(r.status)})"
] ]
timeout: 10s timeout: 10s
interval: 5s interval: 5s
@@ -28,8 +28,15 @@ 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}
@@ -41,7 +48,11 @@ 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: ${LOGFLARE_API_KEY} # LOGFLARE_API_KEY is deprecated
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
@@ -54,7 +65,7 @@ services:
restart: unless-stopped restart: unless-stopped
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 - ./volumes/api/kong.yml:/home/kong/temp.yml:ro,z
depends_on: depends_on:
analytics: analytics:
condition: service_healthy condition: service_healthy
@@ -63,7 +74,7 @@ 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 KONG_PLUGINS: request-transformer,cors,key-auth,acl,basic-auth,request-termination,ip-restriction
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
SUPABASE_ANON_KEY: ${ANON_KEY} SUPABASE_ANON_KEY: ${ANON_KEY}
@@ -75,7 +86,7 @@ services:
/docker-entrypoint.sh kong docker-start' /docker-entrypoint.sh kong docker-start'
auth: auth:
image: supabase/gotrue:v2.167.0 image: supabase/gotrue:v2.184.0
restart: unless-stopped restart: unless-stopped
healthcheck: healthcheck:
test: test:
@@ -100,7 +111,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}
@@ -157,7 +171,7 @@ services:
# GOTRUE_HOOK_SEND_EMAIL_SECRETS: "v1,whsec_VGhpcyBpcyBhbiBleGFtcGxlIG9mIGEgc2hvcnRlciBCYXNlNjQgc3RyaW5n" # GOTRUE_HOOK_SEND_EMAIL_SECRETS: "v1,whsec_VGhpcyBpcyBhbiBleGFtcGxlIG9mIGEgc2hvcnRlciBCYXNlNjQgc3RyaW5n"
rest: rest:
image: postgrest/postgrest:v12.2.0 image: postgrest/postgrest:v14.1
restart: unless-stopped restart: unless-stopped
depends_on: depends_on:
db: db:
@@ -177,7 +191,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.34.7 image: supabase/realtime:v2.68.0
restart: unless-stopped restart: unless-stopped
depends_on: depends_on:
db: db:
@@ -188,15 +202,9 @@ services:
healthcheck: healthcheck:
test: test:
[ [
"CMD", "CMD-SHELL",
"curl", "curl -sSfL --head -o /dev/null -H \"Authorization: Bearer
"-sSfL", ${ANON_KEY}\" http://localhost:4000/api/tenants/realtime-dev/health"
"--head",
"-o",
"/dev/null",
"-H",
"Authorization: Bearer ${ANON_KEY}",
"http://localhost:4000/api/tenants/realtime-dev/health"
] ]
timeout: 5s timeout: 5s
interval: 5s interval: 5s
@@ -216,12 +224,12 @@ 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"
# 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.14.5 image: supabase/storage-api:v1.33.0
restart: unless-stopped restart: unless-stopped
volumes: volumes:
- ./volumes/storage:/var/lib/storage:z - ./volumes/storage:/var/lib/storage:z
@@ -252,6 +260,7 @@ services:
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
FILE_STORAGE_BACKEND_PATH: /var/lib/storage FILE_STORAGE_BACKEND_PATH: /var/lib/storage
@@ -279,7 +288,7 @@ services:
IMGPROXY_ENABLE_WEBP_DETECTION: ${IMGPROXY_ENABLE_WEBP_DETECTION} IMGPROXY_ENABLE_WEBP_DETECTION: ${IMGPROXY_ENABLE_WEBP_DETECTION}
meta: meta:
image: supabase/postgres-meta:v0.84.2 image: supabase/postgres-meta:v0.95.1
restart: unless-stopped restart: unless-stopped
depends_on: depends_on:
db: db:
@@ -294,9 +303,10 @@ 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.67.0 image: supabase/edge-runtime:v1.69.28
restart: unless-stopped restart: unless-stopped
volumes: volumes:
- ./volumes/functions:/home/deno/functions:Z - ./volumes/functions:/home/deno/functions:Z
@@ -314,7 +324,7 @@ services:
command: [ "start", "--main-service", "/home/deno/functions/main" ] command: [ "start", "--main-service", "/home/deno/functions/main" ]
analytics: analytics:
image: supabase/logflare:1.4.0 image: supabase/logflare:1.27.0
restart: unless-stopped restart: unless-stopped
# Uncomment to use Big Query backend for analytics # Uncomment to use Big Query backend for analytics
# volumes: # volumes:
@@ -339,10 +349,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_API_KEY: ${LOGFLARE_API_KEY} LOGFLARE_PUBLIC_ACCESS_TOKEN: ${LOGFLARE_PUBLIC_ACCESS_TOKEN}
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
@@ -354,7 +364,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.020 image: supabase/postgres:15.8.1.085
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
@@ -405,8 +415,8 @@ services:
image: timberio/vector:0.28.1-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 - ./volumes/logs/vector.yml:/etc/vector/vector.yml:ro,z
- ${DOCKER_SOCKET_LOCATION}:/var/run/docker.sock:ro - ${DOCKER_SOCKET_LOCATION}:/var/run/docker.sock:ro,z
healthcheck: healthcheck:
test: test:
[ [
@@ -421,15 +431,17 @@ services:
interval: 5s interval: 5s
retries: 3 retries: 3
environment: environment:
LOGFLARE_API_KEY: ${LOGFLARE_API_KEY} LOGFLARE_PUBLIC_ACCESS_TOKEN: ${LOGFLARE_PUBLIC_ACCESS_TOKEN}
command: [ "--config", "/etc/vector/vector.yml" ] command: [ "--config", "/etc/vector/vector.yml" ]
security_opt:
- "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:1.1.56 image: supabase/supavisor:2.7.4
restart: unless-stopped restart: unless-stopped
volumes: volumes:
- ./volumes/pooler/pooler.exs:/etc/pooler/pooler.exs:ro - ./volumes/pooler/pooler.exs:/etc/pooler/pooler.exs:ro,z
healthcheck: healthcheck:
test: test:
[ [
@@ -454,7 +466,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}@db:${POSTGRES_PORT}/_supabase DATABASE_URL: ecto://supabase_admin:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${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}
@@ -466,6 +478,7 @@ 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",
+59 -27
View File
@@ -1,44 +1,76 @@
#!/bin/bash #!/bin/sh
echo "WARNING: This will remove all containers and container data, and will reset the .env file. This action cannot be undone!" set -e
read -p "Are you sure you want to proceed? (y/N) " -n 1 -r
echo # Move to a new line auto_confirm=0
if [[ ! $REPLY =~ ^[Yy]$ ]]
then confirm () {
echo "Operation cancelled." if [ "$auto_confirm" = "1" ]; then
exit 1 return 0
fi fi
echo "Stopping and removing all containers..." 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
echo ""
echo "*** WARNING: This will remove all containers and container data, and optionally reset .env ***"
echo ""
confirm
echo "===> Stopping and removing all containers..."
if [ -f ".env" ]; then
docker compose -f docker-compose.yml -f ./dev/docker-compose.dev.yml down -v --remove-orphans docker compose -f docker-compose.yml -f ./dev/docker-compose.dev.yml down -v --remove-orphans
elif [ -f ".env.example" ]; then
echo "Cleaning up bind-mounted directories..." echo "No .env found, using .env.example for docker compose down..."
BIND_MOUNTS=( docker compose --env-file .env.example -f docker-compose.yml -f ./dev/docker-compose.dev.yml down -v --remove-orphans
"./volumes/db/data"
)
for DIR in "${BIND_MOUNTS[@]}"; do
if [ -d "$DIR" ]; then
echo "Deleting $DIR..."
rm -rf "$DIR"
else else
echo "Directory $DIR does not exist. Skipping bind mount deletion step..." 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 fi
done done
echo "Resetting .env file..." echo "===> Resetting .env file (will save backup to .env.old)..."
if [ -f ".env" ]; then confirm
echo "Removing existing .env file..." if [ -f ".env" ] || [ -L ".env" ]; then
rm -f .env echo "Renaming existing .env file to .env.old"
mv .env .env.old
else else
echo "No .env file found. Skipping .env removal step..." echo "No .env file found."
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 ".env.example file not found. Skipping .env reset step..." echo "No .env.example found, can't restore .env to default values."
fi fi
echo "Cleanup complete!" echo "Cleanup complete!"
echo "Re-run 'docker compose pull' to update images."
echo ""
+157
View File
@@ -0,0 +1,157 @@
#!/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 ""
+119
View File
@@ -0,0 +1,119 @@
#!/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)
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 ""
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|^POSTGRES_PASSWORD=.*$|POSTGRES_PASSWORD=${postgres_password}|" \
-e "s|^DASHBOARD_PASSWORD=.*$|DASHBOARD_PASSWORD=${dashboard_password}|" \
.env
+83
View File
@@ -0,0 +1,83 @@
# Docker Image Versions
## 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)
+42
View File
@@ -225,6 +225,48 @@ 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/*'
+31 -10
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 == "supabase-realtime"' realtime: '.appname == "realtime-dev.supabase-realtime"'
storage: '.appname == "supabase-storage"' storage: '.appname == "supabase-storage"'
functions: '.appname == "supabase-functions"' functions: '.appname == "supabase-edge-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:
@@ -117,6 +117,13 @@ 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
@@ -165,7 +172,9 @@ sinks:
method: 'post' method: 'post'
request: request:
retry_max_duration_secs: 10 retry_max_duration_secs: 10
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:
@@ -175,7 +184,9 @@ sinks:
method: 'post' method: 'post'
request: request:
retry_max_duration_secs: 10 retry_max_duration_secs: 10
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:
@@ -185,7 +196,9 @@ sinks:
method: 'post' method: 'post'
request: request:
retry_max_duration_secs: 10 retry_max_duration_secs: 10
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:
@@ -195,20 +208,24 @@ sinks:
method: 'post' method: 'post'
request: request:
retry_max_duration_secs: 10 retry_max_duration_secs: 10
headers:
x-api-key: ${LOGFLARE_PUBLIC_ACCESS_TOKEN?LOGFLARE_PUBLIC_ACCESS_TOKEN is required}
# We must route the sink through kong because ingesting logs before logflare is fully initialised will # We must route the sink through kong because ingesting logs before logflare is fully initialised will
# lead to broken queries from studio. This works by the assumption that containers are started in the # lead to broken queries from studio. This works by the assumption that containers are started in the
# following order: vector > db > logflare > kong # following order: vector > db > logflare > kong
uri: 'http://kong:8000/analytics/v1/api/logs?source_name=postgres.logs&api_key=${LOGFLARE_API_KEY?LOGFLARE_API_KEY is required}' uri: 'http://kong:8000/analytics/v1/api/logs?source_name=postgres.logs'
logflare_functions: logflare_functions:
type: 'http' type: 'http'
inputs: inputs:
- router.functions - functions_logs
encoding: encoding:
codec: 'json' codec: 'json'
method: 'post' method: 'post'
request: request:
retry_max_duration_secs: 10 retry_max_duration_secs: 10
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:
@@ -218,7 +235,9 @@ sinks:
method: 'post' method: 'post'
request: request:
retry_max_duration_secs: 10 retry_max_duration_secs: 10
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:
@@ -229,4 +248,6 @@ sinks:
method: 'post' method: 'post'
request: request:
retry_max_duration_secs: 10 retry_max_duration_secs: 10
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'
+7 -1
View File
@@ -1,7 +1,13 @@
import utils from "../utils.js"; import utils from "../utils.js";
await utils.cloneOrPullRepo({ repo: "https://github.com/supabase/supabase" }); await utils.cloneOrPullRepo({ repo: "https://github.com/supabase/supabase", branch: "master" });
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
@@ -1,11 +0,0 @@
#!/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
@@ -1,4 +0,0 @@
# Twenty
- copied from https://github.com/twentyhq/twenty
- removed `ports`
-19
View File
@@ -1,19 +0,0 @@
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=
-14
View File
@@ -1,14 +0,0 @@
prod-build:
@cd ../.. && docker build -f ./packages/twenty-docker/twenty/Dockerfile --tag twenty . && cd -
prod-run:
@docker run -d -p 3000:3000 --name twenty twenty
prod-postgres-run:
@docker run -d -p 5432:5432 -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres --name twenty-postgres twenty-postgres
prod-website-build:
@cd ../.. && docker build -f ./packages/twenty-docker/twenty-website/Dockerfile --tag twenty-website . && cd -
prod-website-run:
@docker run -d -p 3000:3000 --name twenty-website twenty-website
-88
View File
@@ -1,88 +0,0 @@
name: twenty
services:
change-vol-ownership:
image: ubuntu
user: root
volumes:
- server-local-data:/tmp/server-local-data
- docker-data:/tmp/docker-data
command: >
bash -c " chown -R 1000:1000 /tmp/server-local-data && chown -R 1000:1000
/tmp/docker-data"
server:
image: twentycrm/twenty:${TAG:-latest}
volumes:
- server-local-data:/app/packages/twenty-server/${STORAGE_LOCAL_PATH:-.local-storage}
- docker-data:/app/docker-data
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}
depends_on:
change-vol-ownership:
condition: service_completed_successfully
db:
condition: service_healthy
healthcheck:
test: curl --fail http://localhost:3000/healthz
interval: 5s
timeout: 5s
retries: 10
restart: always
worker:
image: twentycrm/twenty:${TAG:-latest}
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}
depends_on:
db:
condition: service_healthy
server:
condition: service_healthy
restart: always
db:
image: twentycrm/twenty-postgres-spilo:${TAG:-latest}
volumes:
- db-data:/home/postgres/pgdata
environment:
PGUSER_SUPERUSER: ${PG_DATABASE_USER:-postgres}
PGPASSWORD_SUPERUSER: ${PG_DATABASE_PASSWORD:-postgres}
ALLOW_NOSSL: "true"
SPILO_PROVIDER: "local"
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
volumes:
docker-data:
db-data:
server-local-data:
-113
View File
@@ -1,113 +0,0 @@
# README
## 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!
@@ -1,58 +0,0 @@
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
@@ -1,44 +0,0 @@
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
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
@@ -1,76 +0,0 @@
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
@@ -1,57 +0,0 @@
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
@@ -1,24 +0,0 @@
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
@@ -1,11 +0,0 @@
apiVersion: v1
kind: PersistentVolume
metadata:
name: twentycrm-db-pv
spec:
storageClassName: default
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
@@ -1,11 +0,0 @@
apiVersion: v1
kind: PersistentVolume
metadata:
name: twentycrm-docker-data-pv
spec:
storageClassName: default
capacity:
storage: 100Mi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
-12
View File
@@ -1,12 +0,0 @@
apiVersion: v1
kind: PersistentVolume
metadata:
name: twentycrm-server-pv
namespace: twentycrm
spec:
storageClassName: default
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
-13
View File
@@ -1,13 +0,0 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: twentycrm-db-pvc
namespace: twentycrm
spec:
storageClassName: default
volumeName: twentycrm-db-pv
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
@@ -1,13 +0,0 @@
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
@@ -1,13 +0,0 @@
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
@@ -1,18 +0,0 @@
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
@@ -1,18 +0,0 @@
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
@@ -1,19 +0,0 @@
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
@@ -1,48 +0,0 @@
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
@@ -1,73 +0,0 @@
<!-- 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 -->
@@ -1,87 +0,0 @@
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"
}
}
}
}
@@ -1,60 +0,0 @@
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"
}
}
}
}
@@ -1,138 +0,0 @@
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
]
}
@@ -1,99 +0,0 @@
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
@@ -1,30 +0,0 @@
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
@@ -1,23 +0,0 @@
#############
# 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
@@ -1,9 +0,0 @@
resource "kubernetes_namespace" "twentycrm" {
metadata {
annotations = {
name = var.twentycrm_namespace
}
name = var.twentycrm_namespace
}
}
-19
View File
@@ -1,19 +0,0 @@
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
}
}
}
}
@@ -1,19 +0,0 @@
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
@@ -1,19 +0,0 @@
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
@@ -1,15 +0,0 @@
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
}
}
@@ -1,15 +0,0 @@
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
@@ -1,15 +0,0 @@
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
@@ -1,28 +0,0 @@
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
@@ -1,18 +0,0 @@
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"
}
}
@@ -1,18 +0,0 @@
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"
}
}
@@ -1,19 +0,0 @@
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
@@ -1,136 +0,0 @@
######################
# 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."
}
-22
View File
@@ -1,22 +0,0 @@
pull_version=${VERSION:-$(curl -s https://api.github.com/repos/twentyhq/twenty/tags | grep '"name":' | head -n 1 | cut -d '"' -f 4)}
if [[ -z "$pull_version" ]]; then
echo "Error: Unable to fetch the latest version tag. Please check your network connection or the GitHub API response."
exit 1
fi
pull_branch=${BRANCH:-$pull_version}
version_num=${pull_version#v}
target_version="0.32.4"
# We moved the install script to a different location in v0.32.4
if [[ -n "$BRANCH" ]] || [[ "$(printf '%s\n' "$target_version" "$version_num" | sort -V | head -n1)" != "$version_num" ]]; then
curl -sL "https://raw.githubusercontent.com/twentyhq/twenty/$pull_branch/packages/twenty-docker/scripts/install.sh" -o twenty_install.sh
else
curl -sL "https://raw.githubusercontent.com/twentyhq/twenty/$pull_branch/install.sh" -o twenty_install.sh
fi
chmod +x twenty_install.sh
VERSION="$VERSION" BRANCH="$BRANCH" ./twenty_install.sh
rm twenty_install.sh
-167
View File
@@ -1,167 +0,0 @@
#!/bin/bash
echo "🔧 Checking dependencies..."
if ! command -v docker &>/dev/null; then
echo -e "\t❌ Docker is not installed or not in PATH. Please install Docker first.\n\t\tSee https://docs.docker.com/get-docker/"
exit 1
fi
# Check if docker compose plugin is installed
if ! docker compose version &>/dev/null; then
echo -e "\t❌ Docker Compose is not installed or not in PATH (n.b. docker-compose is deprecated)\n\t\tUpdate docker or install docker-compose-plugin\n\t\tOn Linux: sudo apt-get install docker-compose-plugin\n\t\tSee https://docs.docker.com/compose/install/"
exit 1
fi
# Check if docker is started
if ! docker info &>/dev/null; then
echo -e "\t❌ Docker is not running.\n\t\tPlease start Docker Desktop, Docker or check documentation at https://docs.docker.com/config/daemon/start/"
exit 1
fi
if ! command -v curl &>/dev/null; then
echo -e "\t❌ Curl is not installed or not in PATH.\n\t\tOn macOS: brew install curl\n\t\tOn Linux: sudo apt install curl"
exit 1
fi
# Check if docker compose version is >= 2
if [ "$(docker compose version --short | cut -d' ' -f3 | cut -d'.' -f1)" -lt 2 ]; then
echo -e "\t❌ Docker Compose is outdated. Please update Docker Compose to version 2 or higher.\n\t\tSee https://docs.docker.com/compose/install/linux/"
exit 1
fi
# Check if docker-compose is installed, if so issue a warning if version is < 2
if command -v docker-compose &>/dev/null; then
if [ "$(docker-compose version --short | cut -d' ' -f3 | cut -d'.' -f1)" -lt 2 ]; then
echo -e "\n\t⚠️ 'docker-compose' is installed but outdated. Make sure to use 'docker compose' or to upgrade 'docker-compose' to version 2.\n\t\tSee https://docs.docker.com/compose/install/standalone/\n"
fi
fi
# Catch errors
set -e
function on_exit {
# $? is the exit status of the last command executed
local exit_status=$?
if [ $exit_status -ne 0 ]; then
echo "❌ Something went wrong, exiting: $exit_status"
fi
}
trap on_exit EXIT
# Use environment variables VERSION and BRANCH, with defaults if not set
version=${VERSION:-$(curl -s "https://hub.docker.com/v2/repositories/twentycrm/twenty/tags" | grep -o '"name":"[^"]*"' | grep -v 'latest' | cut -d'"' -f4 | sort -V | tail -n1)}
branch=${BRANCH:-$(curl -s https://api.github.com/repos/twentyhq/twenty/tags | grep '"name":' | head -n 1 | cut -d '"' -f 4)}
echo "🚀 Using docker version $version and Github branch $branch"
dir_name="twenty"
function ask_directory {
read -p "📁 Enter the directory name to setup the project (default: $dir_name): " answer
if [ -n "$answer" ]; then
dir_name=$answer
fi
}
ask_directory
while [ -d "$dir_name" ]; do
read -p "🚫 Directory '$dir_name' already exists. Do you want to overwrite it? (y/N) " answer
if [ "$answer" = "y" ]; then
break
else
ask_directory
fi
done
# Create a directory named twenty
echo "📁 Creating directory '$dir_name'"
mkdir -p "$dir_name" && cd "$dir_name" || { echo "❌ Failed to create/access directory '$dir_name'"; exit 1; }
# Copy twenty/packages/twenty-docker/docker-compose.yml in it
echo -e "\t• Copying docker-compose.yml"
curl -sLo docker-compose.yml https://raw.githubusercontent.com/twentyhq/twenty/$branch/packages/twenty-docker/docker-compose.yml
# Copy twenty/packages/twenty-docker/.env.example to .env
echo -e "\t• Setting up .env file"
curl -sLo .env https://raw.githubusercontent.com/twentyhq/twenty/$branch/packages/twenty-docker/.env.example
# Replace TAG=latest by TAG=<latest_release or version input>
if [[ $(uname) == "Darwin" ]]; then
# Running on macOS
sed -i '' "s/TAG=latest/TAG=$version/g" .env
else
# Assuming Linux
sed -i'' "s/TAG=latest/TAG=$version/g" .env
fi
# Generate random strings for secrets
echo "# === Randomly generated secret ===" >> .env
echo "APP_SECRET=$(openssl rand -base64 32)" >> .env
echo "" >> .env
echo "PG_DATABASE_PASSWORD=$(openssl rand -hex 16)" >> .env
echo -e "\t• .env configuration completed"
port=3000
# Check if command nc is available
if command -v nc &> /dev/null; then
# Check if port 3000 is already in use, propose to change it
while nc -zv localhost $port &>/dev/null; do
read -p "🚫 Port $port is already in use. Do you want to use another port? (Y/n) " answer
if [ "$answer" = "n" ]; then
continue
fi
read -p "Enter a new port number: " new_port
if [[ $(uname) == "Darwin" ]]; then
sed -i '' "s/$port:$port/$new_port:$port/g" docker-compose.yml
sed -E -i '' "s|^SERVER_URL=http://localhost:[0-9]+|SERVER_URL=http://localhost:$new_port|g" .env
else
sed -i'' "s/$port:$port/$new_port:$port/g" docker-compose.yml
sed -E -i'' "s|^SERVER_URL=http://localhost:[0-9]+|SERVER_URL=http://localhost:$new_port|g" .env
fi
port=$new_port
done
fi
# Ask user if they want to start the project
read -p "🚀 Do you want to start the project now? (Y/n) " answer
if [ "$answer" = "n" ]; then
echo "✅ Project setup completed. Run 'docker compose up -d' to start."
exit 0
else
echo "🐳 Starting Docker containers..."
docker compose up -d
# Check if port is listening
echo "Waiting for server to be healthy, it might take a few minutes while we initialize the database..."
# Tail logs of the server until it's ready
docker compose logs -f server &
pid=$!
while [ ! $(docker inspect --format='{{.State.Health.Status}}' twenty-server-1) = "healthy" ]; do
sleep 1
done
kill $pid
echo ""
echo "✅ Server is up and running"
fi
function ask_open_browser {
read -p "🌐 Do you want to open the project in your browser? (Y/n) " answer
if [ "$answer" = "n" ]; then
echo "✅ Setup completed. Access your project at http://localhost:$port"
exit 0
fi
}
# Ask user if they want to open the project
# Running on macOS
if [[ $(uname) == "Darwin" ]]; then
ask_open_browser
open "http://localhost:$port"
# Assuming Linux
else
# xdg-open is not installed, we could be running in a non gui environment
if command -v xdg-open >/dev/null 2>&1; then
ask_open_browser
xdg-open "http://localhost:$port"
else
echo "✅ Setup completed. Your project is available at http://localhost:$port"
fi
fi
@@ -1,68 +0,0 @@
ARG POSTGRES_VERSION=15
ARG SPILO_VERSION=3.2-p1
ARG WRAPPERS_VERSION=0.2.0
# Build the mysql_fdw extension
FROM debian:bookworm AS build-mysql_fdw
ARG POSTGRES_VERSION
ENV DEBIAN_FRONTEND=noninteractive
RUN apt update && \
apt install -y \
build-essential \
git \
postgresql-server-dev-${POSTGRES_VERSION} \
default-libmysqlclient-dev && \
rm -rf /var/lib/apt/lists/*
# Install mysql_fdw
RUN git clone https://github.com/EnterpriseDB/mysql_fdw.git
WORKDIR /mysql_fdw
RUN make USE_PGXS=1
# Build libssl for wrappers
FROM ubuntu:22.04 AS build-libssl
ENV DEBIAN_FRONTEND=noninteractive
RUN apt update && \
apt install -y \
build-essential \
git && \
rm -rf /var/lib/apt/lists/*
WORKDIR /build
RUN git clone --branch OpenSSL_1_1_1-stable https://github.com/openssl/openssl.git
WORKDIR /build/openssl
RUN ./config && make && make install
# Extend the Spilo image with the mysql_fdw extensions
FROM ghcr.io/zalando/spilo-${POSTGRES_VERSION}:${SPILO_VERSION}
ARG POSTGRES_VERSION
ARG WRAPPERS_VERSION
ARG TARGETARCH
# Install precompiled supabase wrappers extensions
RUN set -eux; \
ARCH="$(dpkg --print-architecture)"; \
case "${ARCH}" in \
aarch64|arm64) TARGETARCH='arm64';; \
amd64|x86_64) TARGETARCH='amd64';; \
*) echo "Unsupported arch: ${ARCH}"; exit 1;; \
esac;
RUN apt update && apt install default-libmysqlclient-dev -y && rm -rf /var/lib/apt/lists/*
RUN curl -L "https://github.com/supabase/wrappers/releases/download/v${WRAPPERS_VERSION}/wrappers-v${WRAPPERS_VERSION}-pg${POSTGRES_VERSION}-${TARGETARCH}-linux-gnu.deb" -o wrappers.deb && \
dpkg --install wrappers.deb && \
rm wrappers.deb
COPY --from=build-libssl /usr/local/lib/libssl* /usr/local/lib/libcrypto* /usr/lib/
COPY --from=build-libssl /usr/local/lib/engines-1.1 /usr/lib/engines-1.1
# Copy mysql_fdw
COPY --from=build-mysql_fdw /mysql_fdw/mysql_fdw.so \
/usr/lib/postgresql/${POSTGRES_VERSION}/lib/mysql_fdw.so
COPY --from=build-mysql_fdw /mysql_fdw/mysql_fdw*.sql /mysql_fdw/mysql_fdw.control /mysql_fdw/mysql_fdw_pushdown.config \
/usr/share/postgresql/${POSTGRES_VERSION}/extension/
-29
View File
@@ -1,29 +0,0 @@
FROM node:18.17.1-alpine as twenty-website-build
WORKDIR /app
COPY ./package.json .
COPY ./yarn.lock .
COPY ./.yarnrc.yml .
COPY ./.yarn/releases /app/.yarn/releases
COPY ./tools/eslint-rules /app/tools/eslint-rules
COPY ./packages/twenty-website/package.json /app/packages/twenty-website/package.json
RUN yarn
COPY ./packages/twenty-website /app/packages/twenty-website
RUN npx nx build twenty-website
FROM node:18.17.1-alpine as twenty-website
WORKDIR /app/packages/twenty-website
COPY --from=twenty-website-build /app /app
WORKDIR /app/packages/twenty-website
LABEL org.opencontainers.image.source=https://github.com/twentyhq/twenty
LABEL org.opencontainers.image.description="This image provides a consistent and reproducible environment for the website."
CMD ["/bin/sh", "-c", "npx nx start"]
-85
View File
@@ -1,85 +0,0 @@
# Base image for common dependencies
FROM node:18.17.1-alpine as common-deps
WORKDIR /app
# Copy only the necessary files for dependency resolution
COPY ./package.json ./yarn.lock ./.yarnrc.yml ./tsconfig.base.json ./nx.json /app/
COPY ./.yarn/releases /app/.yarn/releases
COPY ./packages/twenty-emails/package.json /app/packages/twenty-emails/
COPY ./packages/twenty-server/package.json /app/packages/twenty-server/
COPY ./packages/twenty-server/patches /app/packages/twenty-server/patches
COPY ./packages/twenty-ui/package.json /app/packages/twenty-ui/
COPY ./packages/twenty-shared/package.json /app/packages/twenty-shared/
COPY ./packages/twenty-front/package.json /app/packages/twenty-front/
# Install all dependencies
RUN yarn && yarn cache clean && npx nx reset
# Build the back
FROM common-deps as twenty-server-build
# Copy sourcecode after installing dependences to accelerate subsequents builds
COPY ./packages/twenty-emails /app/packages/twenty-emails
COPY ./packages/twenty-shared /app/packages/twenty-shared
COPY ./packages/twenty-server /app/packages/twenty-server
RUN npx nx run twenty-server:build
RUN mv /app/packages/twenty-server/dist /app/packages/twenty-server/build
RUN npx nx run twenty-server:build:packageJson
RUN mv /app/packages/twenty-server/dist/package.json /app/packages/twenty-server/package.json
RUN rm -rf /app/packages/twenty-server/dist
RUN mv /app/packages/twenty-server/build /app/packages/twenty-server/dist
RUN yarn workspaces focus --production twenty-emails twenty-shared twenty-server
# Build the front
FROM common-deps as twenty-front-build
ARG REACT_APP_SERVER_BASE_URL
COPY ./packages/twenty-front /app/packages/twenty-front
COPY ./packages/twenty-ui /app/packages/twenty-ui
COPY ./packages/twenty-shared /app/packages/twenty-shared
RUN npx nx build twenty-front
# Final stage: Run the application
FROM node:18.17.1-alpine as twenty
# Used to run healthcheck in docker
RUN apk add --no-cache curl jq
RUN npm install -g tsx
RUN apk add --no-cache postgresql-client
COPY ./packages/twenty-docker/twenty/entrypoint.sh /app/entrypoint.sh
RUN chmod +x /app/entrypoint.sh
WORKDIR /app/packages/twenty-server
ARG REACT_APP_SERVER_BASE_URL
ENV REACT_APP_SERVER_BASE_URL $REACT_APP_SERVER_BASE_URL
ARG SENTRY_RELEASE
ENV SENTRY_RELEASE $SENTRY_RELEASE
# Copy built applications from previous stages
COPY --chown=1000 --from=twenty-server-build /app /app
COPY --chown=1000 --from=twenty-server-build /app/packages/twenty-server /app/packages/twenty-server
COPY --chown=1000 --from=twenty-front-build /app/packages/twenty-front/build /app/packages/twenty-server/dist/front
# Set metadata and labels
LABEL org.opencontainers.image.source=https://github.com/twentyhq/twenty
LABEL org.opencontainers.image.description="This image provides a consistent and reproducible environment for the backend and frontend, ensuring it deploys faster and runs the same way regardless of the deployment environment."
RUN mkdir /app/.local-storage
RUN chown -R 1000 /app
# Use non root user with uid 1000
USER 1000
CMD ["node", "dist/src/main"]
ENTRYPOINT ["/app/entrypoint.sh"]
-26
View File
@@ -1,26 +0,0 @@
#!/bin/sh
set -e
# Check if the initialization has already been done and that we enabled automatic migration
if [ "${DISABLE_DB_MIGRATIONS}" != "true" ] && [ ! -f /app/docker-data/db_status ]; then
echo "Running database setup and migrations..."
# Creating the database if it doesn't exist
PGUSER=$(echo $PG_DATABASE_URL | awk -F '//' '{print $2}' | awk -F ':' '{print $1}')
PGPASS=$(echo $PG_DATABASE_URL | awk -F ':' '{print $3}' | awk -F '@' '{print $1}')
PGHOST=$(echo $PG_DATABASE_URL | awk -F '@' '{print $2}' | awk -F ':' '{print $1}')
PGPORT=$(echo $PG_DATABASE_URL | awk -F ':' '{print $4}' | awk -F '/' '{print $1}')
PGPASSWORD=${PGPASS} psql -h ${PGHOST} -p ${PGPORT} -U ${PGUSER} -d postgres -tc "SELECT 1 FROM pg_database WHERE datname = 'default'" | grep -q 1 || \
PGPASSWORD=${PGPASS} psql -h ${PGHOST} -p ${PGPORT} -U ${PGUSER} -d postgres -c "CREATE DATABASE \"default\""
# Run setup and migration scripts
NODE_OPTIONS="--max-old-space-size=1500" tsx ./scripts/setup-db.ts
yarn database:migrate:prod
# Mark initialization as done
echo "Successfuly migrated DB!"
touch /app/docker-data/db_status
fi
# Continue with the original Docker command
exec "$@"
-25
View File
@@ -1,25 +0,0 @@
import utils from "../utils.js";
await utils.cloneOrPullRepo({ repo: "git@github.com:twentyhq/twenty.git" });
await utils.copyDir("./repo/packages/twenty-docker", "./code");
await utils.removeContainerNames("./code/docker-compose.yml");
await utils.removePorts("./code/docker-compose.yml");
await utils.searchReplace(
"./code/.env.example",
"#REDIS_URL=redis://redis:6379",
"REDIS_URL=redis://redis:6379"
);
await utils.searchReplace(
"./code/.env.example",
"SERVER_URL=http://localhost:3000",
"SERVER_URL=https://$(PRIMARY_DOMAIN)"
);
await utils.searchReplace(
"./code/.env.example",
"# APP_SECRET=replace_me_with_a_random_string",
"APP_SECRET=replace_me_with_a_random_string"
);
-13
View File
@@ -1,13 +0,0 @@
#!/bin/bash
if [ ! -d "./repo" ]; then
git clone --depth 1 --branch main --single-branch git@github.com:twentyhq/twenty.git repo
else
cd repo
git pull
cd ..
fi
cp -r ./repo/packages/twenty-docker/. ./code

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