Compare commits

...

21 Commits

Author SHA1 Message Date
Andrei Canta e0e7cbeeef update 2025-07-03 16:01:58 +03:00
Andrei Canta 405fd49534 update 2025-05-21 20:09:48 +03:00
Andrei Canta f57b86d84f update templates 2025-02-20 12:56:11 +02:00
Andrei Canta 5fac760f2a update 2025-01-30 14:37:42 +02:00
Andrei Canta aa05d8edec update all 2024-12-04 15:21:36 +02:00
Andrei Canta 9c2502c8d8 add nodejs update scripts 2024-12-04 15:16:47 +02:00
Andrei Canta e9a2778e17 Merge pull request #13 from juniorsereno/patch-1
Update Dify .env.example to 0.10.1
2024-12-04 14:06:20 +02:00
Andrei Canta e466f70643 Merge pull request #16 from Ahson-Shaikh/twenty-template-update-2024-11-09
Twenty template fixed and updated to v0.32.3
2024-12-04 14:04:26 +02:00
Andrei Canta bce0268b02 Merge pull request #18 from Ahson-Shaikh/updated-plane-and-fixed
Fixed Plane and Updated to newer version.
2024-12-04 14:04:03 +02:00
Andrei Canta 3da4af5431 Merge pull request #20 from 2BX-git/main
docker-compose.yaml
2024-12-04 14:02:59 +02:00
2BX 0b3cb0b5d3 docker-compose.yaml 2024-11-22 19:19:34 -03:00
Ahson Shaikh 9d7cf80691 Fixed the wrong syntax 2024-11-13 23:21:38 +05:00
Ahson Shaikh fec2d9955c Updated Plane and Fixed 2024-11-13 22:37:21 +05:00
Ahson Shaikh b16791dd7a Twenty template fixed and updated to v0.32.3 2024-11-09 16:04:56 +05:00
juniorsereno c82da10738 Update .env.example to 0.10.1 2024-10-24 14:15:22 -03:00
Andrei Canta f0fd148d95 update supabase 2024-09-27 14:45:55 +03:00
Andrei Canta 334f94878b update appwrite 2024-09-27 14:41:34 +03:00
Andrei Canta e6ca3d4c99 fix twenty env 2024-09-27 14:39:59 +03:00
Andrei Canta e75da89239 update twenty 2024-09-27 14:30:46 +03:00
Andrei Canta 2466ad1785 update dify 2024-09-27 14:29:29 +03:00
Andrei Canta 662394d56d Merge pull request #8 from easypanel-io/update-templates
update templates 30.08.24
2024-08-30 12:06:41 +03:00
98 changed files with 6224 additions and 1110 deletions
+1
View File
@@ -1 +1,2 @@
repo repo
node_modules
+24 -1
View File
@@ -3,17 +3,24 @@ _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=localhost
_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_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=
_APP_CONSOLE_HOSTNAMES= _APP_CONSOLE_HOSTNAMES=
_APP_SYSTEM_EMAIL_NAME=Appwrite _APP_SYSTEM_EMAIL_NAME=Appwrite
_APP_SYSTEM_EMAIL_ADDRESS=team@appwrite.io _APP_SYSTEM_EMAIL_ADDRESS=noreply@appwrite.io
_APP_SYSTEM_TEAM_EMAIL=team@appwrite.io
_APP_SYSTEM_RESPONSE_FORMAT= _APP_SYSTEM_RESPONSE_FORMAT=
_APP_SYSTEM_SECURITY_EMAIL_ADDRESS=certs@appwrite.io _APP_SYSTEM_SECURITY_EMAIL_ADDRESS=certs@appwrite.io
_APP_EMAIL_SECURITY= _APP_EMAIL_SECURITY=
@@ -25,6 +32,9 @@ _APP_USAGE_AGGREGATION_INTERVAL=30
_APP_USAGE_TIMESERIES_INTERVAL=30 _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_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=
@@ -56,6 +66,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
@@ -73,11 +84,16 @@ _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_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
@@ -85,14 +101,19 @@ _APP_EXECUTOR_HOST=http://exc1/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=
@@ -101,9 +122,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
+177 -68
View File
@@ -1,9 +1,9 @@
x-logging: &x-logging x-logging: &x-logging
logging: logging:
driver: "json-file" driver: 'json-file'
options: options:
max-file: "5" max-file: '5'
max-size: "10m" max-size: '10m'
services: services:
traefik: traefik:
image: traefik:2.11 image: traefik:2.11
@@ -28,7 +28,7 @@ services:
- appwrite - appwrite
appwrite: appwrite:
image: appwrite/appwrite:1.5.10 image: appwrite/appwrite:1.7.4
<<: *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,8 +64,10 @@ 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_WHITELIST_IPS - _APP_CONSOLE_WHITELIST_IPS
- _APP_CONSOLE_HOSTNAMES - _APP_CONSOLE_HOSTNAMES
- _APP_SYSTEM_EMAIL_NAME - _APP_SYSTEM_EMAIL_NAME
@@ -72,10 +77,12 @@ 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_FUNCTIONS - _APP_DOMAIN_FUNCTIONS
- _APP_REDIS_HOST - _APP_REDIS_HOST
- _APP_REDIS_PORT - _APP_REDIS_PORT
@@ -102,6 +109,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
@@ -118,22 +126,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_PROVIDER
- _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
@@ -151,8 +163,29 @@ services:
- _APP_MIGRATIONS_FIREBASE_CLIENT_SECRET - _APP_MIGRATIONS_FIREBASE_CLIENT_SECRET
- _APP_ASSISTANT_OPENAI_API_KEY - _APP_ASSISTANT_OPENAI_API_KEY
appwrite-console:
<<: *x-logging
image: appwrite/console:6.0.13
restart: unless-stopped
networks:
- appwrite
labels:
- "traefik.enable=true"
- "traefik.constraint-label-stack=appwrite"
- "traefik.docker.network=appwrite"
- "traefik.http.services.appwrite_console.loadbalancer.server.port=80"
#ws
- traefik.http.routers.appwrite_console_http.entrypoints=appwrite_web
- traefik.http.routers.appwrite_console_http.rule=PathPrefix(`/console`)
- traefik.http.routers.appwrite_console_http.service=appwrite_console
# wss
- traefik.http.routers.appwrite_console_https.entrypoints=appwrite_websecure
- traefik.http.routers.appwrite_console_https.rule=PathPrefix(`/console`)
- traefik.http.routers.appwrite_console_https.service=appwrite_console
- traefik.http.routers.appwrite_console_https.tls=true
appwrite-realtime: appwrite-realtime:
image: appwrite/appwrite:1.5.10 image: appwrite/appwrite:1.7.4
entrypoint: realtime entrypoint: realtime
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
@@ -191,11 +224,10 @@ services:
- _APP_DB_USER - _APP_DB_USER
- _APP_DB_PASS - _APP_DB_PASS
- _APP_USAGE_STATS - _APP_USAGE_STATS
- _APP_LOGGING_PROVIDER
- _APP_LOGGING_CONFIG - _APP_LOGGING_CONFIG
appwrite-worker-audits: appwrite-worker-audits:
image: appwrite/appwrite:1.5.10 image: appwrite/appwrite:1.7.4
entrypoint: worker-audits entrypoint: worker-audits
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
@@ -217,11 +249,10 @@ services:
- _APP_DB_SCHEMA - _APP_DB_SCHEMA
- _APP_DB_USER - _APP_DB_USER
- _APP_DB_PASS - _APP_DB_PASS
- _APP_LOGGING_PROVIDER
- _APP_LOGGING_CONFIG - _APP_LOGGING_CONFIG
appwrite-worker-webhooks: appwrite-worker-webhooks:
image: appwrite/appwrite:1.5.10 image: appwrite/appwrite:1.7.4
entrypoint: worker-webhooks entrypoint: worker-webhooks
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
@@ -245,11 +276,10 @@ services:
- _APP_REDIS_PORT - _APP_REDIS_PORT
- _APP_REDIS_USER - _APP_REDIS_USER
- _APP_REDIS_PASS - _APP_REDIS_PASS
- _APP_LOGGING_PROVIDER
- _APP_LOGGING_CONFIG - _APP_LOGGING_CONFIG
appwrite-worker-deletes: appwrite-worker-deletes:
image: appwrite/appwrite:1.5.10 image: appwrite/appwrite:1.7.4
entrypoint: worker-deletes entrypoint: worker-deletes
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
@@ -262,6 +292,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:
@@ -282,6 +313,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
@@ -298,13 +330,18 @@ 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_LOGGING_PROVIDER
- _APP_LOGGING_CONFIG - _APP_LOGGING_CONFIG
- _APP_EXECUTOR_SECRET - _APP_EXECUTOR_SECRET
- _APP_EXECUTOR_HOST - _APP_EXECUTOR_HOST
- _APP_MAINTENANCE_RETENTION_ABUSE
- _APP_MAINTENANCE_RETENTION_AUDIT
- _APP_MAINTENANCE_RETENTION_AUDIT_CONSOLE
- _APP_MAINTENANCE_RETENTION_EXECUTION
- _APP_SYSTEM_SECURITY_EMAIL_ADDRESS
- _APP_EMAIL_CERTIFICATES
appwrite-worker-databases: appwrite-worker-databases:
image: appwrite/appwrite:1.5.10 image: appwrite/appwrite:1.7.4
entrypoint: worker-databases entrypoint: worker-databases
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
@@ -326,11 +363,10 @@ services:
- _APP_DB_SCHEMA - _APP_DB_SCHEMA
- _APP_DB_USER - _APP_DB_USER
- _APP_DB_PASS - _APP_DB_PASS
- _APP_LOGGING_PROVIDER
- _APP_LOGGING_CONFIG - _APP_LOGGING_CONFIG
appwrite-worker-builds: appwrite-worker-builds:
image: appwrite/appwrite:1.5.10 image: appwrite/appwrite:1.7.4
entrypoint: worker-builds entrypoint: worker-builds
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
@@ -341,7 +377,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
@@ -357,24 +395,25 @@ services:
- _APP_DB_SCHEMA - _APP_DB_SCHEMA
- _APP_DB_USER - _APP_DB_USER
- _APP_DB_PASS - _APP_DB_PASS
- _APP_LOGGING_PROVIDER
- _APP_LOGGING_CONFIG - _APP_LOGGING_CONFIG
- _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
- _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
@@ -391,9 +430,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.5.10 image: appwrite/appwrite:1.7.4
entrypoint: worker-certificates entrypoint: worker-certificates
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
@@ -410,7 +450,9 @@ 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_FUNCTIONS - _APP_DOMAIN_FUNCTIONS
- _APP_EMAIL_CERTIFICATES - _APP_EMAIL_CERTIFICATES
- _APP_REDIS_HOST - _APP_REDIS_HOST
@@ -422,11 +464,10 @@ services:
- _APP_DB_SCHEMA - _APP_DB_SCHEMA
- _APP_DB_USER - _APP_DB_USER
- _APP_DB_PASS - _APP_DB_PASS
- _APP_LOGGING_PROVIDER
- _APP_LOGGING_CONFIG - _APP_LOGGING_CONFIG
appwrite-worker-functions: appwrite-worker-functions:
image: appwrite/appwrite:1.5.10 image: appwrite/appwrite:1.7.4
entrypoint: worker-functions entrypoint: worker-functions
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
@@ -440,6 +481,8 @@ services:
- _APP_ENV - _APP_ENV
- _APP_WORKER_PER_CORE - _APP_WORKER_PER_CORE
- _APP_OPENSSL_KEY_V1 - _APP_OPENSSL_KEY_V1
- _APP_DOMAIN
- _APP_OPTIONS_FORCE_HTTPS
- _APP_REDIS_HOST - _APP_REDIS_HOST
- _APP_REDIS_PORT - _APP_REDIS_PORT
- _APP_REDIS_USER - _APP_REDIS_USER
@@ -450,19 +493,19 @@ 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
- _APP_DOCKER_HUB_USERNAME - _APP_DOCKER_HUB_USERNAME
- _APP_DOCKER_HUB_PASSWORD - _APP_DOCKER_HUB_PASSWORD
- _APP_LOGGING_CONFIG - _APP_LOGGING_CONFIG
- _APP_LOGGING_PROVIDER
appwrite-worker-mails: appwrite-worker-mails:
image: appwrite/appwrite:1.5.10 image: appwrite/appwrite:1.7.4
entrypoint: worker-mails entrypoint: worker-mails
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
@@ -490,11 +533,12 @@ services:
- _APP_SMTP_SECURE - _APP_SMTP_SECURE
- _APP_SMTP_USERNAME - _APP_SMTP_USERNAME
- _APP_SMTP_PASSWORD - _APP_SMTP_PASSWORD
- _APP_LOGGING_PROVIDER
- _APP_LOGGING_CONFIG - _APP_LOGGING_CONFIG
- _APP_DOMAIN
- _APP_OPTIONS_FORCE_HTTPS
appwrite-worker-messaging: appwrite-worker-messaging:
image: appwrite/appwrite:1.5.10 image: appwrite/appwrite:1.7.4
entrypoint: worker-messaging entrypoint: worker-messaging
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
@@ -517,7 +561,6 @@ services:
- _APP_DB_SCHEMA - _APP_DB_SCHEMA
- _APP_DB_USER - _APP_DB_USER
- _APP_DB_PASS - _APP_DB_PASS
- _APP_LOGGING_PROVIDER
- _APP_LOGGING_CONFIG - _APP_LOGGING_CONFIG
- _APP_SMS_FROM - _APP_SMS_FROM
- _APP_SMS_PROVIDER - _APP_SMS_PROVIDER
@@ -526,6 +569,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
@@ -544,12 +588,14 @@ services:
- _APP_STORAGE_WASABI_BUCKET - _APP_STORAGE_WASABI_BUCKET
appwrite-worker-migrations: appwrite-worker-migrations:
image: appwrite/appwrite:1.5.10 image: appwrite/appwrite:1.7.4
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:
@@ -557,7 +603,9 @@ 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_EMAIL_SECURITY - _APP_EMAIL_SECURITY
- _APP_REDIS_HOST - _APP_REDIS_HOST
- _APP_REDIS_PORT - _APP_REDIS_PORT
@@ -568,13 +616,12 @@ services:
- _APP_DB_SCHEMA - _APP_DB_SCHEMA
- _APP_DB_USER - _APP_DB_USER
- _APP_DB_PASS - _APP_DB_PASS
- _APP_LOGGING_PROVIDER
- _APP_LOGGING_CONFIG - _APP_LOGGING_CONFIG
- _APP_MIGRATIONS_FIREBASE_CLIENT_ID - _APP_MIGRATIONS_FIREBASE_CLIENT_ID
- _APP_MIGRATIONS_FIREBASE_CLIENT_SECRET - _APP_MIGRATIONS_FIREBASE_CLIENT_SECRET
appwrite-task-maintenance: appwrite-task-maintenance:
image: appwrite/appwrite:1.5.10 image: appwrite/appwrite:1.7.4
entrypoint: maintenance entrypoint: maintenance
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
@@ -586,7 +633,9 @@ 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_FUNCTIONS - _APP_DOMAIN_FUNCTIONS
- _APP_OPENSSL_KEY_V1 - _APP_OPENSSL_KEY_V1
- _APP_REDIS_HOST - _APP_REDIS_HOST
@@ -603,12 +652,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.5.10 image: appwrite/appwrite:1.7.4
entrypoint: worker-usage entrypoint: stats-resources
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
networks: networks:
@@ -630,14 +680,42 @@ services:
- _APP_REDIS_USER - _APP_REDIS_USER
- _APP_REDIS_PASS - _APP_REDIS_PASS
- _APP_USAGE_STATS - _APP_USAGE_STATS
- _APP_LOGGING_PROVIDER
- _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.5.10 image: appwrite/appwrite:1.7.4
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.7.4
entrypoint: worker-stats-usage
<<: *x-logging
restart: unless-stopped
networks: networks:
- appwrite - appwrite
depends_on: depends_on:
@@ -657,12 +735,11 @@ services:
- _APP_REDIS_USER - _APP_REDIS_USER
- _APP_REDIS_PASS - _APP_REDIS_PASS
- _APP_USAGE_STATS - _APP_USAGE_STATS
- _APP_LOGGING_PROVIDER
- _APP_LOGGING_CONFIG - _APP_LOGGING_CONFIG
- _APP_USAGE_AGGREGATION_INTERVAL - _APP_USAGE_AGGREGATION_INTERVAL
appwrite-task-scheduler-functions: appwrite-task-scheduler-functions:
image: appwrite/appwrite:1.5.10 image: appwrite/appwrite:1.7.4
entrypoint: schedule-functions entrypoint: schedule-functions
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
@@ -685,8 +762,32 @@ services:
- _APP_DB_USER - _APP_DB_USER
- _APP_DB_PASS - _APP_DB_PASS
appwrite-task-scheduler-executions:
image: appwrite/appwrite:1.7.4
entrypoint: schedule-executions
<<: *x-logging
restart: unless-stopped
networks:
- appwrite
depends_on:
- mariadb
- redis
environment:
- _APP_ENV
- _APP_WORKER_PER_CORE
- _APP_OPENSSL_KEY_V1
- _APP_REDIS_HOST
- _APP_REDIS_PORT
- _APP_REDIS_USER
- _APP_REDIS_PASS
- _APP_DB_HOST
- _APP_DB_PORT
- _APP_DB_SCHEMA
- _APP_DB_USER
- _APP_DB_PASS
appwrite-task-scheduler-messages: appwrite-task-scheduler-messages:
image: appwrite/appwrite:1.5.10 image: appwrite/appwrite:1.7.4
entrypoint: schedule-messages entrypoint: schedule-messages
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
@@ -718,12 +819,19 @@ services:
environment: environment:
- _APP_ASSISTANT_OPENAI_API_KEY - _APP_ASSISTANT_OPENAI_API_KEY
appwrite-browser:
image: appwrite/browser:0.2.4
<<: *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.5.7 image: openruntimes/executor:0.7.14
networks: networks:
- appwrite - appwrite
- runtimes - runtimes
@@ -731,25 +839,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_LOGGING_PROVIDER=$_APP_LOGGING_PROVIDER - 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
@@ -781,22 +891,19 @@ services:
- MYSQL_USER=${_APP_DB_USER} - MYSQL_USER=${_APP_DB_USER}
- MYSQL_PASSWORD=${_APP_DB_PASS} - MYSQL_PASSWORD=${_APP_DB_PASS}
- MARIADB_AUTO_UPGRADE=1 - MARIADB_AUTO_UPGRADE=1
command: "mysqld --innodb-flush-method=fsync" command: 'mysqld --innodb-flush-method=fsync'
redis: redis:
image: redis:7.2.4-alpine image: redis:7.2.4-alpine
<<: *x-logging <<: *x-logging
restart: unless-stopped restart: unless-stopped
command: > command: >
redis-server redis-server --maxmemory 512mb
--maxmemory 512mb --maxmemory-policy allkeys-lru --maxmemory-samples 5
--maxmemory-policy allkeys-lru
--maxmemory-samples 5
networks: networks:
- appwrite - appwrite
volumes: volumes:
- appwrite-redis:/data:rw - appwrite-redis:/data:rw
# clamav: # clamav:
# image: appwrite/clamav:1.2.0 # image: appwrite/clamav:1.2.0
# container_name: appwrite-clamav # container_name: appwrite-clamav
@@ -819,7 +926,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:
+13
View File
@@ -0,0 +1,13 @@
import utils from "../utils.js";
await utils.downloadFile(
"https://appwrite.io/install/compose",
"./code/docker-compose.yml"
);
await utils.downloadFile(
"https://appwrite.io/install/env",
"./code/.env.example"
);
await utils.removeContainerNames("./code/docker-compose.yml");
await utils.removePorts("./code/docker-compose.yml");
+491 -78
View File
@@ -39,6 +39,12 @@ APP_WEB_URL=
# File preview or download Url prefix. # File preview or download Url prefix.
# used to display File preview or download Url to the front-end or as Multi-model inputs; # used to display File preview or download Url to the front-end or as Multi-model inputs;
# Url is signed and has expiration time. # Url is signed and has expiration time.
# Setting FILES_URL is required for file processing plugins.
# - For https://example.com, use FILES_URL=https://example.com
# - For http://example.com, use FILES_URL=http://example.com
# Recommendation: use a dedicated domain (e.g., https://upload.example.com).
# Alternatively, use http://<your-ip>:5001 or http://api:5001,
# ensuring port 5001 is externally accessible (see docker-compose.yaml).
FILES_URL= FILES_URL=
# ------------------------------ # ------------------------------
@@ -48,6 +54,16 @@ FILES_URL=
# The log level for the application. # The log level for the application.
# Supported values are `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL` # Supported values are `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL`
LOG_LEVEL=INFO LOG_LEVEL=INFO
# Log file path
LOG_FILE=/app/logs/server.log
# Log file max size, the unit is MB
LOG_FILE_MAX_SIZE=20
# Log file max backup count
LOG_FILE_BACKUP_COUNT=5
# Log dateformat
LOG_DATEFORMAT=%Y-%m-%d %H:%M:%S
# Log Timezone
LOG_TZ=UTC
# Debug mode, default is false. # Debug mode, default is false.
# It is recommended to turn on this configuration for local development # It is recommended to turn on this configuration for local development
@@ -58,7 +74,11 @@ DEBUG=false
# which is convenient for debugging. # which is convenient for debugging.
FLASK_DEBUG=false FLASK_DEBUG=false
# A secretkey that is used for securely signing the session cookie # Enable request logging, which will log the request and response information.
# And the log level is DEBUG
ENABLE_REQUEST_LOGGING=False
# A secret key that is used for securely signing the session cookie
# and encrypting sensitive information on the database. # and encrypting sensitive information on the database.
# You can generate a strong key using `openssl rand -base64 42`. # You can generate a strong key using `openssl rand -base64 42`.
SECRET_KEY=sk-9f73s3ljTXVcMT3Blb3ljTqtsKiGHXVcMT3BlbkFJLK7U SECRET_KEY=sk-9f73s3ljTXVcMT3Blb3ljTqtsKiGHXVcMT3BlbkFJLK7U
@@ -66,6 +86,7 @@ SECRET_KEY=sk-9f73s3ljTXVcMT3Blb3ljTqtsKiGHXVcMT3BlbkFJLK7U
# Password for admin user initialization. # Password for admin user initialization.
# If left unset, admin user will not be prompted for a password # If left unset, admin user will not be prompted for a password
# when creating the initial admin account. # when creating the initial admin account.
# The length of the password cannot exceed 30 characters.
INIT_PASSWORD= INIT_PASSWORD=
# Deployment environment. # Deployment environment.
@@ -75,7 +96,7 @@ INIT_PASSWORD=
DEPLOY_ENV=PRODUCTION DEPLOY_ENV=PRODUCTION
# Whether to enable the version check policy. # Whether to enable the version check policy.
# If set to empty, https://updates.dify.ai will not be called for version check. # If set to empty, https://updates.dify.ai will be called for version check.
CHECK_UPDATE_URL=https://updates.dify.ai CHECK_UPDATE_URL=https://updates.dify.ai
# Used to change the OpenAI base address, default is https://api.openai.com/v1. # Used to change the OpenAI base address, default is https://api.openai.com/v1.
@@ -91,8 +112,15 @@ MIGRATION_ENABLED=true
# The default value is 300 seconds. # The default value is 300 seconds.
FILES_ACCESS_TIMEOUT=300 FILES_ACCESS_TIMEOUT=300
# Access token expiration time in minutes
ACCESS_TOKEN_EXPIRE_MINUTES=60
# Refresh token expiration time in days
REFRESH_TOKEN_EXPIRE_DAYS=30
# The maximum number of active requests for the application, where 0 means unlimited, should be a non-negative integer. # The maximum number of active requests for the application, where 0 means unlimited, should be a non-negative integer.
APP_MAX_ACTIVE_REQUESTS=0 APP_MAX_ACTIVE_REQUESTS=0
APP_MAX_EXECUTION_TIME=1200
# ------------------------------ # ------------------------------
# Container Startup Related Configuration # Container Startup Related Configuration
@@ -105,15 +133,18 @@ DIFY_BIND_ADDRESS=0.0.0.0
# API service binding port number, default 5001. # API service binding port number, default 5001.
DIFY_PORT=5001 DIFY_PORT=5001
# The number of API server workers, i.e., the number of gevent workers. # The number of API server workers, i.e., the number of workers.
# Formula: number of cpu cores x 2 + 1 # Formula: number of cpu cores x 2 + 1 for sync, 1 for Gevent
# Reference: https://docs.gunicorn.org/en/stable/design.html#how-many-workers # Reference: https://docs.gunicorn.org/en/stable/design.html#how-many-workers
SERVER_WORKER_AMOUNT= SERVER_WORKER_AMOUNT=1
# Defaults to gevent. If using windows, it can be switched to sync or solo. # Defaults to gevent. If using windows, it can be switched to sync or solo.
SERVER_WORKER_CLASS= SERVER_WORKER_CLASS=gevent
# Similar to SERVER_WORKER_CLASS. Default is gevent. # Default number of worker connections, the default is 10.
SERVER_WORKER_CONNECTIONS=10
# Similar to SERVER_WORKER_CLASS.
# If using windows, it can be switched to sync or solo. # If using windows, it can be switched to sync or solo.
CELERY_WORKER_CLASS= CELERY_WORKER_CLASS=
@@ -153,6 +184,12 @@ CELERY_MIN_WORKERS=
API_TOOL_DEFAULT_CONNECT_TIMEOUT=10 API_TOOL_DEFAULT_CONNECT_TIMEOUT=10
API_TOOL_DEFAULT_READ_TIMEOUT=60 API_TOOL_DEFAULT_READ_TIMEOUT=60
# -------------------------------
# Datasource Configuration
# --------------------------------
ENABLE_WEBSITE_JINAREADER=true
ENABLE_WEBSITE_FIRECRAWL=true
ENABLE_WEBSITE_WATERCRAWL=true
# ------------------------------ # ------------------------------
# Database Configuration # Database Configuration
@@ -213,6 +250,25 @@ REDIS_PORT=6379
REDIS_USERNAME= REDIS_USERNAME=
REDIS_PASSWORD=difyai123456 REDIS_PASSWORD=difyai123456
REDIS_USE_SSL=false REDIS_USE_SSL=false
REDIS_DB=0
# Whether to use Redis Sentinel mode.
# If set to true, the application will automatically discover and connect to the master node through Sentinel.
REDIS_USE_SENTINEL=false
# List of Redis Sentinel nodes. If Sentinel mode is enabled, provide at least one Sentinel IP and port.
# Format: `<sentinel1_ip>:<sentinel1_port>,<sentinel2_ip>:<sentinel2_port>,<sentinel3_ip>:<sentinel3_port>`
REDIS_SENTINELS=
REDIS_SENTINEL_SERVICE_NAME=
REDIS_SENTINEL_USERNAME=
REDIS_SENTINEL_PASSWORD=
REDIS_SENTINEL_SOCKET_TIMEOUT=0.1
# List of Redis Cluster nodes. If Cluster mode is enabled, provide at least one Cluster IP and port.
# Format: `<Cluster1_ip>:<Cluster1_port>,<Cluster2_ip>:<Cluster2_port>,<Cluster3_ip>:<Cluster3_port>`
REDIS_USE_CLUSTERS=false
REDIS_CLUSTERS=
REDIS_CLUSTERS_PASSWORD=
# ------------------------------ # ------------------------------
# Celery Configuration # Celery Configuration
@@ -221,9 +277,17 @@ REDIS_USE_SSL=false
# Use redis as the broker, and redis db 1 for celery broker. # Use redis as the broker, and redis db 1 for celery broker.
# Format as follows: `redis://<redis_username>:<redis_password>@<redis_host>:<redis_port>/<redis_database>` # Format as follows: `redis://<redis_username>:<redis_password>@<redis_host>:<redis_port>/<redis_database>`
# Example: redis://:difyai123456@redis:6379/1 # Example: redis://:difyai123456@redis:6379/1
# If use Redis Sentinel, format as follows: `sentinel://<sentinel_username>:<sentinel_password>@<sentinel_host>:<sentinel_port>/<redis_database>`
# Example: sentinel://localhost:26379/1;sentinel://localhost:26380/1;sentinel://localhost:26381/1
CELERY_BROKER_URL=redis://:difyai123456@redis:6379/1 CELERY_BROKER_URL=redis://:difyai123456@redis:6379/1
BROKER_USE_SSL=false BROKER_USE_SSL=false
# If you are using Redis Sentinel for high availability, configure the following settings.
CELERY_USE_SENTINEL=false
CELERY_SENTINEL_MASTER_NAME=
CELERY_SENTINEL_PASSWORD=
CELERY_SENTINEL_SOCKET_TIMEOUT=0.1
# ------------------------------ # ------------------------------
# CORS Configuration # CORS Configuration
# Used to set the front-end cross-domain access policy. # Used to set the front-end cross-domain access policy.
@@ -242,97 +306,124 @@ CONSOLE_CORS_ALLOW_ORIGINS=*
# ------------------------------ # ------------------------------
# The type of storage to use for storing user files. # The type of storage to use for storing user files.
# Supported values are `local` and `s3` and `azure-blob` and `google-storage` and `tencent-cos`, STORAGE_TYPE=opendal
# Default: `local`
STORAGE_TYPE=local # Apache OpenDAL Configuration
# The configuration for OpenDAL consists of the following format: OPENDAL_<SCHEME_NAME>_<CONFIG_NAME>.
# You can find all the service configurations (CONFIG_NAME) in the repository at: https://github.com/apache/opendal/tree/main/core/src/services.
# Dify will scan configurations starting with OPENDAL_<SCHEME_NAME> and automatically apply them.
# The scheme name for the OpenDAL storage.
OPENDAL_SCHEME=fs
# Configurations for OpenDAL Local File System.
OPENDAL_FS_ROOT=storage
# S3 Configuration # S3 Configuration
#
S3_ENDPOINT=
S3_REGION=us-east-1
S3_BUCKET_NAME=difyai
S3_ACCESS_KEY=
S3_SECRET_KEY=
# Whether to use AWS managed IAM roles for authenticating with the S3 service. # Whether to use AWS managed IAM roles for authenticating with the S3 service.
# If set to false, the access key and secret key must be provided. # If set to false, the access key and secret key must be provided.
S3_USE_AWS_MANAGED_IAM=false S3_USE_AWS_MANAGED_IAM=false
# The endpoint of the S3 service.
S3_ENDPOINT=
# The region of the S3 service.
S3_REGION=us-east-1
# The name of the S3 bucket to use for storing files.
S3_BUCKET_NAME=difyai
# The access key to use for authenticating with the S3 service.
S3_ACCESS_KEY=
# The secret key to use for authenticating with the S3 service.
S3_SECRET_KEY=
# Azure Blob Configuration # Azure Blob Configuration
# The name of the Azure Blob Storage account to use for storing files. #
AZURE_BLOB_ACCOUNT_NAME=difyai AZURE_BLOB_ACCOUNT_NAME=difyai
# The access key to use for authenticating with the Azure Blob Storage account.
AZURE_BLOB_ACCOUNT_KEY=difyai AZURE_BLOB_ACCOUNT_KEY=difyai
# The name of the Azure Blob Storage container to use for storing files.
AZURE_BLOB_CONTAINER_NAME=difyai-container AZURE_BLOB_CONTAINER_NAME=difyai-container
# The URL of the Azure Blob Storage account.
AZURE_BLOB_ACCOUNT_URL=https://<your_account_name>.blob.core.windows.net AZURE_BLOB_ACCOUNT_URL=https://<your_account_name>.blob.core.windows.net
# Google Storage Configuration # Google Storage Configuration
# The name of the Google Storage bucket to use for storing files. #
GOOGLE_STORAGE_BUCKET_NAME=your-bucket-name GOOGLE_STORAGE_BUCKET_NAME=your-bucket-name
# The service account JSON key to use for authenticating with the Google Storage service. GOOGLE_STORAGE_SERVICE_ACCOUNT_JSON_BASE64=
GOOGLE_STORAGE_SERVICE_ACCOUNT_JSON_BASE64=your-google-service-account-json-base64-string
# The Alibaba Cloud OSS configurations, # The Alibaba Cloud OSS configurations,
# only available when STORAGE_TYPE is `aliyun-oss` #
ALIYUN_OSS_BUCKET_NAME=your-bucket-name ALIYUN_OSS_BUCKET_NAME=your-bucket-name
ALIYUN_OSS_ACCESS_KEY=your-access-key ALIYUN_OSS_ACCESS_KEY=your-access-key
ALIYUN_OSS_SECRET_KEY=your-secret-key ALIYUN_OSS_SECRET_KEY=your-secret-key
ALIYUN_OSS_ENDPOINT=https://oss-ap-southeast-1-internal.aliyuncs.com ALIYUN_OSS_ENDPOINT=https://oss-ap-southeast-1-internal.aliyuncs.com
ALIYUN_OSS_REGION=ap-southeast-1 ALIYUN_OSS_REGION=ap-southeast-1
ALIYUN_OSS_AUTH_VERSION=v4 ALIYUN_OSS_AUTH_VERSION=v4
# Don't start with '/'. OSS doesn't support leading slash in object names.
ALIYUN_OSS_PATH=your-path
# Tencent COS Configuration # Tencent COS Configuration
# The name of the Tencent COS bucket to use for storing files. #
TENCENT_COS_BUCKET_NAME=your-bucket-name TENCENT_COS_BUCKET_NAME=your-bucket-name
# The secret key to use for authenticating with the Tencent COS service.
TENCENT_COS_SECRET_KEY=your-secret-key TENCENT_COS_SECRET_KEY=your-secret-key
# The secret id to use for authenticating with the Tencent COS service.
TENCENT_COS_SECRET_ID=your-secret-id TENCENT_COS_SECRET_ID=your-secret-id
# The region of the Tencent COS service.
TENCENT_COS_REGION=your-region TENCENT_COS_REGION=your-region
# The scheme of the Tencent COS service.
TENCENT_COS_SCHEME=your-scheme TENCENT_COS_SCHEME=your-scheme
# Oracle Storage Configuration
#
OCI_ENDPOINT=https://your-object-storage-namespace.compat.objectstorage.us-ashburn-1.oraclecloud.com
OCI_BUCKET_NAME=your-bucket-name
OCI_ACCESS_KEY=your-access-key
OCI_SECRET_KEY=your-secret-key
OCI_REGION=us-ashburn-1
# Huawei OBS Configuration
#
HUAWEI_OBS_BUCKET_NAME=your-bucket-name
HUAWEI_OBS_SECRET_KEY=your-secret-key
HUAWEI_OBS_ACCESS_KEY=your-access-key
HUAWEI_OBS_SERVER=your-server-url
# Volcengine TOS Configuration
#
VOLCENGINE_TOS_BUCKET_NAME=your-bucket-name
VOLCENGINE_TOS_SECRET_KEY=your-secret-key
VOLCENGINE_TOS_ACCESS_KEY=your-access-key
VOLCENGINE_TOS_ENDPOINT=your-server-url
VOLCENGINE_TOS_REGION=your-region
# Baidu OBS Storage Configuration
#
BAIDU_OBS_BUCKET_NAME=your-bucket-name
BAIDU_OBS_SECRET_KEY=your-secret-key
BAIDU_OBS_ACCESS_KEY=your-access-key
BAIDU_OBS_ENDPOINT=your-server-url
# Supabase Storage Configuration
#
SUPABASE_BUCKET_NAME=your-bucket-name
SUPABASE_API_KEY=your-access-key
SUPABASE_URL=your-server-url
# ------------------------------ # ------------------------------
# Vector Database Configuration # Vector Database Configuration
# ------------------------------ # ------------------------------
# The type of vector store to use. # The type of vector store to use.
# Supported values are `weaviate`, `qdrant`, `milvus`, `myscale`, `relyt`, `pgvector`, `chroma`, `opensearch`, `tidb_vector`, `oracle`, `tencent`, `elasticsearch`. # Supported values are `weaviate`, `qdrant`, `milvus`, `myscale`, `relyt`, `pgvector`, `pgvecto-rs`, `chroma`, `opensearch`, `oracle`, `tencent`, `elasticsearch`, `elasticsearch-ja`, `analyticdb`, `couchbase`, `vikingdb`, `oceanbase`, `opengauss`, `tablestore`,`vastbase`,`tidb`,`tidb_on_qdrant`,`baidu`,`lindorm`,`huawei_cloud`,`upstash`, `matrixone`.
VECTOR_STORE=weaviate VECTOR_STORE=weaviate
# The Weaviate endpoint URL. Only available when VECTOR_STORE is `weaviate`. # The Weaviate endpoint URL. Only available when VECTOR_STORE is `weaviate`.
WEAVIATE_ENDPOINT=http://weaviate:8080 WEAVIATE_ENDPOINT=http://weaviate:8080
# The Weaviate API key.
WEAVIATE_API_KEY=WVF5YThaHlkYwhGUSmCRgsX3tD5ngdN8pkih WEAVIATE_API_KEY=WVF5YThaHlkYwhGUSmCRgsX3tD5ngdN8pkih
# The Qdrant endpoint URL. Only available when VECTOR_STORE is `qdrant`. # The Qdrant endpoint URL. Only available when VECTOR_STORE is `qdrant`.
QDRANT_URL=http://qdrant:6333 QDRANT_URL=http://qdrant:6333
# The Qdrant API key.
QDRANT_API_KEY=difyai123456 QDRANT_API_KEY=difyai123456
# The Qdrant client timeout setting.
QDRANT_CLIENT_TIMEOUT=20 QDRANT_CLIENT_TIMEOUT=20
# The Qdrant client enable gRPC mode.
QDRANT_GRPC_ENABLED=false QDRANT_GRPC_ENABLED=false
# The Qdrant server gRPC mode PORT.
QDRANT_GRPC_PORT=6334 QDRANT_GRPC_PORT=6334
QDRANT_REPLICATION_FACTOR=1
# Milvus configuration Only available when VECTOR_STORE is `milvus`. # Milvus configuration. Only available when VECTOR_STORE is `milvus`.
# The milvus host. # The milvus uri.
MILVUS_HOST=127.0.0.1 MILVUS_URI=http://host.docker.internal:19530
# The milvus host. MILVUS_DATABASE=
MILVUS_PORT=19530 MILVUS_TOKEN=
# The milvus username. MILVUS_USER=
MILVUS_USER=root MILVUS_PASSWORD=
# The milvus password. MILVUS_ENABLE_HYBRID_SEARCH=False
MILVUS_PASSWORD=Milvus MILVUS_ANALYZER_PARAMS=
# The milvus tls switch.
MILVUS_SECURE=false
# MyScale configuration, only available when VECTOR_STORE is `myscale` # MyScale configuration, only available when VECTOR_STORE is `myscale`
# For multi-language support, please set MYSCALE_FTS_PARAMS with referring to: # For multi-language support, please set MYSCALE_FTS_PARAMS with referring to:
@@ -344,34 +435,99 @@ MYSCALE_PASSWORD=
MYSCALE_DATABASE=dify MYSCALE_DATABASE=dify
MYSCALE_FTS_PARAMS= MYSCALE_FTS_PARAMS=
# pgvector configurations, only available when VECTOR_STORE is `pgvecto-rs or pgvector` # Couchbase configurations, only available when VECTOR_STORE is `couchbase`
# The connection string must include hostname defined in the docker-compose file (couchbase-server in this case)
COUCHBASE_CONNECTION_STRING=couchbase://couchbase-server
COUCHBASE_USER=Administrator
COUCHBASE_PASSWORD=password
COUCHBASE_BUCKET_NAME=Embeddings
COUCHBASE_SCOPE_NAME=_default
# pgvector configurations, only available when VECTOR_STORE is `pgvector`
PGVECTOR_HOST=pgvector PGVECTOR_HOST=pgvector
PGVECTOR_PORT=5432 PGVECTOR_PORT=5432
PGVECTOR_USER=postgres PGVECTOR_USER=postgres
PGVECTOR_PASSWORD=difyai123456 PGVECTOR_PASSWORD=difyai123456
PGVECTOR_DATABASE=dify PGVECTOR_DATABASE=dify
PGVECTOR_MIN_CONNECTION=1
PGVECTOR_MAX_CONNECTION=5
PGVECTOR_PG_BIGM=false
PGVECTOR_PG_BIGM_VERSION=1.2-20240606
# TiDB vector configurations, only available when VECTOR_STORE is `tidb` # vastbase configurations, only available when VECTOR_STORE is `vastbase`
VASTBASE_HOST=vastbase
VASTBASE_PORT=5432
VASTBASE_USER=dify
VASTBASE_PASSWORD=Difyai123456
VASTBASE_DATABASE=dify
VASTBASE_MIN_CONNECTION=1
VASTBASE_MAX_CONNECTION=5
# pgvecto-rs configurations, only available when VECTOR_STORE is `pgvecto-rs`
PGVECTO_RS_HOST=pgvecto-rs
PGVECTO_RS_PORT=5432
PGVECTO_RS_USER=postgres
PGVECTO_RS_PASSWORD=difyai123456
PGVECTO_RS_DATABASE=dify
# analyticdb configurations, only available when VECTOR_STORE is `analyticdb`
ANALYTICDB_KEY_ID=your-ak
ANALYTICDB_KEY_SECRET=your-sk
ANALYTICDB_REGION_ID=cn-hangzhou
ANALYTICDB_INSTANCE_ID=gp-ab123456
ANALYTICDB_ACCOUNT=testaccount
ANALYTICDB_PASSWORD=testpassword
ANALYTICDB_NAMESPACE=dify
ANALYTICDB_NAMESPACE_PASSWORD=difypassword
ANALYTICDB_HOST=gp-test.aliyuncs.com
ANALYTICDB_PORT=5432
ANALYTICDB_MIN_CONNECTION=1
ANALYTICDB_MAX_CONNECTION=5
# TiDB vector configurations, only available when VECTOR_STORE is `tidb_vector`
TIDB_VECTOR_HOST=tidb TIDB_VECTOR_HOST=tidb
TIDB_VECTOR_PORT=4000 TIDB_VECTOR_PORT=4000
TIDB_VECTOR_USER=xxx.root TIDB_VECTOR_USER=
TIDB_VECTOR_PASSWORD=xxxxxx TIDB_VECTOR_PASSWORD=
TIDB_VECTOR_DATABASE=dify TIDB_VECTOR_DATABASE=dify
# Matrixone vector configurations.
MATRIXONE_HOST=matrixone
MATRIXONE_PORT=6001
MATRIXONE_USER=dump
MATRIXONE_PASSWORD=111
MATRIXONE_DATABASE=dify
# Tidb on qdrant configuration, only available when VECTOR_STORE is `tidb_on_qdrant`
TIDB_ON_QDRANT_URL=http://127.0.0.1
TIDB_ON_QDRANT_API_KEY=dify
TIDB_ON_QDRANT_CLIENT_TIMEOUT=20
TIDB_ON_QDRANT_GRPC_ENABLED=false
TIDB_ON_QDRANT_GRPC_PORT=6334
TIDB_PUBLIC_KEY=dify
TIDB_PRIVATE_KEY=dify
TIDB_API_URL=http://127.0.0.1
TIDB_IAM_API_URL=http://127.0.0.1
TIDB_REGION=regions/aws-us-east-1
TIDB_PROJECT_ID=dify
TIDB_SPEND_LIMIT=100
# Chroma configuration, only available when VECTOR_STORE is `chroma` # Chroma configuration, only available when VECTOR_STORE is `chroma`
CHROMA_HOST=127.0.0.1 CHROMA_HOST=127.0.0.1
CHROMA_PORT=8000 CHROMA_PORT=8000
CHROMA_TENANT=default_tenant CHROMA_TENANT=default_tenant
CHROMA_DATABASE=default_database CHROMA_DATABASE=default_database
CHROMA_AUTH_PROVIDER=chromadb.auth.token_authn.TokenAuthClientProvider CHROMA_AUTH_PROVIDER=chromadb.auth.token_authn.TokenAuthClientProvider
CHROMA_AUTH_CREDENTIALS=xxxxxx CHROMA_AUTH_CREDENTIALS=
# Oracle configuration, only available when VECTOR_STORE is `oracle` # Oracle configuration, only available when VECTOR_STORE is `oracle`
ORACLE_HOST=oracle
ORACLE_PORT=1521
ORACLE_USER=dify ORACLE_USER=dify
ORACLE_PASSWORD=dify ORACLE_PASSWORD=dify
ORACLE_DATABASE=FREEPDB1 ORACLE_DSN=oracle:1521/FREEPDB1
ORACLE_CONFIG_DIR=/app/api/storage/wallet
ORACLE_WALLET_LOCATION=/app/api/storage/wallet
ORACLE_WALLET_PASSWORD=dify
ORACLE_IS_AUTONOMOUS=false
# relyt configurations, only available when VECTOR_STORE is `relyt` # relyt configurations, only available when VECTOR_STORE is `relyt`
RELYT_HOST=db RELYT_HOST=db
@@ -383,9 +539,14 @@ RELYT_DATABASE=postgres
# open search configuration, only available when VECTOR_STORE is `opensearch` # open search configuration, only available when VECTOR_STORE is `opensearch`
OPENSEARCH_HOST=opensearch OPENSEARCH_HOST=opensearch
OPENSEARCH_PORT=9200 OPENSEARCH_PORT=9200
OPENSEARCH_SECURE=true
OPENSEARCH_VERIFY_CERTS=true
OPENSEARCH_AUTH_METHOD=basic
OPENSEARCH_USER=admin OPENSEARCH_USER=admin
OPENSEARCH_PASSWORD=admin OPENSEARCH_PASSWORD=admin
OPENSEARCH_SECURE=true # If using AWS managed IAM, e.g. Managed Cluster or OpenSearch Serverless
OPENSEARCH_AWS_REGION=ap-southeast-1
OPENSEARCH_AWS_SERVICE=aoss
# tencent vector configurations, only available when VECTOR_STORE is `tencent` # tencent vector configurations, only available when VECTOR_STORE is `tencent`
TENCENT_VECTOR_DB_URL=http://127.0.0.1 TENCENT_VECTOR_DB_URL=http://127.0.0.1
@@ -395,12 +556,74 @@ TENCENT_VECTOR_DB_USERNAME=dify
TENCENT_VECTOR_DB_DATABASE=dify TENCENT_VECTOR_DB_DATABASE=dify
TENCENT_VECTOR_DB_SHARD=1 TENCENT_VECTOR_DB_SHARD=1
TENCENT_VECTOR_DB_REPLICAS=2 TENCENT_VECTOR_DB_REPLICAS=2
TENCENT_VECTOR_DB_ENABLE_HYBRID_SEARCH=false
# ElasticSearch configuration, only available when VECTOR_STORE is `elasticsearch` # ElasticSearch configuration, only available when VECTOR_STORE is `elasticsearch`
ELASTICSEARCH_HOST=0.0.0.0 ELASTICSEARCH_HOST=0.0.0.0
ELASTICSEARCH_PORT=9200 ELASTICSEARCH_PORT=9200
ELASTICSEARCH_USERNAME=elastic ELASTICSEARCH_USERNAME=elastic
ELASTICSEARCH_PASSWORD=elastic ELASTICSEARCH_PASSWORD=elastic
KIBANA_PORT=5601
# baidu vector configurations, only available when VECTOR_STORE is `baidu`
BAIDU_VECTOR_DB_ENDPOINT=http://127.0.0.1:5287
BAIDU_VECTOR_DB_CONNECTION_TIMEOUT_MS=30000
BAIDU_VECTOR_DB_ACCOUNT=root
BAIDU_VECTOR_DB_API_KEY=dify
BAIDU_VECTOR_DB_DATABASE=dify
BAIDU_VECTOR_DB_SHARD=1
BAIDU_VECTOR_DB_REPLICAS=3
# VikingDB configurations, only available when VECTOR_STORE is `vikingdb`
VIKINGDB_ACCESS_KEY=your-ak
VIKINGDB_SECRET_KEY=your-sk
VIKINGDB_REGION=cn-shanghai
VIKINGDB_HOST=api-vikingdb.xxx.volces.com
VIKINGDB_SCHEMA=http
VIKINGDB_CONNECTION_TIMEOUT=30
VIKINGDB_SOCKET_TIMEOUT=30
# Lindorm configuration, only available when VECTOR_STORE is `lindorm`
LINDORM_URL=http://lindorm:30070
LINDORM_USERNAME=lindorm
LINDORM_PASSWORD=lindorm
LINDORM_QUERY_TIMEOUT=1
# OceanBase Vector configuration, only available when VECTOR_STORE is `oceanbase`
OCEANBASE_VECTOR_HOST=oceanbase
OCEANBASE_VECTOR_PORT=2881
OCEANBASE_VECTOR_USER=root@test
OCEANBASE_VECTOR_PASSWORD=difyai123456
OCEANBASE_VECTOR_DATABASE=test
OCEANBASE_CLUSTER_NAME=difyai
OCEANBASE_MEMORY_LIMIT=6G
OCEANBASE_ENABLE_HYBRID_SEARCH=false
# opengauss configurations, only available when VECTOR_STORE is `opengauss`
OPENGAUSS_HOST=opengauss
OPENGAUSS_PORT=6600
OPENGAUSS_USER=postgres
OPENGAUSS_PASSWORD=Dify@123
OPENGAUSS_DATABASE=dify
OPENGAUSS_MIN_CONNECTION=1
OPENGAUSS_MAX_CONNECTION=5
OPENGAUSS_ENABLE_PQ=false
# huawei cloud search service vector configurations, only available when VECTOR_STORE is `huawei_cloud`
HUAWEI_CLOUD_HOSTS=https://127.0.0.1:9200
HUAWEI_CLOUD_USER=admin
HUAWEI_CLOUD_PASSWORD=admin
# Upstash Vector configuration, only available when VECTOR_STORE is `upstash`
UPSTASH_VECTOR_URL=https://xxx-vector.upstash.io
UPSTASH_VECTOR_TOKEN=dify
# TableStore Vector configuration
# (only used when VECTOR_STORE is tablestore)
TABLESTORE_ENDPOINT=https://instance-name.cn-hangzhou.ots.aliyuncs.com
TABLESTORE_INSTANCE_NAME=instance-name
TABLESTORE_ACCESS_KEY_ID=xxx
TABLESTORE_ACCESS_KEY_SECRET=xxx
# ------------------------------ # ------------------------------
# Knowledge Configuration # Knowledge Configuration
@@ -412,42 +635,68 @@ UPLOAD_FILE_SIZE_LIMIT=15
# The maximum number of files that can be uploaded at a time, default 5. # The maximum number of files that can be uploaded at a time, default 5.
UPLOAD_FILE_BATCH_LIMIT=5 UPLOAD_FILE_BATCH_LIMIT=5
# ETl type, support: `dify`, `Unstructured` # ETL type, support: `dify`, `Unstructured`
# `dify` Dify's proprietary file extraction scheme # `dify` Dify's proprietary file extraction scheme
# `Unstructured` Unstructured.io file extraction scheme # `Unstructured` Unstructured.io file extraction scheme
ETL_TYPE=dify ETL_TYPE=dify
# Unstructured API path, needs to be configured when ETL_TYPE is Unstructured. # Unstructured API path and API key, needs to be configured when ETL_TYPE is Unstructured
# Or using Unstructured for document extractor node for pptx.
# For example: http://unstructured:8000/general/v0/general # For example: http://unstructured:8000/general/v0/general
UNSTRUCTURED_API_URL= UNSTRUCTURED_API_URL=
UNSTRUCTURED_API_KEY=
SCARF_NO_ANALYTICS=true
# ------------------------------
# Model Configuration
# ------------------------------
# The maximum number of tokens allowed for prompt generation.
# This setting controls the upper limit of tokens that can be used by the LLM
# when generating a prompt in the prompt generation tool.
# Default: 512 tokens.
PROMPT_GENERATION_MAX_TOKENS=512
# The maximum number of tokens allowed for code generation.
# This setting controls the upper limit of tokens that can be used by the LLM
# when generating code in the code generation tool.
# Default: 1024 tokens.
CODE_GENERATION_MAX_TOKENS=1024
# Enable or disable plugin based token counting. If disabled, token counting will return 0.
# This can improve performance by skipping token counting operations.
# Default: false (disabled).
PLUGIN_BASED_TOKEN_COUNTING_ENABLED=false
# ------------------------------ # ------------------------------
# Multi-modal Configuration # Multi-modal Configuration
# ------------------------------ # ------------------------------
# The format of the image sent when the multi-modal model is input, # The format of the image/video/audio/document sent when the multi-modal model is input,
# the default is base64, optional url. # the default is base64, optional url.
# The delay of the call in url mode will be lower than that in base64 mode. # The delay of the call in url mode will be lower than that in base64 mode.
# It is generally recommended to use the more compatible base64 mode. # It is generally recommended to use the more compatible base64 mode.
# If configured as url, you need to configure FILES_URL as an externally accessible address so that the multi-modal model can access the image. # If configured as url, you need to configure FILES_URL as an externally accessible address so that the multi-modal model can access the image/video/audio/document.
MULTIMODAL_SEND_IMAGE_FORMAT=base64 MULTIMODAL_SEND_FORMAT=base64
# Upload image file size limit, default 10M. # Upload image file size limit, default 10M.
UPLOAD_IMAGE_FILE_SIZE_LIMIT=10 UPLOAD_IMAGE_FILE_SIZE_LIMIT=10
# Upload video file size limit, default 100M.
UPLOAD_VIDEO_FILE_SIZE_LIMIT=100
# Upload audio file size limit, default 50M.
UPLOAD_AUDIO_FILE_SIZE_LIMIT=50
# ------------------------------ # ------------------------------
# Sentry Configuration # Sentry Configuration
# Used for application monitoring and error log tracking. # Used for application monitoring and error log tracking.
# ------------------------------ # ------------------------------
SENTRY_DSN=
# API Service Sentry DSN address, default is empty, when empty, # API Service Sentry DSN address, default is empty, when empty,
# all monitoring information is not reported to Sentry. # all monitoring information is not reported to Sentry.
# If not set, Sentry error reporting will be disabled. # If not set, Sentry error reporting will be disabled.
API_SENTRY_DSN= API_SENTRY_DSN=
# API Service The reporting ratio of Sentry events, if it is 0.01, it is 1%. # API Service The reporting ratio of Sentry events, if it is 0.01, it is 1%.
API_SENTRY_TRACES_SAMPLE_RATE=1.0 API_SENTRY_TRACES_SAMPLE_RATE=1.0
# API Service The reporting ratio of Sentry profiles, if it is 0.01, it is 1%. # API Service The reporting ratio of Sentry profiles, if it is 0.01, it is 1%.
API_SENTRY_PROFILES_SAMPLE_RATE=1.0 API_SENTRY_PROFILES_SAMPLE_RATE=1.0
@@ -478,15 +727,18 @@ NOTION_INTERNAL_SECRET=
# Mail related configuration # Mail related configuration
# ------------------------------ # ------------------------------
# Mail type, support: resend, smtp # Mail type, support: resend, smtp, sendgrid
MAIL_TYPE=resend MAIL_TYPE=resend
# Default send from email address, if not specified # Default send from email address, if not specified
# If using SendGrid, use the 'from' field for authentication if necessary.
MAIL_DEFAULT_SEND_FROM= MAIL_DEFAULT_SEND_FROM=
# API-Key for the Resend email provider, used when MAIL_TYPE is `resend`. # API-Key for the Resend email provider, used when MAIL_TYPE is `resend`.
RESEND_API_URL=https://api.resend.com
RESEND_API_KEY=your-resend-api-key RESEND_API_KEY=your-resend-api-key
# SMTP server configuration, used when MAIL_TYPE is `smtp` # SMTP server configuration, used when MAIL_TYPE is `smtp`
SMTP_SERVER= SMTP_SERVER=
SMTP_PORT=465 SMTP_PORT=465
@@ -495,43 +747,91 @@ SMTP_PASSWORD=
SMTP_USE_TLS=true SMTP_USE_TLS=true
SMTP_OPPORTUNISTIC_TLS=false SMTP_OPPORTUNISTIC_TLS=false
# Sendgid configuration
SENDGRID_API_KEY=
# ------------------------------ # ------------------------------
# Others Configuration # Others Configuration
# ------------------------------ # ------------------------------
# Maximum length of segmentation tokens for indexing # Maximum length of segmentation tokens for indexing
INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH=1000 INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH=4000
# Member invitation link valid time (hours), # Member invitation link valid time (hours),
# Default: 72. # Default: 72.
INVITE_EXPIRY_HOURS=72 INVITE_EXPIRY_HOURS=72
# Reset password token valid time (hours), # Reset password token valid time (minutes),
# Default: 24. RESET_PASSWORD_TOKEN_EXPIRY_MINUTES=5
RESET_PASSWORD_TOKEN_EXPIRY_HOURS=24
# The sandbox service endpoint. # The sandbox service endpoint.
CODE_EXECUTION_ENDPOINT=http://sandbox:8194 CODE_EXECUTION_ENDPOINT=http://sandbox:8194
CODE_EXECUTION_API_KEY=dify-sandbox
CODE_MAX_NUMBER=9223372036854775807 CODE_MAX_NUMBER=9223372036854775807
CODE_MIN_NUMBER=-9223372036854775808 CODE_MIN_NUMBER=-9223372036854775808
CODE_MAX_DEPTH=5 CODE_MAX_DEPTH=5
CODE_MAX_PRECISION=20 CODE_MAX_PRECISION=20
CODE_MAX_STRING_LENGTH=80000 CODE_MAX_STRING_LENGTH=80000
TEMPLATE_TRANSFORM_MAX_LENGTH=80000
CODE_MAX_STRING_ARRAY_LENGTH=30 CODE_MAX_STRING_ARRAY_LENGTH=30
CODE_MAX_OBJECT_ARRAY_LENGTH=30 CODE_MAX_OBJECT_ARRAY_LENGTH=30
CODE_MAX_NUMBER_ARRAY_LENGTH=1000 CODE_MAX_NUMBER_ARRAY_LENGTH=1000
CODE_EXECUTION_CONNECT_TIMEOUT=10
CODE_EXECUTION_READ_TIMEOUT=60
CODE_EXECUTION_WRITE_TIMEOUT=10
TEMPLATE_TRANSFORM_MAX_LENGTH=80000
# Workflow runtime configuration
WORKFLOW_MAX_EXECUTION_STEPS=500
WORKFLOW_MAX_EXECUTION_TIME=1200
WORKFLOW_CALL_MAX_DEPTH=5
MAX_VARIABLE_SIZE=204800
WORKFLOW_PARALLEL_DEPTH_LIMIT=3
WORKFLOW_FILE_UPLOAD_LIMIT=10
# Workflow storage configuration
# Options: rdbms, hybrid
# rdbms: Use only the relational database (default)
# hybrid: Save new data to object storage, read from both object storage and RDBMS
WORKFLOW_NODE_EXECUTION_STORAGE=rdbms
# HTTP request node in workflow configuration
HTTP_REQUEST_NODE_MAX_BINARY_SIZE=10485760
HTTP_REQUEST_NODE_MAX_TEXT_SIZE=1048576
HTTP_REQUEST_NODE_SSL_VERIFY=True
# Respect X-* headers to redirect clients
RESPECT_XFORWARD_HEADERS_ENABLED=false
# SSRF Proxy server HTTP URL # SSRF Proxy server HTTP URL
SSRF_PROXY_HTTP_URL=http://ssrf_proxy:3128 SSRF_PROXY_HTTP_URL=http://ssrf_proxy:3128
# SSRF Proxy server HTTPS URL # SSRF Proxy server HTTPS URL
SSRF_PROXY_HTTPS_URL=http://ssrf_proxy:3128 SSRF_PROXY_HTTPS_URL=http://ssrf_proxy:3128
# Maximum loop count in the workflow
LOOP_NODE_MAX_COUNT=100
# The maximum number of tools that can be used in the agent.
MAX_TOOLS_NUM=10
# Maximum number of Parallelism branches in the workflow
MAX_PARALLEL_LIMIT=10
# The maximum number of iterations for agent setting
MAX_ITERATIONS_NUM=99
# ------------------------------
# Environment Variables for web Service
# ------------------------------
# The timeout for the text generation in millisecond
TEXT_GENERATION_TIMEOUT_MS=60000
# ------------------------------ # ------------------------------
# Environment Variables for db Service # Environment Variables for db Service
# ------------------------------ # ------------------------------
PGUSER=${DB_USERNAME} # The name of the default postgres user.
POSTGRES_USER=${DB_USERNAME}
# The password for the default postgres user. # The password for the default postgres user.
POSTGRES_PASSWORD=${DB_PASSWORD} POSTGRES_PASSWORD=${DB_PASSWORD}
# The name of the default postgres database. # The name of the default postgres database.
@@ -562,7 +862,7 @@ SANDBOX_PORT=8194
# Environment Variables for weaviate Service # Environment Variables for weaviate Service
# (only used when VECTOR_STORE is weaviate) # (only used when VECTOR_STORE is weaviate)
# ------------------------------ # ------------------------------
WEAVIATE_PERSISTENCE_DATA_PATH='/var/lib/weaviate' WEAVIATE_PERSISTENCE_DATA_PATH=/var/lib/weaviate
WEAVIATE_QUERY_DEFAULTS_LIMIT=25 WEAVIATE_QUERY_DEFAULTS_LIMIT=25
WEAVIATE_AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED=true WEAVIATE_AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED=true
WEAVIATE_DEFAULT_VECTORIZER_MODULE=none WEAVIATE_DEFAULT_VECTORIZER_MODULE=none
@@ -587,7 +887,7 @@ CHROMA_IS_PERSISTENT=TRUE
# ------------------------------ # ------------------------------
# Environment Variables for Oracle Service # Environment Variables for Oracle Service
# (only used when VECTOR_STORE is Oracle) # (only used when VECTOR_STORE is oracle)
# ------------------------------ # ------------------------------
ORACLE_PWD=Dify123456 ORACLE_PWD=Dify123456
ORACLE_CHARACTERSET=AL32UTF8 ORACLE_CHARACTERSET=AL32UTF8
@@ -689,6 +989,10 @@ SSRF_HTTP_PORT=3128
SSRF_COREDUMP_DIR=/var/spool/squid SSRF_COREDUMP_DIR=/var/spool/squid
SSRF_REVERSE_PROXY_PORT=8194 SSRF_REVERSE_PROXY_PORT=8194
SSRF_SANDBOX_HOST=sandbox SSRF_SANDBOX_HOST=sandbox
SSRF_DEFAULT_TIME_OUT=5
SSRF_DEFAULT_CONNECT_TIME_OUT=5
SSRF_DEFAULT_READ_TIME_OUT=5
SSRF_DEFAULT_WRITE_TIME_OUT=5
# ------------------------------ # ------------------------------
# docker env var for specifying vector db type at startup # docker env var for specifying vector db type at startup
@@ -721,4 +1025,113 @@ POSITION_TOOL_EXCLUDES=
# Example: POSITION_PROVIDER_PINS=openai,openllm # Example: POSITION_PROVIDER_PINS=openai,openllm
POSITION_PROVIDER_PINS= POSITION_PROVIDER_PINS=
POSITION_PROVIDER_INCLUDES= POSITION_PROVIDER_INCLUDES=
POSITION_PROVIDER_EXCLUDES= POSITION_PROVIDER_EXCLUDES=
# CSP https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP
CSP_WHITELIST=
# Enable or disable create tidb service job
CREATE_TIDB_SERVICE_JOB_ENABLED=false
# Maximum number of submitted thread count in a ThreadPool for parallel node execution
MAX_SUBMIT_COUNT=100
# The maximum number of top-k value for RAG.
TOP_K_MAX_VALUE=10
# ------------------------------
# Plugin Daemon Configuration
# ------------------------------
DB_PLUGIN_DATABASE=dify_plugin
EXPOSE_PLUGIN_DAEMON_PORT=5002
PLUGIN_DAEMON_PORT=5002
PLUGIN_DAEMON_KEY=lYkiYYT6owG+71oLerGzA7GXCgOT++6ovaezWAjpCjf+Sjc3ZtU+qUEi
PLUGIN_DAEMON_URL=http://plugin_daemon:5002
PLUGIN_MAX_PACKAGE_SIZE=52428800
PLUGIN_PPROF_ENABLED=false
PLUGIN_DEBUGGING_HOST=0.0.0.0
PLUGIN_DEBUGGING_PORT=5003
EXPOSE_PLUGIN_DEBUGGING_HOST=localhost
EXPOSE_PLUGIN_DEBUGGING_PORT=5003
# If this key is changed, DIFY_INNER_API_KEY in plugin_daemon service must also be updated or agent node will fail.
PLUGIN_DIFY_INNER_API_KEY=QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1
PLUGIN_DIFY_INNER_API_URL=http://api:5001
ENDPOINT_URL_TEMPLATE=http://localhost/e/{hook_id}
MARKETPLACE_ENABLED=true
MARKETPLACE_API_URL=https://marketplace.dify.ai
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 aliyun_oss volcengine_tos
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=false
PLUGIN_S3_USE_AWS_MANAGED_IAM=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=
# ------------------------------
# OTLP Collector Configuration
# ------------------------------
ENABLE_OTEL=false
OTLP_BASE_ENDPOINT=http://localhost:4318
OTLP_API_KEY=
OTEL_EXPORTER_OTLP_PROTOCOL=
OTEL_EXPORTER_TYPE=otlp
OTEL_SAMPLING_RATE=0.1
OTEL_BATCH_EXPORT_SCHEDULE_DELAY=5000
OTEL_MAX_QUEUE_SIZE=2048
OTEL_MAX_EXPORT_BATCH_SIZE=512
OTEL_METRIC_EXPORT_INTERVAL=60000
OTEL_BATCH_EXPORT_TIMEOUT=10000
OTEL_METRIC_EXPORT_TIMEOUT=30000
# Prevent Clickjacking
ALLOW_EMBED=false
# Dataset queue monitor configuration
QUEUE_MONITOR_THRESHOLD=200
# You can configure multiple ones, separated by commas. eg: test1@dify.ai,test2@dify.ai
QUEUE_MONITOR_ALERT_EMAILS=
# Monitor interval in minutes, default is 30 minutes
QUEUE_MONITOR_INTERVAL=30
+13 -6
View File
@@ -14,7 +14,6 @@ Welcome to the new `docker` directory for deploying Dify using Docker Compose. T
- **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`
@@ -27,7 +26,10 @@ Welcome to the new `docker` directory for deploying Dify using Docker Compose. T
- 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**: 4. **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.
5. **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
@@ -36,7 +38,8 @@ Welcome to the new `docker` directory for deploying Dify using Docker Compose. T
- 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**: 2. **Running Middleware Services**:
- Execute `docker-compose -f docker-compose.middleware.yaml up -d` to start the middleware services. - Navigate to the `docker` directory.
- Execute `docker compose -f docker-compose.middleware.yaml --profile weaviate -p dify up -d` to start the middleware services. (Change the profile to other vector database if you are not using weaviate)
### Migration for Existing Users ### Migration for Existing Users
@@ -54,7 +57,7 @@ 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
@@ -83,12 +86,16 @@ The `.env.example` file provided in the Docker setup is extensive and covers a w
7. **Vector Database Configuration**: 7. **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_HOST`. - Specific settings for each vector store like `WEAVIATE_ENDPOINT`, `MILVUS_URI`.
8. **CORS Configuration**: 8. **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**: 9. **OpenTelemetry Configuration**:
- `ENABLE_OTEL`: Enable OpenTelemetry collector in api.
- `OTLP_BASE_ENDPOINT`: Endpoint for your OTLP exporter.
10. **Other Service-Specific Environment Variables**:
- Each service like `nginx`, `redis`, `db`, and vector databases have specific environment variables that are directly referenced in the `docker-compose.yaml`. - Each service like `nginx`, `redis`, `db`, and vector databases have specific environment variables that are directly referenced in the `docker-compose.yaml`.
### Additional Information ### Additional Information
+13 -13
View File
@@ -2,8 +2,8 @@
## 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
@@ -18,21 +18,21 @@ Use `docker-compose --profile certbot up` to use this features.
``` ```
execute command: execute command:
```shell ```shell
sudo docker network prune docker network prune
sudo docker-compose --profile certbot up --force-recreate -d docker compose --profile certbot up --force-recreate -d
``` ```
then after the containers launched: then after the containers launched:
```shell ```shell
sudo 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 `sudo docker-compose --profile certbot up` again. 2. Edit `.env` file and `docker compose --profile certbot up` again.
set `.env` value additionally set `.env` value additionally
```properties ```properties
NGINX_HTTPS_ENABLED=true NGINX_HTTPS_ENABLED=true
``` ```
execute command: execute command:
```shell ```shell
sudo 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)
@@ -42,8 +42,8 @@ Use `docker-compose --profile certbot up` to use this features.
For SSL certificates renewal, execute commands below: For SSL certificates renewal, execute commands below:
```shell ```shell
sudo docker-compose exec -it certbot /bin/sh /update-cert.sh docker compose exec -it certbot /bin/sh /update-cert.sh
sudo docker-compose exec nginx nginx -s reload docker compose exec nginx nginx -s reload
``` ```
## Options for certbot ## Options for certbot
@@ -57,14 +57,14 @@ CERTBOT_OPTIONS=--dry-run
To apply changes to `CERTBOT_OPTIONS`, regenerate the certbot container before updating the certificates. To apply changes to `CERTBOT_OPTIONS`, regenerate the certbot container before updating the certificates.
```shell ```shell
sudo docker-compose --profile certbot up -d --no-deps --force-recreate certbot docker compose --profile certbot up -d --no-deps --force-recreate certbot
sudo docker-compose exec -it certbot /bin/sh /update-cert.sh docker compose exec -it certbot /bin/sh /update-cert.sh
``` ```
Then, reload the nginx container if necessary. Then, reload the nginx container if necessary.
```shell ```shell
sudo docker-compose exec nginx nginx -s reload docker compose exec nginx nginx -s reload
``` ```
## For legacy servers ## For legacy servers
@@ -72,5 +72,5 @@ sudo docker-compose exec nginx nginx -s reload
To use cert files dir `nginx/ssl` as before, simply launch containers WITHOUT `--profile certbot` option. To use cert files dir `nginx/ssl` as before, simply launch containers WITHOUT `--profile certbot` option.
```shell ```shell
sudo docker-compose up -d docker compose up -d
``` ```
+4
View File
@@ -0,0 +1,4 @@
FROM couchbase/server:latest AS stage_base
# FROM couchbase:latest AS stage_base
COPY init-cbserver.sh /opt/couchbase/init/
RUN chmod +x /opt/couchbase/init/init-cbserver.sh
+44
View File
@@ -0,0 +1,44 @@
#!/bin/bash
# used to start couchbase server - can't get around this as docker compose only allows you to start one command - so we have to start couchbase like the standard couchbase Dockerfile would
# https://github.com/couchbase/docker/blob/master/enterprise/couchbase-server/7.2.0/Dockerfile#L88
/entrypoint.sh couchbase-server &
# track if setup is complete so we don't try to setup again
FILE=/opt/couchbase/init/setupComplete.txt
if ! [ -f "$FILE" ]; then
# used to automatically create the cluster based on environment variables
# https://docs.couchbase.com/server/current/cli/cbcli/couchbase-cli-cluster-init.html
echo $COUCHBASE_ADMINISTRATOR_USERNAME ":" $COUCHBASE_ADMINISTRATOR_PASSWORD
sleep 20s
/opt/couchbase/bin/couchbase-cli cluster-init -c 127.0.0.1 \
--cluster-username $COUCHBASE_ADMINISTRATOR_USERNAME \
--cluster-password $COUCHBASE_ADMINISTRATOR_PASSWORD \
--services data,index,query,fts \
--cluster-ramsize $COUCHBASE_RAM_SIZE \
--cluster-index-ramsize $COUCHBASE_INDEX_RAM_SIZE \
--cluster-eventing-ramsize $COUCHBASE_EVENTING_RAM_SIZE \
--cluster-fts-ramsize $COUCHBASE_FTS_RAM_SIZE \
--index-storage-setting default
sleep 2s
# used to auto create the bucket based on environment variables
# https://docs.couchbase.com/server/current/cli/cbcli/couchbase-cli-bucket-create.html
/opt/couchbase/bin/couchbase-cli bucket-create -c localhost:8091 \
--username $COUCHBASE_ADMINISTRATOR_USERNAME \
--password $COUCHBASE_ADMINISTRATOR_PASSWORD \
--bucket $COUCHBASE_BUCKET \
--bucket-ramsize $COUCHBASE_BUCKET_RAMSIZE \
--bucket-type couchbase
# create file so we know that the cluster is setup and don't run the setup again
touch $FILE
fi
# docker compose will stop the container from running unless we do this
# known issue and workaround
tail -f /dev/null
+718
View File
@@ -0,0 +1,718 @@
x-shared-env: &shared-api-worker-env
services:
# API service
api:
image: langgenius/dify-api:1.5.1
restart: always
environment:
# Use the shared environment variables.
<<: *shared-api-worker-env
# Startup mode, 'api' starts the API server.
MODE: api
SENTRY_DSN: ${API_SENTRY_DSN:-}
SENTRY_TRACES_SAMPLE_RATE: ${API_SENTRY_TRACES_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}
INNER_API_KEY_FOR_PLUGIN: ${PLUGIN_DIFY_INNER_API_KEY:-QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1}
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
volumes:
# Mount the storage directory to the container, for storing user files.
- ./volumes/app/storage:/app/api/storage
networks:
- ssrf_proxy_network
- default
# worker service
# The Celery worker for processing the queue.
worker:
image: langgenius/dify-api:1.5.1
restart: always
environment:
# Use the shared environment variables.
<<: *shared-api-worker-env
# Startup mode, 'worker' starts the Celery worker for processing the queue.
MODE: worker
SENTRY_DSN: ${API_SENTRY_DSN:-}
SENTRY_TRACES_SAMPLE_RATE: ${API_SENTRY_TRACES_SAMPLE_RATE:-1.0}
SENTRY_PROFILES_SAMPLE_RATE: ${API_SENTRY_PROFILES_SAMPLE_RATE:-1.0}
PLUGIN_MAX_PACKAGE_SIZE: ${PLUGIN_MAX_PACKAGE_SIZE:-52428800}
INNER_API_KEY_FOR_PLUGIN: ${PLUGIN_DIFY_INNER_API_KEY:-QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1}
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
volumes:
# Mount the storage directory to the container, for storing user files.
- ./volumes/app/storage:/app/api/storage
networks:
- ssrf_proxy_network
- default
# Frontend web application.
web:
image: langgenius/dify-web:1.5.1
restart: always
environment:
CONSOLE_API_URL: ${CONSOLE_API_URL:-}
APP_API_URL: ${APP_API_URL:-}
SENTRY_DSN: ${WEB_SENTRY_DSN:-}
NEXT_TELEMETRY_DISABLED: ${NEXT_TELEMETRY_DISABLED:-0}
TEXT_GENERATION_TIMEOUT_MS: ${TEXT_GENERATION_TIMEOUT_MS:-60000}
CSP_WHITELIST: ${CSP_WHITELIST:-}
ALLOW_EMBED: ${ALLOW_EMBED:-false}
MARKETPLACE_API_URL: ${MARKETPLACE_API_URL:-https://marketplace.dify.ai}
MARKETPLACE_URL: ${MARKETPLACE_URL:-https://marketplace.dify.ai}
TOP_K_MAX_VALUE: ${TOP_K_MAX_VALUE:-}
INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH: ${INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH:-}
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}
ENABLE_WEBSITE_JINAREADER: ${ENABLE_WEBSITE_JINAREADER:-true}
ENABLE_WEBSITE_FIRECRAWL: ${ENABLE_WEBSITE_FIRECRAWL:-true}
ENABLE_WEBSITE_WATERCRAWL: ${ENABLE_WEBSITE_WATERCRAWL:-true}
# The postgres database.
db:
image: postgres:15-alpine
restart: always
environment:
POSTGRES_USER: ${POSTGRES_USER:-postgres}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-difyai123456}
POSTGRES_DB: ${POSTGRES_DB:-dify}
PGDATA: ${PGDATA:-/var/lib/postgresql/data/pgdata}
command: >
postgres -c 'max_connections=${POSTGRES_MAX_CONNECTIONS:-100}'
-c 'shared_buffers=${POSTGRES_SHARED_BUFFERS:-128MB}'
-c 'work_mem=${POSTGRES_WORK_MEM:-4MB}'
-c 'maintenance_work_mem=${POSTGRES_MAINTENANCE_WORK_MEM:-64MB}'
-c 'effective_cache_size=${POSTGRES_EFFECTIVE_CACHE_SIZE:-4096MB}'
volumes:
- ./volumes/db/data:/var/lib/postgresql/data
healthcheck:
test: [ 'CMD', 'pg_isready', '-h', 'db', '-U', '${PGUSER:-postgres}', '-d', '${POSTGRES_DB:-dify}' ]
interval: 1s
timeout: 3s
retries: 60
# The redis cache.
redis:
image: redis:6-alpine
restart: always
environment:
REDISCLI_AUTH: ${REDIS_PASSWORD:-difyai123456}
volumes:
# Mount the redis data directory to the container.
- ./volumes/redis/data:/data
# Set the redis password when startup redis server.
command: redis-server --requirepass ${REDIS_PASSWORD:-difyai123456}
healthcheck:
test: [ 'CMD', 'redis-cli', 'ping' ]
# The DifySandbox
sandbox:
image: langgenius/dify-sandbox:0.2.12
restart: always
environment:
# The DifySandbox configurations
# Make sure you are changing this key for your deployment with a strong key.
# You can generate a strong key using `openssl rand -base64 42`.
API_KEY: ${SANDBOX_API_KEY:-dify-sandbox}
GIN_MODE: ${SANDBOX_GIN_MODE:-release}
WORKER_TIMEOUT: ${SANDBOX_WORKER_TIMEOUT:-15}
ENABLE_NETWORK: ${SANDBOX_ENABLE_NETWORK:-true}
HTTP_PROXY: ${SANDBOX_HTTP_PROXY:-http://ssrf_proxy:3128}
HTTPS_PROXY: ${SANDBOX_HTTPS_PROXY:-http://ssrf_proxy:3128}
SANDBOX_PORT: ${SANDBOX_PORT:-8194}
PIP_MIRROR_URL: ${PIP_MIRROR_URL:-}
volumes:
- ./volumes/sandbox/dependencies:/dependencies
- ./volumes/sandbox/conf:/conf
healthcheck:
test: [ 'CMD', 'curl', '-f', 'http://localhost:8194/health' ]
networks:
- ssrf_proxy_network
# plugin daemon
plugin_daemon:
image: langgenius/dify-plugin-daemon:0.1.3-local
restart: always
environment:
# Use the shared environment variables.
<<: *shared-api-worker-env
DB_DATABASE: ${DB_PLUGIN_DATABASE:-dify_plugin}
SERVER_PORT: ${PLUGIN_DAEMON_PORT:-5002}
SERVER_KEY: ${PLUGIN_DAEMON_KEY:-lYkiYYT6owG+71oLerGzA7GXCgOT++6ovaezWAjpCjf+Sjc3ZtU+qUEi}
MAX_PLUGIN_PACKAGE_SIZE: ${PLUGIN_MAX_PACKAGE_SIZE:-52428800}
PPROF_ENABLED: ${PLUGIN_PPROF_ENABLED:-false}
DIFY_INNER_API_URL: ${PLUGIN_DIFY_INNER_API_URL:-http://api:5001}
DIFY_INNER_API_KEY: ${PLUGIN_DIFY_INNER_API_KEY:-QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1}
PLUGIN_REMOTE_INSTALLING_HOST: ${PLUGIN_DEBUGGING_HOST:-0.0.0.0}
PLUGIN_REMOTE_INSTALLING_PORT: ${PLUGIN_DEBUGGING_PORT:-5003}
PLUGIN_WORKING_PATH: ${PLUGIN_WORKING_PATH:-/app/storage/cwd}
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_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:-}
ports:
- "${EXPOSE_PLUGIN_DEBUGGING_PORT:-5003}:${PLUGIN_DEBUGGING_PORT:-5003}"
volumes:
- ./volumes/plugin_daemon:/app/storage
depends_on:
db:
condition: service_healthy
# ssrf_proxy server
# for more information, please refer to
# https://docs.dify.ai/learn-more/faq/install-faq#18-why-is-ssrf-proxy-needed%3F
ssrf_proxy:
image: ubuntu/squid:latest
restart: always
volumes:
- ./ssrf_proxy/squid.conf.template:/etc/squid/squid.conf.template
- ./ssrf_proxy/docker-entrypoint.sh:/docker-entrypoint-mount.sh
entrypoint: [ 'sh', '-c', "cp /docker-entrypoint-mount.sh /docker-entrypoint.sh && sed -i 's/\r$$//' /docker-entrypoint.sh && chmod +x /docker-entrypoint.sh && /docker-entrypoint.sh" ]
environment:
# pls clearly modify the squid env vars to fit your network environment.
HTTP_PORT: ${SSRF_HTTP_PORT:-3128}
COREDUMP_DIR: ${SSRF_COREDUMP_DIR:-/var/spool/squid}
REVERSE_PROXY_PORT: ${SSRF_REVERSE_PROXY_PORT:-8194}
SANDBOX_HOST: ${SSRF_SANDBOX_HOST:-sandbox}
SANDBOX_PORT: ${SANDBOX_PORT:-8194}
networks:
- ssrf_proxy_network
- default
# Certbot service
# use `docker-compose --profile certbot up` to start the certbot service.
certbot:
image: certbot/certbot
profiles:
- certbot
volumes:
- ./volumes/certbot/conf:/etc/letsencrypt
- ./volumes/certbot/www:/var/www/html
- ./volumes/certbot/logs:/var/log/letsencrypt
- ./volumes/certbot/conf/live:/etc/letsencrypt/live
- ./certbot/update-cert.template.txt:/update-cert.template.txt
- ./certbot/docker-entrypoint.sh:/docker-entrypoint.sh
environment:
- CERTBOT_EMAIL=${CERTBOT_EMAIL}
- CERTBOT_DOMAIN=${CERTBOT_DOMAIN}
- CERTBOT_OPTIONS=${CERTBOT_OPTIONS:-}
entrypoint: [ '/docker-entrypoint.sh' ]
command: [ 'tail', '-f', '/dev/null' ]
# The nginx reverse proxy.
# used for reverse proxying the API service and Web service.
nginx:
image: nginx:latest
restart: always
volumes:
- ./nginx/nginx.conf.template:/etc/nginx/nginx.conf.template
- ./nginx/proxy.conf.template:/etc/nginx/proxy.conf.template
- ./nginx/https.conf.template:/etc/nginx/https.conf.template
- ./nginx/conf.d:/etc/nginx/conf.d
- ./nginx/docker-entrypoint.sh:/docker-entrypoint-mount.sh
- ./nginx/ssl:/etc/ssl # cert dir (legacy)
- ./volumes/certbot/conf/live:/etc/letsencrypt/live # cert dir (with certbot container)
- ./volumes/certbot/conf:/etc/letsencrypt
- ./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" ]
environment:
NGINX_SERVER_NAME: ${NGINX_SERVER_NAME:-_}
NGINX_HTTPS_ENABLED: ${NGINX_HTTPS_ENABLED:-false}
NGINX_SSL_PORT: ${NGINX_SSL_PORT:-443}
NGINX_PORT: ${NGINX_PORT:-80}
# You're required to add your own SSL certificates/keys to the `./nginx/ssl` directory
# 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_KEY_FILENAME: ${NGINX_SSL_CERT_KEY_FILENAME:-dify.key}
NGINX_SSL_PROTOCOLS: ${NGINX_SSL_PROTOCOLS:-TLSv1.1 TLSv1.2 TLSv1.3}
NGINX_WORKER_PROCESSES: ${NGINX_WORKER_PROCESSES:-auto}
NGINX_CLIENT_MAX_BODY_SIZE: ${NGINX_CLIENT_MAX_BODY_SIZE:-15M}
NGINX_KEEPALIVE_TIMEOUT: ${NGINX_KEEPALIVE_TIMEOUT:-65}
NGINX_PROXY_READ_TIMEOUT: ${NGINX_PROXY_READ_TIMEOUT:-3600s}
NGINX_PROXY_SEND_TIMEOUT: ${NGINX_PROXY_SEND_TIMEOUT:-3600s}
NGINX_ENABLE_CERTBOT_CHALLENGE: ${NGINX_ENABLE_CERTBOT_CHALLENGE:-false}
CERTBOT_DOMAIN: ${CERTBOT_DOMAIN:-}
depends_on:
- api
- web
ports:
- '${EXPOSE_NGINX_PORT:-80}:${NGINX_PORT:-80}'
- '${EXPOSE_NGINX_SSL_PORT:-443}:${NGINX_SSL_PORT:-443}'
# The Weaviate vector store.
weaviate:
image: semitechnologies/weaviate:1.19.0
profiles:
- ''
- weaviate
restart: always
volumes:
# Mount the Weaviate data directory to the con tainer.
- ./volumes/weaviate:/var/lib/weaviate
environment:
# The Weaviate configurations
# You can refer to the [Weaviate](https://weaviate.io/developers/weaviate/config-refs/env-vars) documentation for more information.
PERSISTENCE_DATA_PATH: ${WEAVIATE_PERSISTENCE_DATA_PATH:-/var/lib/weaviate}
QUERY_DEFAULTS_LIMIT: ${WEAVIATE_QUERY_DEFAULTS_LIMIT:-25}
AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED: ${WEAVIATE_AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED:-false}
DEFAULT_VECTORIZER_MODULE: ${WEAVIATE_DEFAULT_VECTORIZER_MODULE:-none}
CLUSTER_HOSTNAME: ${WEAVIATE_CLUSTER_HOSTNAME:-node1}
AUTHENTICATION_APIKEY_ENABLED: ${WEAVIATE_AUTHENTICATION_APIKEY_ENABLED:-true}
AUTHENTICATION_APIKEY_ALLOWED_KEYS: ${WEAVIATE_AUTHENTICATION_APIKEY_ALLOWED_KEYS:-WVF5YThaHlkYwhGUSmCRgsX3tD5ngdN8pkih}
AUTHENTICATION_APIKEY_USERS: ${WEAVIATE_AUTHENTICATION_APIKEY_USERS:-hello@dify.ai}
AUTHORIZATION_ADMINLIST_ENABLED: ${WEAVIATE_AUTHORIZATION_ADMINLIST_ENABLED:-true}
AUTHORIZATION_ADMINLIST_USERS: ${WEAVIATE_AUTHORIZATION_ADMINLIST_USERS:-hello@dify.ai}
# Qdrant vector store.
# (if used, you need to set VECTOR_STORE to qdrant in the api & worker service.)
qdrant:
image: langgenius/qdrant:v1.7.3
profiles:
- qdrant
restart: always
volumes:
- ./volumes/qdrant:/qdrant/storage
environment:
QDRANT_API_KEY: ${QDRANT_API_KEY:-difyai123456}
# The Couchbase vector store.
couchbase-server:
build: ./couchbase-server
profiles:
- couchbase
restart: always
environment:
- CLUSTER_NAME=dify_search
- COUCHBASE_ADMINISTRATOR_USERNAME=${COUCHBASE_USER:-Administrator}
- COUCHBASE_ADMINISTRATOR_PASSWORD=${COUCHBASE_PASSWORD:-password}
- COUCHBASE_BUCKET=${COUCHBASE_BUCKET_NAME:-Embeddings}
- COUCHBASE_BUCKET_RAMSIZE=512
- COUCHBASE_RAM_SIZE=2048
- COUCHBASE_EVENTING_RAM_SIZE=512
- COUCHBASE_INDEX_RAM_SIZE=512
- COUCHBASE_FTS_RAM_SIZE=1024
hostname: couchbase-server
container_name: couchbase-server
working_dir: /opt/couchbase
stdin_open: true
tty: true
entrypoint: [ "" ]
command: sh -c "/opt/couchbase/init/init-cbserver.sh"
volumes:
- ./volumes/couchbase/data:/opt/couchbase/var/lib/couchbase/data
healthcheck:
# 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" ]
interval: 10s
retries: 10
start_period: 30s
timeout: 10s
# The pgvector vector database.
pgvector:
image: pgvector/pgvector:pg16
profiles:
- pgvector
restart: always
environment:
PGUSER: ${PGVECTOR_PGUSER:-postgres}
# The password for the default postgres user.
POSTGRES_PASSWORD: ${PGVECTOR_POSTGRES_PASSWORD:-difyai123456}
# The name of the default postgres database.
POSTGRES_DB: ${PGVECTOR_POSTGRES_DB:-dify}
# postgres data directory
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/pgvector/data:/var/lib/postgresql/data
- ./pgvector/docker-entrypoint.sh:/docker-entrypoint.sh
entrypoint: [ '/docker-entrypoint.sh' ]
healthcheck:
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
timeout: 3s
retries: 30
# pgvecto-rs vector store
pgvecto-rs:
image: tensorchord/pgvecto-rs:pg16-v0.3.0
profiles:
- pgvecto-rs
restart: always
environment:
PGUSER: ${PGVECTOR_PGUSER:-postgres}
# The password for the default postgres user.
POSTGRES_PASSWORD: ${PGVECTOR_POSTGRES_PASSWORD:-difyai123456}
# The name of the default postgres database.
POSTGRES_DB: ${PGVECTOR_POSTGRES_DB:-dify}
# postgres data directory
PGDATA: ${PGVECTOR_PGDATA:-/var/lib/postgresql/data/pgdata}
volumes:
- ./volumes/pgvecto_rs/data:/var/lib/postgresql/data
healthcheck:
test: [ 'CMD', 'pg_isready' ]
interval: 1s
timeout: 3s
retries: 30
# Chroma vector database
chroma:
image: ghcr.io/chroma-core/chroma:0.5.20
profiles:
- chroma
restart: always
volumes:
- ./volumes/chroma:/chroma/chroma
environment:
CHROMA_SERVER_AUTHN_CREDENTIALS: ${CHROMA_SERVER_AUTHN_CREDENTIALS:-difyai123456}
CHROMA_SERVER_AUTHN_PROVIDER: ${CHROMA_SERVER_AUTHN_PROVIDER:-chromadb.auth.token_authn.TokenAuthenticationServerProvider}
IS_PERSISTENT: ${CHROMA_IS_PERSISTENT:-TRUE}
# 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
ports:
- "${OCEANBASE_VECTOR_PORT:-2881}:2881"
healthcheck:
test: [ 'CMD-SHELL', 'obclient -h127.0.0.1 -P2881 -uroot@test -p$${OB_TENANT_PASSWORD} -e "SELECT 1;"' ]
interval: 10s
retries: 30
start_period: 30s
timeout: 10s
# Oracle vector database
oracle:
image: container-registry.oracle.com/database/free:latest
profiles:
- oracle
restart: always
volumes:
- source: oradata
type: volume
target: /opt/oracle/oradata
- ./startupscripts:/opt/oracle/scripts/startup
environment:
ORACLE_PWD: ${ORACLE_PWD:-Dify123456}
ORACLE_CHARACTERSET: ${ORACLE_CHARACTERSET:-AL32UTF8}
# Milvus vector database services
etcd:
container_name: milvus-etcd
image: quay.io/coreos/etcd:v3.5.5
profiles:
- milvus
environment:
ETCD_AUTO_COMPACTION_MODE: ${ETCD_AUTO_COMPACTION_MODE:-revision}
ETCD_AUTO_COMPACTION_RETENTION: ${ETCD_AUTO_COMPACTION_RETENTION:-1000}
ETCD_QUOTA_BACKEND_BYTES: ${ETCD_QUOTA_BACKEND_BYTES:-4294967296}
ETCD_SNAPSHOT_COUNT: ${ETCD_SNAPSHOT_COUNT:-50000}
volumes:
- ./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
healthcheck:
test: [ 'CMD', 'etcdctl', 'endpoint', 'health' ]
interval: 30s
timeout: 20s
retries: 3
networks:
- milvus
minio:
container_name: milvus-minio
image: minio/minio:RELEASE.2023-03-20T20-16-18Z
profiles:
- milvus
environment:
MINIO_ACCESS_KEY: ${MINIO_ACCESS_KEY:-minioadmin}
MINIO_SECRET_KEY: ${MINIO_SECRET_KEY:-minioadmin}
volumes:
- ./volumes/milvus/minio:/minio_data
command: minio server /minio_data --console-address ":9001"
healthcheck:
test: [ 'CMD', 'curl', '-f', 'http://localhost:9000/minio/health/live' ]
interval: 30s
timeout: 20s
retries: 3
networks:
- milvus
milvus-standalone:
container_name: milvus-standalone
image: milvusdb/milvus:v2.5.0-beta
profiles:
- milvus
command: [ 'milvus', 'run', 'standalone' ]
environment:
ETCD_ENDPOINTS: ${ETCD_ENDPOINTS:-etcd:2379}
MINIO_ADDRESS: ${MINIO_ADDRESS:-minio:9000}
common.security.authorizationEnabled: ${MILVUS_AUTHORIZATION_ENABLED:-true}
volumes:
- ./volumes/milvus/milvus:/var/lib/milvus
healthcheck:
test: [ 'CMD', 'curl', '-f', 'http://localhost:9091/healthz' ]
interval: 30s
start_period: 90s
timeout: 20s
retries: 3
depends_on:
- etcd
- minio
ports:
- 19530:19530
- 9091:9091
networks:
- milvus
# Opensearch vector database
opensearch:
container_name: opensearch
image: opensearchproject/opensearch:latest
profiles:
- opensearch
environment:
discovery.type: ${OPENSEARCH_DISCOVERY_TYPE:-single-node}
bootstrap.memory_lock: ${OPENSEARCH_BOOTSTRAP_MEMORY_LOCK:-true}
OPENSEARCH_JAVA_OPTS: -Xms${OPENSEARCH_JAVA_OPTS_MIN:-512m} -Xmx${OPENSEARCH_JAVA_OPTS_MAX:-1024m}
OPENSEARCH_INITIAL_ADMIN_PASSWORD: ${OPENSEARCH_INITIAL_ADMIN_PASSWORD:-Qazwsxedc!@#123}
ulimits:
memlock:
soft: ${OPENSEARCH_MEMLOCK_SOFT:--1}
hard: ${OPENSEARCH_MEMLOCK_HARD:--1}
nofile:
soft: ${OPENSEARCH_NOFILE_SOFT:-65536}
hard: ${OPENSEARCH_NOFILE_HARD:-65536}
volumes:
- ./volumes/opensearch/data:/usr/share/opensearch/data
networks:
- opensearch-net
opensearch-dashboards:
container_name: opensearch-dashboards
image: opensearchproject/opensearch-dashboards:latest
profiles:
- opensearch
environment:
OPENSEARCH_HOSTS: '["https://opensearch:9200"]'
volumes:
- ./volumes/opensearch/opensearch_dashboards.yml:/usr/share/opensearch-dashboards/config/opensearch_dashboards.yml
networks:
- opensearch-net
depends_on:
- 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:
container_name: myscale
image: myscale/myscaledb:1.6.4
profiles:
- myscale
restart: always
tty: true
volumes:
- ./volumes/myscale/data:/var/lib/clickhouse
- ./volumes/myscale/log:/var/log/clickhouse-server
- ./volumes/myscale/config/users.d/custom_users_config.xml:/etc/clickhouse-server/users.d/custom_users_config.xml
ports:
- ${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/docker.html#docker-prod-prerequisites
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:8.14.3
container_name: elasticsearch
profiles:
- elasticsearch
- elasticsearch-ja
restart: always
volumes:
- ./elasticsearch/docker-entrypoint.sh:/docker-entrypoint-mount.sh
- dify_es01_data:/usr/share/elasticsearch/data
environment:
ELASTIC_PASSWORD: ${ELASTICSEARCH_PASSWORD:-elastic}
VECTOR_STORE: ${VECTOR_STORE:-}
cluster.name: dify-es-cluster
node.name: dify-es0
discovery.type: single-node
xpack.license.self_generated.type: basic
xpack.security.enabled: 'true'
xpack.security.enrollment.enabled: 'false'
xpack.security.http.ssl.enabled: 'false'
ports:
- ${ELASTICSEARCH_PORT:-9200}:9200
deploy:
resources:
limits:
memory: 2g
entrypoint: [ 'sh', '-c', "sh /docker-entrypoint-mount.sh" ]
healthcheck:
test: [ 'CMD', 'curl', '-s', 'http://localhost:9200/_cluster/health?pretty' ]
interval: 30s
timeout: 10s
retries: 50
# https://www.elastic.co/guide/en/kibana/current/docker.html
# https://www.elastic.co/guide/en/kibana/current/settings.html
kibana:
image: docker.elastic.co/kibana/kibana:8.14.3
container_name: kibana
profiles:
- elasticsearch
depends_on:
- elasticsearch
restart: always
environment:
XPACK_ENCRYPTEDSAVEDOBJECTS_ENCRYPTIONKEY: d1a66dfd-c4d3-4a0a-8290-2abcb83ab3aa
NO_PROXY: localhost,127.0.0.1,elasticsearch,kibana
XPACK_SECURITY_ENABLED: 'true'
XPACK_SECURITY_ENROLLMENT_ENABLED: 'false'
XPACK_SECURITY_HTTP_SSL_ENABLED: 'false'
XPACK_FLEET_ISAIRGAPPED: 'true'
I18N_LOCALE: zh-CN
SERVER_PORT: '5601'
ELASTICSEARCH_HOSTS: http://elasticsearch:9200
ports:
- ${KIBANA_PORT:-5601}:5601
healthcheck:
test: [ 'CMD-SHELL', 'curl -s http://localhost:5601 >/dev/null || exit 1' ]
interval: 30s
timeout: 10s
retries: 3
# unstructured .
# (if used, you need to set ETL_TYPE to Unstructured in the api & worker service.)
unstructured:
image: downloads.unstructured.io/unstructured-io/unstructured-api:latest
profiles:
- unstructured
restart: always
volumes:
- ./volumes/unstructured:/app/data
networks:
# create a network between sandbox, api and ssrf_proxy, and can not access outside.
ssrf_proxy_network:
driver: bridge
internal: true
milvus:
driver: bridge
opensearch-net:
driver: bridge
internal: true
volumes:
oradata:
dify_es01_data:
+89 -6
View File
@@ -16,26 +16,39 @@ services:
-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}'
volumes: volumes:
- ./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:
test: [ "CMD", "pg_isready" ]
interval: 1s
timeout: 3s
retries: 30
# The redis cache. # The redis cache.
redis: redis:
image: redis:6-alpine image: redis:6-alpine
restart: always restart: always
env_file:
- ./middleware.env
environment:
REDISCLI_AUTH: ${REDIS_PASSWORD:-difyai123456}
volumes: volumes:
# Mount the redis data directory to the container. # Mount the redis data directory to the container.
- ./volumes/redis/data:/data - ${REDIS_HOST_VOLUME:-./volumes/redis/data}:/data
# Set the redis password when startup redis server. # Set the redis password when startup redis server.
command: redis-server --requirepass difyai123456 command: redis-server --requirepass ${REDIS_PASSWORD:-difyai123456}
ports: ports:
- "${EXPOSE_REDIS_PORT:-6379}:6379" - "${EXPOSE_REDIS_PORT:-6379}:6379"
healthcheck:
test: [ "CMD", "redis-cli", "ping" ]
# The DifySandbox # The DifySandbox
sandbox: sandbox:
image: langgenius/dify-sandbox:0.2.6 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.
@@ -47,14 +60,81 @@ 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:
test: [ "CMD", "curl", "-f", "http://localhost:8194/health" ]
networks: networks:
- ssrf_proxy_network - ssrf_proxy_network
# plugin daemon
plugin_daemon:
image: langgenius/dify-plugin-daemon:0.1.3-local
restart: always
env_file:
- ./middleware.env
environment:
# Use the shared environment variables.
DB_HOST: ${DB_HOST:-db}
DB_PORT: ${DB_PORT:-5432}
DB_USERNAME: ${DB_USER:-postgres}
DB_PASSWORD: ${DB_PASSWORD:-difyai123456}
DB_DATABASE: ${DB_PLUGIN_DATABASE:-dify_plugin}
REDIS_HOST: ${REDIS_HOST:-redis}
REDIS_PORT: ${REDIS_PORT:-6379}
REDIS_PASSWORD: ${REDIS_PASSWORD:-difyai123456}
SERVER_PORT: ${PLUGIN_DAEMON_PORT:-5002}
SERVER_KEY: ${PLUGIN_DAEMON_KEY:-lYkiYYT6owG+71oLerGzA7GXCgOT++6ovaezWAjpCjf+Sjc3ZtU+qUEi}
MAX_PLUGIN_PACKAGE_SIZE: ${PLUGIN_MAX_PACKAGE_SIZE:-52428800}
PPROF_ENABLED: ${PLUGIN_PPROF_ENABLED:-false}
DIFY_INNER_API_URL: ${PLUGIN_DIFY_INNER_API_URL:-http://host.docker.internal:5001}
DIFY_INNER_API_KEY: ${PLUGIN_DIFY_INNER_API_KEY:-QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1}
PLUGIN_REMOTE_INSTALLING_HOST: ${PLUGIN_DEBUGGING_HOST:-0.0.0.0}
PLUGIN_REMOTE_INSTALLING_PORT: ${PLUGIN_DEBUGGING_PORT:-5003}
PLUGIN_WORKING_PATH: ${PLUGIN_WORKING_PATH:-/app/storage/cwd}
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:-}
ports:
- "${EXPOSE_PLUGIN_DAEMON_PORT:-5002}:${PLUGIN_DAEMON_PORT:-5002}"
- "${EXPOSE_PLUGIN_DEBUGGING_PORT:-5003}:${PLUGIN_DEBUGGING_PORT:-5003}"
volumes:
- ./volumes/plugin_daemon:/app/storage
# 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/self-host-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
@@ -62,6 +142,8 @@ services:
- ./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}
@@ -80,11 +162,12 @@ services:
weaviate: weaviate:
image: semitechnologies/weaviate:1.19.0 image: semitechnologies/weaviate:1.19.0
profiles: profiles:
- ""
- weaviate - weaviate
restart: always restart: always
volumes: volumes:
# Mount the Weaviate data directory to the container. # Mount the Weaviate data directory to the container.
- ./volumes/weaviate:/var/lib/weaviate - ${WEAVIATE_HOST_VOLUME:-./volumes/weaviate}:/var/lib/weaviate
env_file: env_file:
- ./middleware.env - ./middleware.env
environment: environment:
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
+25
View File
@@ -0,0 +1,25 @@
#!/bin/bash
set -e
if [ "${VECTOR_STORE}" = "elasticsearch-ja" ]; then
# Check if the ICU tokenizer plugin is installed
if ! /usr/share/elasticsearch/bin/elasticsearch-plugin list | grep -q analysis-icu; then
printf '%s\n' "Installing the ICU tokenizer plugin"
if ! /usr/share/elasticsearch/bin/elasticsearch-plugin install analysis-icu; then
printf '%s\n' "Failed to install the ICU tokenizer plugin"
exit 1
fi
fi
# Check if the Japanese language analyzer plugin is installed
if ! /usr/share/elasticsearch/bin/elasticsearch-plugin list | grep -q analysis-kuromoji; then
printf '%s\n' "Installing the Japanese language analyzer plugin"
if ! /usr/share/elasticsearch/bin/elasticsearch-plugin install analysis-kuromoji; then
printf '%s\n' "Failed to install the Japanese language analyzer plugin"
exit 1
fi
fi
fi
# Run the original entrypoint script
exec /bin/tini -- /usr/local/bin/docker-entrypoint.sh
+112
View File
@@ -0,0 +1,112 @@
#!/usr/bin/env python3
import os
import re
import sys
def parse_env_example(file_path):
"""
Parses the .env.example file and returns a dictionary with variable names as keys and default values as values.
"""
env_vars = {}
with open(file_path, "r") as f:
for line_number, line in enumerate(f, 1):
line = line.strip()
# Ignore empty lines and comments
if not line or line.startswith("#"):
continue
# Use regex to parse KEY=VALUE
match = re.match(r"^([^=]+)=(.*)$", line)
if match:
key = match.group(1).strip()
value = match.group(2).strip()
# Remove possible quotes around the value
if (value.startswith('"') and value.endswith('"')) or (
value.startswith("'") and value.endswith("'")
):
value = value[1:-1]
env_vars[key] = value
else:
print(f"Warning: Unable to parse line {line_number}: {line}")
return env_vars
def generate_shared_env_block(env_vars, anchor_name="shared-api-worker-env"):
"""
Generates a shared environment variables block as a YAML string.
"""
lines = [f"x-shared-env: &{anchor_name}"]
for key, default in env_vars.items():
if key == "COMPOSE_PROFILES":
continue
# If default value is empty, use ${KEY:-}
if default == "":
lines.append(f" {key}: ${{{key}:-}}")
else:
# If default value contains special characters, wrap it in quotes
if re.search(r"[:\s]", default):
default = f"{default}"
lines.append(f" {key}: ${{{key}:-{default}}}")
return "\n".join(lines)
def insert_shared_env(template_path, output_path, shared_env_block, header_comments):
"""
Inserts the shared environment variables block and header comments into the template file,
removing any existing x-shared-env anchors, and generates the final docker-compose.yaml file.
"""
with open(template_path, "r") as f:
template_content = f.read()
# Remove existing x-shared-env: &shared-api-worker-env lines
template_content = re.sub(
r"^x-shared-env: &shared-api-worker-env\s*\n?",
"",
template_content,
flags=re.MULTILINE,
)
# Prepare the final content with header comments and shared env block
final_content = f"{header_comments}\n{shared_env_block}\n\n{template_content}"
with open(output_path, "w") as f:
f.write(final_content)
print(f"Generated {output_path}")
def main():
env_example_path = ".env.example"
template_path = "docker-compose-template.yaml"
output_path = "docker-compose.yaml"
anchor_name = "shared-api-worker-env" # Can be modified as needed
# Define header comments to be added at the top of docker-compose.yaml
header_comments = (
"# ==================================================================\n"
"# WARNING: This file is auto-generated by generate_docker_compose\n"
"# Do not modify this file directly. Instead, update the .env.example\n"
"# or docker-compose-template.yaml and regenerate this file.\n"
"# ==================================================================\n"
)
# Check if required files exist
for path in [env_example_path, template_path]:
if not os.path.isfile(path):
print(f"Error: File {path} does not exist.")
sys.exit(1)
# Parse .env.example file
env_vars = parse_env_example(env_example_path)
if not env_vars:
print("Warning: No environment variables found in .env.example.")
# Generate shared environment variables block
shared_env_block = generate_shared_env_block(env_vars, anchor_name)
# Insert shared environment variables block and header comments into the template
insert_shared_env(template_path, output_path, shared_env_block, header_comments)
if __name__ == "__main__":
main()
+81 -2
View File
@@ -1,13 +1,14 @@
# ------------------------------ # ------------------------------
# Environment Variables for db Service # Environment Variables for db Service
# ------------------------------ # ------------------------------
PGUSER=postgres POSTGRES_USER=postgres
# The password for the default postgres user. # The password for the default postgres user.
POSTGRES_PASSWORD=difyai123456 POSTGRES_PASSWORD=difyai123456
# The name of the default postgres database. # The name of the default postgres database.
POSTGRES_DB=dify POSTGRES_DB=dify
# postgres data directory # postgres data directory
PGDATA=/var/lib/postgresql/data/pgdata PGDATA=/var/lib/postgresql/data/pgdata
PGDATA_HOST_VOLUME=./volumes/db/data
# Maximum number of connections to the database # Maximum number of connections to the database
# Default is 100 # Default is 100
@@ -39,8 +40,15 @@ 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
# -----------------------------
# Environment Variables for redis Service
# -----------------------------
REDIS_HOST_VOLUME=./volumes/redis/data
REDIS_PASSWORD=difyai123456
# ------------------------------ # ------------------------------
# Environment Variables for sandbox Service # Environment Variables for sandbox Service
# ------------------------------
SANDBOX_API_KEY=dify-sandbox SANDBOX_API_KEY=dify-sandbox
SANDBOX_GIN_MODE=release SANDBOX_GIN_MODE=release
SANDBOX_WORKER_TIMEOUT=15 SANDBOX_WORKER_TIMEOUT=15
@@ -48,7 +56,6 @@ SANDBOX_ENABLE_NETWORK=true
SANDBOX_HTTP_PROXY=http://ssrf_proxy:3128 SANDBOX_HTTP_PROXY=http://ssrf_proxy:3128
SANDBOX_HTTPS_PROXY=http://ssrf_proxy:3128 SANDBOX_HTTPS_PROXY=http://ssrf_proxy:3128
SANDBOX_PORT=8194 SANDBOX_PORT=8194
# ------------------------------
# ------------------------------ # ------------------------------
# Environment Variables for ssrf_proxy Service # Environment Variables for ssrf_proxy Service
@@ -70,6 +77,7 @@ 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_HOST_VOLUME=./volumes/weaviate
# ------------------------------ # ------------------------------
# Docker Compose Service Expose Host Port Configurations # Docker Compose Service Expose Host Port Configurations
@@ -79,3 +87,74 @@ EXPOSE_REDIS_PORT=6379
EXPOSE_SANDBOX_PORT=8194 EXPOSE_SANDBOX_PORT=8194
EXPOSE_SSRF_PROXY_PORT=3128 EXPOSE_SSRF_PROXY_PORT=3128
EXPOSE_WEAVIATE_PORT=8080 EXPOSE_WEAVIATE_PORT=8080
# ------------------------------
# Plugin Daemon Configuration
# ------------------------------
DB_PLUGIN_DATABASE=dify_plugin
EXPOSE_PLUGIN_DAEMON_PORT=5002
PLUGIN_DAEMON_PORT=5002
PLUGIN_DAEMON_KEY=lYkiYYT6owG+71oLerGzA7GXCgOT++6ovaezWAjpCjf+Sjc3ZtU+qUEi
PLUGIN_DAEMON_URL=http://host.docker.internal:5002
PLUGIN_MAX_PACKAGE_SIZE=52428800
PLUGIN_PPROF_ENABLED=false
PLUGIN_WORKING_PATH=/app/storage/cwd
ENDPOINT_URL_TEMPLATE=http://localhost:5002/e/{hook_id}
PLUGIN_DEBUGGING_PORT=5003
PLUGIN_DEBUGGING_HOST=0.0.0.0
EXPOSE_PLUGIN_DEBUGGING_HOST=localhost
EXPOSE_PLUGIN_DEBUGGING_PORT=5003
PLUGIN_DIFY_INNER_API_KEY=QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1
PLUGIN_DIFY_INNER_API_URL=http://host.docker.internal:5001
MARKETPLACE_ENABLED=true
MARKETPLACE_API_URL=https://marketplace.dify.ai
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=
@@ -24,6 +24,17 @@ server {
include proxy.conf; include proxy.conf;
} }
location /explore {
proxy_pass http://web:3000;
include proxy.conf;
}
location /e/ {
proxy_pass http://plugin_daemon:5002;
proxy_set_header Dify-Hook-Url $scheme://$host$request_uri;
include proxy.conf;
}
location / { location / {
proxy_pass http://web:3000; proxy_pass http://web:3000;
include proxy.conf; include proxy.conf;
+5 -2
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;'
+1 -1
View File
@@ -6,4 +6,4 @@ ssl_certificate_key ${SSL_CERTIFICATE_KEY_PATH};
ssl_protocols ${NGINX_SSL_PROTOCOLS}; ssl_protocols ${NGINX_SSL_PROTOCOLS};
ssl_prefer_server_ciphers on; ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m; ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m; ssl_session_timeout 10m;
+1 -1
View File
@@ -31,4 +31,4 @@ http {
client_max_body_size ${NGINX_CLIENT_MAX_BODY_SIZE}; client_max_body_size ${NGINX_CLIENT_MAX_BODY_SIZE};
include /etc/nginx/conf.d/*.conf; include /etc/nginx/conf.d/*.conf;
} }
+1
View File
@@ -3,6 +3,7 @@
proxy_set_header Host $host; proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port $server_port;
proxy_http_version 1.1; proxy_http_version 1.1;
proxy_set_header Connection ""; proxy_set_header Connection "";
proxy_buffering off; proxy_buffering 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
+7 -1
View File
@@ -7,6 +7,7 @@ acl localnet src 192.168.0.0/16 # RFC 1918 local private network (LAN)
acl localnet src fc00::/7 # RFC 4193 local private network range acl localnet src fc00::/7 # RFC 4193 local private network range
acl localnet src fe80::/10 # RFC 4291 link-local (directly plugged) machines acl localnet src fe80::/10 # RFC 4291 link-local (directly plugged) machines
acl SSL_ports port 443 acl SSL_ports port 443
# acl SSL_ports port 1025-65535 # Enable the configuration to resolve this issue: https://github.com/langgenius/dify/issues/12792
acl Safe_ports port 80 # http acl Safe_ports port 80 # http
acl Safe_ports port 21 # ftp acl Safe_ports port 21 # ftp
acl Safe_ports port 443 # https acl Safe_ports port 443 # https
@@ -18,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
@@ -41,10 +44,13 @@ refresh_pattern . 0 20% 4320
# cache_dir ufs /var/spool/squid 100 16 256 # cache_dir ufs /var/spool/squid 100 16 256
# upstream proxy, set to your own upstream proxy IP to avoid SSRF attacks # upstream proxy, set to your own upstream proxy IP to avoid SSRF attacks
# cache_peer 172.1.1.1 parent 3128 0 no-query no-digest no-netdb-exchange default # cache_peer 172.1.1.1 parent 3128 0 no-query no-digest no-netdb-exchange default
################################## Reverse Proxy To Sandbox ################################ ################################## Reverse Proxy To Sandbox ################################
http_port ${REVERSE_PROXY_PORT} accel vhost 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
+7 -7
View File
@@ -1,13 +1,13 @@
#!/usr/bin/env bash #!/usr/bin/env bash
DB_INITIALISED="/opt/oracle/oradata/dbinit" DB_INITIALIZED="/opt/oracle/oradata/dbinit"
#[ -f ${DB_INITIALISED} ] && exit #[ -f ${DB_INITIALIZED} ] && exit
#touch ${DB_INITIALISED} #touch ${DB_INITIALIZED}
if [ -f ${DB_INITIALISED} ]; then if [ -f ${DB_INITIALIZED} ]; then
echo 'File exists. Standards for have been Init' echo 'File exists. Standards for have been Init'
exit exit
else else
echo 'File does not exist. Standards for first time Strart up this DB' echo 'File does not exist. Standards for first time Start up this DB'
"$ORACLE_HOME"/bin/sqlplus -s "/ as sysdba" @"/opt/oracle/scripts/startup/init_user.script"; "$ORACLE_HOME"/bin/sqlplus -s "/ as sysdba" @"/opt/oracle/scripts/startup/init_user.script";
touch ${DB_INITIALISED} touch ${DB_INITIALIZED}
fi fi
+2 -2
View File
@@ -1,10 +1,10 @@
show pdbs; show pdbs;
ALTER SYSTEM SET PROCESSES=500 SCOPE=SPFILE; ALTER SYSTEM SET PROCESSES=500 SCOPE=SPFILE;
alter session set container= freepdb1; alter session set container= freepdb1;
create user dify identified by dify DEFAULT TABLESPACE users quota unlimited on users; create user dify identified by dify DEFAULT TABLESPACE users quota unlimited on users;
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;
/ /
+4
View File
@@ -0,0 +1,4 @@
# PD Configuration File reference:
# https://docs.pingcap.com/tidb/stable/pd-configuration-file#pd-configuration-file
[replication]
max-replicas = 1
@@ -0,0 +1,13 @@
# TiFlash tiflash-learner.toml Configuration File reference:
# https://docs.pingcap.com/tidb/stable/tiflash-configuration#configure-the-tiflash-learnertoml-file
log-file = "/logs/tiflash_tikv.log"
[server]
engine-addr = "tiflash:4030"
addr = "0.0.0.0:20280"
advertise-addr = "tiflash:20280"
status-addr = "tiflash:20292"
[storage]
data-dir = "/data/flash"
+19
View File
@@ -0,0 +1,19 @@
# TiFlash tiflash.toml Configuration File reference:
# https://docs.pingcap.com/tidb/stable/tiflash-configuration#configure-the-tiflashtoml-file
listen_host = "0.0.0.0"
path = "/data"
[flash]
tidb_status_addr = "tidb:10080"
service_addr = "tiflash:4030"
[flash.proxy]
config = "/tiflash-learner.toml"
[logger]
errorlog = "/logs/tiflash_error.log"
log = "/logs/tiflash.log"
[raft]
pd_addr = "pd0:2379"
+62
View File
@@ -0,0 +1,62 @@
services:
pd0:
image: pingcap/pd:v8.5.1
# ports:
# - "2379"
volumes:
- ./config/pd.toml:/pd.toml:ro
- ./volumes/data:/data
- ./volumes/logs:/logs
command:
- --name=pd0
- --client-urls=http://0.0.0.0:2379
- --peer-urls=http://0.0.0.0:2380
- --advertise-client-urls=http://pd0:2379
- --advertise-peer-urls=http://pd0:2380
- --initial-cluster=pd0=http://pd0:2380
- --data-dir=/data/pd
- --config=/pd.toml
- --log-file=/logs/pd.log
restart: on-failure
tikv:
image: pingcap/tikv:v8.5.1
volumes:
- ./volumes/data:/data
- ./volumes/logs:/logs
command:
- --addr=0.0.0.0:20160
- --advertise-addr=tikv:20160
- --status-addr=tikv:20180
- --data-dir=/data/tikv
- --pd=pd0:2379
- --log-file=/logs/tikv.log
depends_on:
- "pd0"
restart: on-failure
tidb:
image: pingcap/tidb:v8.5.1
# ports:
# - "4000:4000"
volumes:
- ./volumes/logs:/logs
command:
- --advertise-address=tidb
- --store=tikv
- --path=pd0:2379
- --log-file=/logs/tidb.log
depends_on:
- "tikv"
restart: on-failure
tiflash:
image: pingcap/tiflash:v8.5.1
volumes:
- ./config/tiflash.toml:/tiflash.toml:ro
- ./config/tiflash-learner.toml:/tiflash-learner.toml:ro
- ./volumes/data:/data
- ./volumes/logs:/logs
command:
- --config=/tiflash.toml
depends_on:
- "tikv"
- "tidb"
restart: on-failure
@@ -14,4 +14,4 @@
<access_management>1</access_management> <access_management>1</access_management>
</default> </default>
</users> </users>
</clickhouse> </clickhouse>
@@ -0,0 +1 @@
ALTER SYSTEM SET ob_vector_memory_limit_percentage = 30;
@@ -0,0 +1,14 @@
app:
port: 8194
debug: True
key: dify-sandbox
max_workers: 4
max_requests: 50
worker_timeout: 5
python_path: /usr/local/bin/python3
enable_network: True # please make sure there is no network risk in your environment
allowed_syscalls: # please leave it empty if you have no idea how seccomp works
proxy:
socks5: ''
http: ''
https: ''
@@ -0,0 +1,35 @@
app:
port: 8194
debug: True
key: dify-sandbox
max_workers: 4
max_requests: 50
worker_timeout: 5
python_path: /usr/local/bin/python3
python_lib_path:
- /usr/local/lib/python3.10
- /usr/lib/python3.10
- /usr/lib/python3
- /usr/lib/x86_64-linux-gnu
- /etc/ssl/certs/ca-certificates.crt
- /etc/nsswitch.conf
- /etc/hosts
- /etc/resolv.conf
- /run/systemd/resolve/stub-resolv.conf
- /run/resolvconf/resolv.conf
- /etc/localtime
- /usr/share/zoneinfo
- /etc/timezone
# add more paths if needed
python_pip_mirror_url: https://pypi.tuna.tsinghua.edu.cn/simple
nodejs_path: /usr/local/bin/node
enable_network: True
allowed_syscalls:
- 1
- 2
- 3
# add all the syscalls which you require
proxy:
socks5: ''
http: ''
https: ''
+6
View File
@@ -0,0 +1,6 @@
import utils from "../utils.js";
await utils.cloneOrPullRepo({ repo: "https://github.com/langgenius/dify.git" });
await utils.copyDir("./repo/docker", "./code");
await utils.removeContainerNames("./code/docker-compose.yaml");
await utils.removePorts("./code/docker-compose.yaml");
+705
View File
@@ -0,0 +1,705 @@
{
"name": "compose",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"dependencies": {
"execa": "^9.5.1",
"glob": "^11.0.0",
"yaml": "^2.6.1"
}
},
"node_modules/@isaacs/cliui": {
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
"integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
"license": "ISC",
"dependencies": {
"string-width": "^5.1.2",
"string-width-cjs": "npm:string-width@^4.2.0",
"strip-ansi": "^7.0.1",
"strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
"wrap-ansi": "^8.1.0",
"wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
},
"engines": {
"node": ">=12"
}
},
"node_modules/@sec-ant/readable-stream": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz",
"integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==",
"license": "MIT"
},
"node_modules/@sindresorhus/merge-streams": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz",
"integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==",
"license": "MIT",
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/ansi-regex": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
"integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/ansi-regex?sponsor=1"
}
},
"node_modules/ansi-styles": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
"integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"license": "MIT"
},
"node_modules/brace-expansion": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0"
}
},
"node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"license": "MIT",
"dependencies": {
"color-name": "~1.1.4"
},
"engines": {
"node": ">=7.0.0"
}
},
"node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"license": "MIT"
},
"node_modules/cross-spawn": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
"license": "MIT",
"dependencies": {
"path-key": "^3.1.0",
"shebang-command": "^2.0.0",
"which": "^2.0.1"
},
"engines": {
"node": ">= 8"
}
},
"node_modules/eastasianwidth": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
"license": "MIT"
},
"node_modules/emoji-regex": {
"version": "9.2.2",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
"license": "MIT"
},
"node_modules/execa": {
"version": "9.5.1",
"resolved": "https://registry.npmjs.org/execa/-/execa-9.5.1.tgz",
"integrity": "sha512-QY5PPtSonnGwhhHDNI7+3RvY285c7iuJFFB+lU+oEzMY/gEGJ808owqJsrr8Otd1E/x07po1LkUBmdAc5duPAg==",
"license": "MIT",
"dependencies": {
"@sindresorhus/merge-streams": "^4.0.0",
"cross-spawn": "^7.0.3",
"figures": "^6.1.0",
"get-stream": "^9.0.0",
"human-signals": "^8.0.0",
"is-plain-obj": "^4.1.0",
"is-stream": "^4.0.1",
"npm-run-path": "^6.0.0",
"pretty-ms": "^9.0.0",
"signal-exit": "^4.1.0",
"strip-final-newline": "^4.0.0",
"yoctocolors": "^2.0.0"
},
"engines": {
"node": "^18.19.0 || >=20.5.0"
},
"funding": {
"url": "https://github.com/sindresorhus/execa?sponsor=1"
}
},
"node_modules/figures": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz",
"integrity": "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==",
"license": "MIT",
"dependencies": {
"is-unicode-supported": "^2.0.0"
},
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/foreground-child": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz",
"integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==",
"license": "ISC",
"dependencies": {
"cross-spawn": "^7.0.0",
"signal-exit": "^4.0.1"
},
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/get-stream": {
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz",
"integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==",
"license": "MIT",
"dependencies": {
"@sec-ant/readable-stream": "^0.4.1",
"is-stream": "^4.0.1"
},
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/glob": {
"version": "11.0.0",
"resolved": "https://registry.npmjs.org/glob/-/glob-11.0.0.tgz",
"integrity": "sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g==",
"license": "ISC",
"dependencies": {
"foreground-child": "^3.1.0",
"jackspeak": "^4.0.1",
"minimatch": "^10.0.0",
"minipass": "^7.1.2",
"package-json-from-dist": "^1.0.0",
"path-scurry": "^2.0.0"
},
"bin": {
"glob": "dist/esm/bin.mjs"
},
"engines": {
"node": "20 || >=22"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/human-signals": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.0.tgz",
"integrity": "sha512-/1/GPCpDUCCYwlERiYjxoczfP0zfvZMU/OWgQPMya9AbAE24vseigFdhAMObpc8Q4lc/kjutPfUddDYyAmejnA==",
"license": "Apache-2.0",
"engines": {
"node": ">=18.18.0"
}
},
"node_modules/is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/is-plain-obj": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz",
"integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==",
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/is-stream": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz",
"integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==",
"license": "MIT",
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/is-unicode-supported": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz",
"integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==",
"license": "MIT",
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
"license": "ISC"
},
"node_modules/jackspeak": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.0.2.tgz",
"integrity": "sha512-bZsjR/iRjl1Nk1UkjGpAzLNfQtzuijhn2g+pbZb98HQ1Gk8vM9hfbxeMBP+M2/UUdwj0RqGG3mlvk2MsAqwvEw==",
"license": "BlueOak-1.0.0",
"dependencies": {
"@isaacs/cliui": "^8.0.2"
},
"engines": {
"node": "20 || >=22"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/lru-cache": {
"version": "11.0.2",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.0.2.tgz",
"integrity": "sha512-123qHRfJBmo2jXDbo/a5YOQrJoHF/GNQTLzQ5+IdK5pWpceK17yRc6ozlWd25FxvGKQbIUs91fDFkXmDHTKcyA==",
"license": "ISC",
"engines": {
"node": "20 || >=22"
}
},
"node_modules/minimatch": {
"version": "10.0.1",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz",
"integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==",
"license": "ISC",
"dependencies": {
"brace-expansion": "^2.0.1"
},
"engines": {
"node": "20 || >=22"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/minipass": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
"integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
"license": "ISC",
"engines": {
"node": ">=16 || 14 >=14.17"
}
},
"node_modules/npm-run-path": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz",
"integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==",
"license": "MIT",
"dependencies": {
"path-key": "^4.0.0",
"unicorn-magic": "^0.3.0"
},
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/npm-run-path/node_modules/path-key": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz",
"integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==",
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/package-json-from-dist": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
"integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==",
"license": "BlueOak-1.0.0"
},
"node_modules/parse-ms": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-4.0.0.tgz",
"integrity": "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==",
"license": "MIT",
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/path-key": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/path-scurry": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz",
"integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==",
"license": "BlueOak-1.0.0",
"dependencies": {
"lru-cache": "^11.0.0",
"minipass": "^7.1.2"
},
"engines": {
"node": "20 || >=22"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/pretty-ms": {
"version": "9.2.0",
"resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.2.0.tgz",
"integrity": "sha512-4yf0QO/sllf/1zbZWYnvWw3NxCQwLXKzIj0G849LSufP15BXKM0rbD2Z3wVnkMfjdn/CB0Dpp444gYAACdsplg==",
"license": "MIT",
"dependencies": {
"parse-ms": "^4.0.0"
},
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
"license": "MIT",
"dependencies": {
"shebang-regex": "^3.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/shebang-regex": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/signal-exit": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
"license": "ISC",
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/string-width": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
"integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
"license": "MIT",
"dependencies": {
"eastasianwidth": "^0.2.0",
"emoji-regex": "^9.2.2",
"strip-ansi": "^7.0.1"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/string-width-cjs": {
"name": "string-width",
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"license": "MIT",
"dependencies": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^6.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/string-width-cjs/node_modules/ansi-regex": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/string-width-cjs/node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"license": "MIT"
},
"node_modules/string-width-cjs/node_modules/strip-ansi": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"license": "MIT",
"dependencies": {
"ansi-regex": "^5.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/strip-ansi": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
"integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
"license": "MIT",
"dependencies": {
"ansi-regex": "^6.0.1"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/strip-ansi?sponsor=1"
}
},
"node_modules/strip-ansi-cjs": {
"name": "strip-ansi",
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"license": "MIT",
"dependencies": {
"ansi-regex": "^5.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/strip-ansi-cjs/node_modules/ansi-regex": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/strip-final-newline": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz",
"integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==",
"license": "MIT",
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/unicorn-magic": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz",
"integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==",
"license": "MIT",
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
"license": "ISC",
"dependencies": {
"isexe": "^2.0.0"
},
"bin": {
"node-which": "bin/node-which"
},
"engines": {
"node": ">= 8"
}
},
"node_modules/wrap-ansi": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
"integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
"license": "MIT",
"dependencies": {
"ansi-styles": "^6.1.0",
"string-width": "^5.0.1",
"strip-ansi": "^7.0.1"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
"node_modules/wrap-ansi-cjs": {
"name": "wrap-ansi",
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
"license": "MIT",
"dependencies": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
"strip-ansi": "^6.0.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
"node_modules/wrap-ansi-cjs/node_modules/ansi-regex": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/wrap-ansi-cjs/node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"license": "MIT",
"dependencies": {
"color-convert": "^2.0.1"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/wrap-ansi-cjs/node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"license": "MIT"
},
"node_modules/wrap-ansi-cjs/node_modules/string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"license": "MIT",
"dependencies": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^6.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/wrap-ansi-cjs/node_modules/strip-ansi": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"license": "MIT",
"dependencies": {
"ansi-regex": "^5.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/yaml": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.1.tgz",
"integrity": "sha512-7r0XPzioN/Q9kXBro/XPnA6kznR73DHq+GXh5ON7ZozRO6aMjbmiBuKste2wslTFkC5d1dw0GooOCepZXJ2SAg==",
"license": "ISC",
"bin": {
"yaml": "bin.mjs"
},
"engines": {
"node": ">= 14"
}
},
"node_modules/yoctocolors": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.1.tgz",
"integrity": "sha512-GQHQqAopRhwU8Kt1DDM8NjibDXHC8eoh1erhGAJPEyveY9qqVeXvVikNKrDz69sHowPMorbPUrH/mx8c50eiBQ==",
"license": "MIT",
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
}
}
}
+11
View File
@@ -0,0 +1,11 @@
{
"type": "module",
"scripts": {
"update": "node update.js"
},
"dependencies": {
"execa": "^9.5.1",
"glob": "^11.0.0",
"yaml": "^2.6.1"
}
}
+17 -5
View File
@@ -5,13 +5,15 @@ 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 NGINX_PORT=80
WEB_URL=http://${APP_DOMAIN} WEB_URL=http://${APP_DOMAIN}
DEBUG=0 DEBUG=0
SENTRY_DSN=
SENTRY_ENVIRONMENT=production
CORS_ALLOWED_ORIGINS=http://${APP_DOMAIN} CORS_ALLOWED_ORIGINS=http://${APP_DOMAIN}
API_BASE_URL=http://api:8000
#DB SETTINGS #DB SETTINGS
PGHOST=plane-db PGHOST=plane-db
@@ -28,6 +30,14 @@ REDIS_HOST=plane-redis
REDIS_PORT=6379 REDIS_PORT=6379
REDIS_URL= REDIS_URL=
# RabbitMQ Settings
RABBITMQ_HOST=plane-mq
RABBITMQ_PORT=5672
RABBITMQ_USER=plane
RABBITMQ_PASSWORD=plane
RABBITMQ_VHOST=plane
AMQP_URL=
# Secret Key # Secret Key
SECRET_KEY=60gp0byfz2dvffa45cxl20p1scy9xbpf6d8c5y0geejgkyp1b5 SECRET_KEY=60gp0byfz2dvffa45cxl20p1scy9xbpf6d8c5y0geejgkyp1b5
@@ -38,9 +48,6 @@ AWS_ACCESS_KEY_ID=access-key
AWS_SECRET_ACCESS_KEY=secret-key AWS_SECRET_ACCESS_KEY=secret-key
AWS_S3_ENDPOINT_URL=http://plane-minio:9000 AWS_S3_ENDPOINT_URL=http://plane-minio:9000
AWS_S3_BUCKET_NAME=uploads AWS_S3_BUCKET_NAME=uploads
MINIO_ROOT_USER=access-key
MINIO_ROOT_PASSWORD=secret-key
BUCKET_NAME=uploads
FILE_SIZE_LIMIT=5242880 FILE_SIZE_LIMIT=5242880
# Gunicorn Workers # Gunicorn Workers
@@ -49,3 +56,8 @@ 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
+163 -16
View File
@@ -55,14 +55,26 @@ Installing plane is a very easy and minimal step process.
- User context used must have access to docker services. In most cases, use sudo su to switch as root user - 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 - Use the terminal (or gitbash) window to run all the future steps
### Downloading Latest Stable Release ### Downloading Latest Release
``` ```
mkdir plane-selfhost mkdir plane-selfhost
cd plane-selfhost cd plane-selfhost
```
curl -fsSL -o setup.sh https://raw.githubusercontent.com/makeplane/plane/master/deploy/selfhost/install.sh #### For *Docker Compose* based setup
```
curl -fsSL -o setup.sh https://github.com/makeplane/plane/releases/latest/download/setup.sh
chmod +x setup.sh
```
#### For *Docker Swarm* based setup
```
curl -fsSL -o setup.sh https://github.com/makeplane/plane/releases/latest/download/swarm.sh
chmod +x setup.sh chmod +x setup.sh
``` ```
@@ -77,8 +89,9 @@ Lets get started by running the `./setup.sh` command.
This will prompt you with the below options. This will prompt you with the below options.
#### Docker Compose
```bash ```bash
Select a Action you want to perform: Select an Action you want to perform:
1) Install (x86_64) 1) Install (x86_64)
2) Start 2) Start
3) Stop 3) Stop
@@ -87,17 +100,42 @@ Select a Action you want to perform:
6) View Logs 6) View Logs
7) Backup Data 7) Backup Data
8) Exit 8) Exit
Action [2]: 1 Action [2]: 1
``` ```
For the 1st time setup, type "1" as action input. 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 This will create a folder `plane-app` and will download 2 files inside that
- `docker-compose.yaml` - `docker-compose.yaml`
- `plane.env` - `plane.env`
Again the `options [1-8]` will be popped up and this time hit `8` to exit. Again the `options [1-8]` will be popped up, and this time hit `8` to exit.
#### Docker Swarm
```bash
Select an Action you want to perform:
1) Deploy Stack
2) Remove Stack
3) View Stack Status
4) Redeploy Stack
5) Upgrade
6) View Logs
7) Exit
Action [3]: 1
```
For the 1st time setup, type "1" as action input.
This will create a create a folder `plane-app` and will download 2 files inside that
- `docker-compose.yaml`
- `plane.env`
Again the `options [1-7]` will be popped up, and this time hit `7` to exit.
--- ---
@@ -116,7 +154,7 @@ There are many other settings you can play with, but we suggest you configure `E
--- ---
### Continue with setup - Start Server ### Continue with setup - Start Server (Docker Compose)
Lets again run the `./setup.sh` command. You will again be prompted with the below options. This time select `2` to start the sevices Lets again run the `./setup.sh` command. You will again be prompted with the below options. This time select `2` to start the sevices
@@ -147,9 +185,11 @@ You have successfully self hosted `Plane` instance. Access the application by go
--- ---
### Stopping the Server ### Stopping the Server / Remove Stack
In case you want to make changes to `.env` variables, we suggest you to stop the services before doing that. In case you want to make changes to `plane.env` variables, we suggest you to stop the services before doing that.
#### Docker Compose
Lets again run the `./setup.sh` command. You will again be prompted with the below options. This time select `3` to stop the sevices Lets again run the `./setup.sh` command. You will again be prompted with the below options. This time select `3` to stop the sevices
@@ -171,14 +211,34 @@ If all goes well, you must see something like this
![Stop Services](images/stopped.png) ![Stop Services](images/stopped.png)
#### Docker Swarm
Lets again run the `./setup.sh` command. You will again be prompted with the below options. This time select `2` to stop the sevices
```bash
Select an Action you want to perform:
1) Deploy Stack
2) Remove Stack
3) View Stack Status
4) Redeploy Stack
5) Upgrade
6) View Logs
7) Exit
Action [3]: 2
```
If all goes well, you will see the confirmation from docker cli
--- ---
### Restarting the Server ### Restarting the Server / Redeploy Stack
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. In case you want to make changes to `plane.env` variables, without stopping the server or you noticed some abnormalies in services, you can restart the services with `RESTART` / `REDEPLOY` option.
Lets again run the `./setup.sh` command. You will again be prompted with the below options. This time select `4` to restart the sevices Lets again run the `./setup.sh` command. You will again be prompted with the below options. This time select `4` to restart the sevices
#### Docker Compose
```bash ```bash
Select a Action you want to perform: Select a Action you want to perform:
1) Install (x86_64) 1) Install (x86_64)
@@ -197,14 +257,32 @@ If all goes well, you must see something like this
![Restart Services](images/restart.png) ![Restart Services](images/restart.png)
#### Docker Swarm
```bash
1) Deploy Stack
2) Remove Stack
3) View Stack Status
4) Redeploy Stack
5) Upgrade
6) View Logs
7) Exit
Action [3]: 4
```
If all goes well, you will see the confirmation from docker cli
--- ---
### Upgrading Plane Version ### Upgrading Plane Version
It is always advised to keep Plane up to date with the latest release. 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. Lets again run the `./setup.sh` command. You will again be prompted with the below options. This time select `5` to upgrade the release.
#### Docker Compose
```bash ```bash
Select a Action you want to perform: Select a Action you want to perform:
1) Install (x86_64) 1) Install (x86_64)
@@ -231,13 +309,41 @@ Once done, choose `8` to exit from prompt.
Once done with making changes in `plane.env` file, jump on to `Start Server` Once done with making changes in `plane.env` file, jump on to `Start Server`
#### Docker Swarm
Lets again run the `./setup.sh` command. You will again be prompted with the below options. This time select `5` to upgrade the release.
```bash
1) Deploy Stack
2) Remove Stack
3) View Stack Status
4) Redeploy Stack
5) Upgrade
6) View Logs
7) Exit
Action [3]: 5
```
By choosing this, it will stop the services and then will download the latest `docker-compose.yaml` and `plane.env`.
Once done, choose `7` to exit from prompt.
> It is very important for you to validate the `plane.env` for the new changes.
Once done with making changes in `plane.env` file, jump on to `Redeploy Stack`
--- ---
### View Logs ### View Logs
There would a time when you might want to check what is happening inside the API, Worker or any other container. 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. Lets again run the `./setup.sh` command. You will again be prompted with the below options.
This time select `6` to view logs.
#### Docker Compose
```bash ```bash
Select a Action you want to perform: Select a Action you want to perform:
@@ -253,7 +359,22 @@ Select a Action you want to perform:
Action [2]: 6 Action [2]: 6
``` ```
#### Docker Swarm
```bash
1) Deploy Stack
2) Remove Stack
3) View Stack Status
4) Redeploy Stack
5) Upgrade
6) View Logs
7) Exit
Action [3]: 6
```
#### Service Menu Options for Logs
This will further open sub-menu with list of services This will further open sub-menu with list of services
```bash ```bash
Select a Service you want to view the logs for: Select a Service you want to view the logs for:
@@ -267,9 +388,10 @@ Select a Service you want to view the logs for:
8) Redis 8) Redis
9) Postgres 9) Postgres
10) Minio 10) Minio
11) RabbitMQ
0) Back to Main Menu 0) Back to Main Menu
Service: Service: 3
``` ```
Select any of the service to view the logs e.g. `3`. Expect something similar to this Select any of the service to view the logs e.g. `3`. Expect something similar to this
@@ -323,7 +445,7 @@ Similarly, you can view the logs of other services.
--- ---
### Backup Data ### Backup Data (Docker Compose)
There would a time when you might want to backup your data from docker volumes to external storage like S3 or drives. There would a time when you might want to backup your data from docker volumes to external storage like S3 or drives.
@@ -355,7 +477,7 @@ Backup completed successfully. Backup files are stored in /....../plane-app/back
--- ---
### Restore Data ### Restore Data (Docker Compose)
When you want to restore the previously backed-up data, follow the instructions below. When you want to restore the previously backed-up data, follow the instructions below.
@@ -364,7 +486,7 @@ When you want to restore the previously backed-up data, follow the instructions
1. Download the restore script using the command below. We suggest downloading it in the same folder as `setup.sh`. 1. Download the restore script using the command below. We suggest downloading it in the same folder as `setup.sh`.
```bash ```bash
curl -fsSL -o restore.sh https://raw.githubusercontent.com/makeplane/plane/master/deploy/selfhost/restore.sh curl -fsSL -o restore.sh https://github.com/makeplane/plane/releases/latest/download/restore.sh
chmod +x restore.sh chmod +x restore.sh
``` ```
@@ -407,6 +529,31 @@ When you want to restore the previously backed-up data, follow the instructions
--- ---
### Restore for Commercial Air-Gapped (Docker Compose)
When you want to restore the previously backed-up data on Plane Commercial Air-Gapped version, follow the instructions below.
1. Download the restore script using the command below
```bash
curl -fsSL -o restore-airgapped.sh https://github.com/makeplane/plane/releases/latest/download/restore-airgapped.sh
chmod +x restore-airgapped.sh
```
1. Copy the backup folder and the `restore-airgapped.sh` to `Commercial Airgapped Edition` server
1. Make sure that Plane Commercial (Airgapped) is extracted and ready to get started. In case it is running, you would need to stop that.
1. Execute the command below to restore your data.
```bash
./restore-airgapped.sh <path to backup folder containing *.tar.gz files>
```
1. After restoration, you are ready to start Plane Commercial (Airgapped) will all your previously saved data.
---
<details> <details>
<summary><h2>Upgrading from v0.13.2 to v0.14.x</h2></summary> <summary><h2>Upgrading from v0.13.2 to v0.14.x</h2></summary>
+141 -88
View File
@@ -1,174 +1,226 @@
x-db-env: &db-env
PGHOST: ${PGHOST:-plane-db}
PGDATABASE: ${PGDATABASE:-plane}
POSTGRES_USER: ${POSTGRES_USER:-plane}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-plane}
POSTGRES_DB: ${POSTGRES_DB:-plane}
POSTGRES_PORT: ${POSTGRES_PORT:-5432}
PGDATA: ${PGDATA:-/var/lib/postgresql/data}
x-redis-env: &redis-env
REDIS_HOST: ${REDIS_HOST:-plane-redis}
REDIS_PORT: ${REDIS_PORT:-6379}
REDIS_URL: ${REDIS_URL:-redis://plane-redis:6379/}
x-minio-env: &minio-env
MINIO_ROOT_USER: ${AWS_ACCESS_KEY_ID:-access-key}
MINIO_ROOT_PASSWORD: ${AWS_SECRET_ACCESS_KEY:-secret-key}
x-aws-s3-env: &aws-s3-env
AWS_REGION: ${AWS_REGION:-}
AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID:-access-key}
AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY:-secret-key}
AWS_S3_ENDPOINT_URL: ${AWS_S3_ENDPOINT_URL:-http://plane-minio:9000}
AWS_S3_BUCKET_NAME: ${AWS_S3_BUCKET_NAME:-uploads}
x-proxy-env: &proxy-env
NGINX_PORT: ${NGINX_PORT:-80}
BUCKET_NAME: ${AWS_S3_BUCKET_NAME:-uploads}
FILE_SIZE_LIMIT: ${FILE_SIZE_LIMIT:-5242880}
x-mq-env:
# RabbitMQ Settings
&mq-env
RABBITMQ_HOST: ${RABBITMQ_HOST:-plane-mq}
RABBITMQ_PORT: ${RABBITMQ_PORT:-5672}
RABBITMQ_DEFAULT_USER: ${RABBITMQ_USER:-plane}
RABBITMQ_DEFAULT_PASS: ${RABBITMQ_PASSWORD:-plane}
RABBITMQ_DEFAULT_VHOST: ${RABBITMQ_VHOST:-plane}
RABBITMQ_VHOST: ${RABBITMQ_VHOST:-plane}
x-live-env: &live-env
API_BASE_URL: ${API_BASE_URL:-http://api:8000}
x-app-env: &app-env x-app-env: &app-env
environment: WEB_URL: ${WEB_URL:-http://localhost}
- NGINX_PORT=${NGINX_PORT:-80} DEBUG: ${DEBUG:-0}
- WEB_URL=${WEB_URL:-http://localhost} CORS_ALLOWED_ORIGINS: ${CORS_ALLOWED_ORIGINS}
- DEBUG=${DEBUG:-0} GUNICORN_WORKERS: 1
- SENTRY_DSN=${SENTRY_DSN} USE_MINIO: ${USE_MINIO:-1}
- SENTRY_ENVIRONMENT=${SENTRY_ENVIRONMENT:-"production"} DATABASE_URL: ${DATABASE_URL:-postgresql://plane:plane@plane-db/plane}
- CORS_ALLOWED_ORIGINS=${CORS_ALLOWED_ORIGINS} SECRET_KEY: ${SECRET_KEY:-60gp0byfz2dvffa45cxl20p1scy9xbpf6d8c5y0geejgkyp1b5}
# Gunicorn Workers AMQP_URL: ${AMQP_URL:-amqp://plane:plane@plane-mq:5672/plane}
- GUNICORN_WORKERS=${GUNICORN_WORKERS:-1} API_KEY_RATE_LIMIT: ${API_KEY_RATE_LIMIT:-60/minute}
#DB SETTINGS MINIO_ENDPOINT_SSL: ${MINIO_ENDPOINT_SSL:-0}
- PGHOST=${PGHOST:-plane-db}
- PGDATABASE=${PGDATABASE:-plane}
- POSTGRES_USER=${POSTGRES_USER:-plane}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-plane}
- POSTGRES_DB=${POSTGRES_DB:-plane}
- POSTGRES_PORT=${POSTGRES_PORT:-5432}
- PGDATA=${PGDATA:-/var/lib/postgresql/data}
- DATABASE_URL=${DATABASE_URL:-postgresql://plane:plane@plane-db/plane}
# REDIS SETTINGS
- REDIS_HOST=${REDIS_HOST:-plane-redis}
- REDIS_PORT=${REDIS_PORT:-6379}
- REDIS_URL=${REDIS_URL:-redis://plane-redis:6379/}
# Application secret
- SECRET_KEY=${SECRET_KEY:-60gp0byfz2dvffa45cxl20p1scy9xbpf6d8c5y0geejgkyp1b5}
# DATA STORE SETTINGS
- USE_MINIO=${USE_MINIO:-1}
- AWS_REGION=${AWS_REGION:-""}
- AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID:-"access-key"}
- AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY:-"secret-key"}
- AWS_S3_ENDPOINT_URL=${AWS_S3_ENDPOINT_URL:-http://plane-minio:9000}
- AWS_S3_BUCKET_NAME=${AWS_S3_BUCKET_NAME:-uploads}
- MINIO_ROOT_USER=${MINIO_ROOT_USER:-"access-key"}
- MINIO_ROOT_PASSWORD=${MINIO_ROOT_PASSWORD:-"secret-key"}
- BUCKET_NAME=${BUCKET_NAME:-uploads}
- FILE_SIZE_LIMIT=${FILE_SIZE_LIMIT:-5242880}
# Admin and Space URLs
- ADMIN_BASE_URL=${ADMIN_BASE_URL}
- SPACE_BASE_URL=${SPACE_BASE_URL}
- APP_BASE_URL=${APP_BASE_URL}
services: services:
web: web:
<<: *app-env image: artifacts.plane.so/makeplane/plane-frontend:${APP_RELEASE:-stable}
image: ${DOCKERHUB_USER:-makeplane}/plane-frontend:${APP_RELEASE:-stable}
platform: ${DOCKER_PLATFORM:-}
pull_policy: if_not_present
restart: unless-stopped
command: node web/server.js web command: node web/server.js web
deploy: deploy:
replicas: ${WEB_REPLICAS:-1} replicas: ${WEB_REPLICAS:-1}
restart_policy:
condition: on-failure
depends_on: depends_on:
- api - api
- worker - worker
space: space:
<<: *app-env image: artifacts.plane.so/makeplane/plane-space:${APP_RELEASE:-stable}
image: ${DOCKERHUB_USER:-makeplane}/plane-space:${APP_RELEASE:-stable}
platform: ${DOCKER_PLATFORM:-}
pull_policy: if_not_present
restart: unless-stopped
command: node space/server.js space command: node space/server.js space
deploy: deploy:
replicas: ${SPACE_REPLICAS:-1} replicas: ${SPACE_REPLICAS:-1}
restart_policy:
condition: on-failure
depends_on: depends_on:
- api - api
- worker - worker
- web - web
admin: admin:
<<: *app-env image: artifacts.plane.so/makeplane/plane-admin:${APP_RELEASE:-stable}
image: ${DOCKERHUB_USER:-makeplane}/plane-admin:${APP_RELEASE:-stable}
platform: ${DOCKER_PLATFORM:-}
pull_policy: if_not_present
restart: unless-stopped
command: node admin/server.js admin command: node admin/server.js admin
deploy: deploy:
replicas: ${ADMIN_REPLICAS:-1} replicas: ${ADMIN_REPLICAS:-1}
restart_policy:
condition: on-failure
depends_on:
- api
- web
live:
image: artifacts.plane.so/makeplane/plane-live:${APP_RELEASE:-stable}
command: node live/dist/server.js live
environment:
<<: [ *live-env ]
deploy:
replicas: ${LIVE_REPLICAS:-1}
restart_policy:
condition: on-failure
depends_on: depends_on:
- api - api
- web - web
api: api:
<<: *app-env image: artifacts.plane.so/makeplane/plane-backend:${APP_RELEASE:-stable}
image: ${DOCKERHUB_USER:-makeplane}/plane-backend:${APP_RELEASE:-stable}
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: on-failure
volumes: volumes:
- logs_api:/code/plane/logs - logs_api:/code/plane/logs
environment:
<<: [ *app-env, *db-env, *redis-env, *minio-env, *aws-s3-env, *proxy-env ]
depends_on: depends_on:
- plane-db - plane-db
- plane-redis - plane-redis
- plane-mq
worker: worker:
<<: *app-env image: artifacts.plane.so/makeplane/plane-backend:${APP_RELEASE:-stable}
image: ${DOCKERHUB_USER:-makeplane}/plane-backend:${APP_RELEASE:-stable}
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: on-failure
volumes: volumes:
- logs_worker:/code/plane/logs - logs_worker:/code/plane/logs
environment:
<<: [ *app-env, *db-env, *redis-env, *minio-env, *aws-s3-env, *proxy-env ]
depends_on: depends_on:
- api - api
- plane-db - plane-db
- plane-redis - plane-redis
- plane-mq
beat-worker: beat-worker:
<<: *app-env image: artifacts.plane.so/makeplane/plane-backend:${APP_RELEASE:-stable}
image: ${DOCKERHUB_USER:-makeplane}/plane-backend:${APP_RELEASE:-stable}
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: on-failure
volumes: volumes:
- logs_beat-worker:/code/plane/logs - logs_beat-worker:/code/plane/logs
environment:
<<: [ *app-env, *db-env, *redis-env, *minio-env, *aws-s3-env, *proxy-env ]
depends_on: depends_on:
- api - api
- plane-db - plane-db
- plane-redis - plane-redis
- plane-mq
migrator: migrator:
<<: *app-env image: artifacts.plane.so/makeplane/plane-backend:${APP_RELEASE:-stable}
image: ${DOCKERHUB_USER:-makeplane}/plane-backend:${APP_RELEASE:-stable}
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:
<<: [ *app-env, *db-env, *redis-env, *minio-env, *aws-s3-env, *proxy-env ]
depends_on: depends_on:
- plane-db - plane-db
- plane-redis - plane-redis
# Comment this if you already have a database running
plane-db: plane-db:
<<: *app-env
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: on-failure
environment:
<<: *db-env
volumes: volumes:
- pgdata:/var/lib/postgresql/data - pgdata:/var/lib/postgresql/data
plane-redis: plane-redis:
<<: *app-env
image: valkey/valkey:7.2.5-alpine image: valkey/valkey:7.2.5-alpine
pull_policy: if_not_present deploy:
restart: unless-stopped replicas: 1
restart_policy:
condition: on-failure
volumes: volumes:
- redisdata:/data - redisdata:/data
plane-mq:
image: rabbitmq:3.13.6-management-alpine
deploy:
replicas: 1
restart_policy:
condition: on-failure
environment:
<<: *mq-env
volumes:
- rabbitmq_data:/var/lib/rabbitmq
# Comment this if you using any external s3 compatible storage
plane-minio: plane-minio:
<<: *app-env
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: on-failure
environment:
<<: *minio-env
volumes: volumes:
- uploads:/export - uploads:/export
# Comment this if you already have a reverse proxy running # Comment this if you already have a reverse proxy running
proxy: proxy:
<<: *app-env image: artifacts.plane.so/makeplane/plane-proxy:${APP_RELEASE:-stable}
image: ${DOCKERHUB_USER:-makeplane}/plane-proxy:${APP_RELEASE:-stable} environment:
platform: ${DOCKER_PLATFORM:-} <<: *proxy-env
pull_policy: if_not_present deploy:
restart: unless-stopped replicas: 1
restart_policy:
condition: on-failure
depends_on: depends_on:
- web - web
- api - api
@@ -182,3 +234,4 @@ volumes:
logs_worker: logs_worker:
logs_beat-worker: logs_beat-worker:
logs_migrator: logs_migrator:
rabbitmq_data:
+153 -40
View File
@@ -4,9 +4,12 @@ BRANCH=${BRANCH:-master}
SCRIPT_DIR=$PWD SCRIPT_DIR=$PWD
SERVICE_FOLDER=plane-app SERVICE_FOLDER=plane-app
PLANE_INSTALL_DIR=$PWD/$SERVICE_FOLDER PLANE_INSTALL_DIR=$PWD/$SERVICE_FOLDER
export APP_RELEASE="stable" export APP_RELEASE=stable
export DOCKERHUB_USER=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 RELEASE_DOWNLOAD_URL="https://github.com/$GH_REPO/releases/download"
export FALLBACK_DOWNLOAD_URL="https://raw.githubusercontent.com/$GH_REPO/$BRANCH/deploy/selfhost"
CPU_ARCH=$(uname -m) CPU_ARCH=$(uname -m)
OS_NAME=$(uname) OS_NAME=$(uname)
@@ -16,13 +19,6 @@ mkdir -p $PLANE_INSTALL_DIR/archive
DOCKER_FILE_PATH=$PLANE_INSTALL_DIR/docker-compose.yaml DOCKER_FILE_PATH=$PLANE_INSTALL_DIR/docker-compose.yaml
DOCKER_ENV_PATH=$PLANE_INSTALL_DIR/plane.env DOCKER_ENV_PATH=$PLANE_INSTALL_DIR/plane.env
SED_PREFIX=()
if [ "$OS_NAME" == "Darwin" ]; then
SED_PREFIX=("-i" "")
else
SED_PREFIX=("-i")
fi
function print_header() { function print_header() {
clear clear
@@ -59,6 +55,17 @@ function spinner() {
printf " \b\b\b\b" >&2 printf " \b\b\b\b" >&2
} }
function checkLatestRelease(){
echo "Checking for the latest release..." >&2
local latest_release=$(curl -s https://api.github.com/repos/$GH_REPO/releases/latest | grep -o '"tag_name": "[^"]*"' | sed 's/"tag_name": "//;s/"//g')
if [ -z "$latest_release" ]; then
echo "Failed to check for the latest release. Exiting..." >&2
exit 1
fi
echo $latest_release
}
function initialize(){ function initialize(){
printf "Please wait while we check the availability of Docker images for the selected release ($APP_RELEASE) with ${UPPER_CPU_ARCH} support." >&2 printf "Please wait while we check the availability of Docker images for the selected release ($APP_RELEASE) with ${UPPER_CPU_ARCH} support." >&2
@@ -130,8 +137,12 @@ function updateEnvFile() {
echo "$key=$value" >> "$file" echo "$key=$value" >> "$file"
return return
else else
# if key exists, update the value if [ "$OS_NAME" == "Darwin" ]; then
sed "${SED_PREFIX[@]}" "s/^$key=.*/$key=$value/g" "$file" value=$(echo "$value" | sed 's/|/\\|/g')
sed -i '' "s|^$key=.*|$key=$value|g" "$file"
else
sed -i "s/^$key=.*/$key=$value/g" "$file"
fi
fi fi
else else
echo "File not found: $file" echo "File not found: $file"
@@ -182,7 +193,7 @@ function buildYourOwnImage(){
local PLANE_TEMP_CODE_DIR=~/tmp/plane local PLANE_TEMP_CODE_DIR=~/tmp/plane
rm -rf $PLANE_TEMP_CODE_DIR rm -rf $PLANE_TEMP_CODE_DIR
mkdir -p $PLANE_TEMP_CODE_DIR mkdir -p $PLANE_TEMP_CODE_DIR
REPO=https://github.com/makeplane/plane.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/deploy/selfhost/build.yml" "$PLANE_TEMP_CODE_DIR/build.yml"
@@ -204,6 +215,10 @@ function install() {
echo "Begin Installing Plane" echo "Begin Installing Plane"
echo "" echo ""
if [ "$APP_RELEASE" == "stable" ]; then
export APP_RELEASE=$(checkLatestRelease)
fi
local build_image=$(initialize) local build_image=$(initialize)
if [ "$build_image" == "build" ]; then if [ "$build_image" == "build" ]; then
@@ -232,8 +247,49 @@ 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
curl -H 'Cache-Control: no-cache, no-store' -s -o $PLANE_INSTALL_DIR/docker-compose.yaml https://raw.githubusercontent.com/makeplane/plane/$BRANCH/deploy/selfhost/docker-compose.yml?$(date +%s) RESPONSE=$(curl -H 'Cache-Control: no-cache, no-store' -s -w "HTTPSTATUS:%{http_code}" "$RELEASE_DOWNLOAD_URL/$APP_RELEASE/docker-compose.yml?$(date +%s)")
curl -H 'Cache-Control: no-cache, no-store' -s -o $PLANE_INSTALL_DIR/variables-upgrade.env https://raw.githubusercontent.com/makeplane/plane/$BRANCH/deploy/selfhost/variables.env?$(date +%s) BODY=$(echo "$RESPONSE" | sed -e 's/HTTPSTATUS\:.*//g')
STATUS=$(echo "$RESPONSE" | tr -d '\n' | sed -e 's/.*HTTPSTATUS://')
if [ "$STATUS" -eq 200 ]; then
echo "$BODY" > $PLANE_INSTALL_DIR/docker-compose.yaml
else
# Fallback to download from the raw github url
RESPONSE=$(curl -H 'Cache-Control: no-cache, no-store' -s -w "HTTPSTATUS:%{http_code}" "$FALLBACK_DOWNLOAD_URL/docker-compose.yml?$(date +%s)")
BODY=$(echo "$RESPONSE" | sed -e 's/HTTPSTATUS\:.*//g')
STATUS=$(echo "$RESPONSE" | tr -d '\n' | sed -e 's/.*HTTPSTATUS://')
if [ "$STATUS" -eq 200 ]; then
echo "$BODY" > $PLANE_INSTALL_DIR/docker-compose.yaml
else
echo "Failed to download docker-compose.yml. HTTP Status: $STATUS"
echo "URL: $RELEASE_DOWNLOAD_URL/$APP_RELEASE/docker-compose.yml"
mv $PLANE_INSTALL_DIR/archive/$TS.docker-compose.yaml $PLANE_INSTALL_DIR/docker-compose.yaml
exit 1
fi
fi
RESPONSE=$(curl -H 'Cache-Control: no-cache, no-store' -s -w "HTTPSTATUS:%{http_code}" "$RELEASE_DOWNLOAD_URL/$APP_RELEASE/variables.env?$(date +%s)")
BODY=$(echo "$RESPONSE" | sed -e 's/HTTPSTATUS\:.*//g')
STATUS=$(echo "$RESPONSE" | tr -d '\n' | sed -e 's/.*HTTPSTATUS://')
if [ "$STATUS" -eq 200 ]; then
echo "$BODY" > $PLANE_INSTALL_DIR/variables-upgrade.env
else
# Fallback to download from the raw github url
RESPONSE=$(curl -H 'Cache-Control: no-cache, no-store' -s -w "HTTPSTATUS:%{http_code}" "$FALLBACK_DOWNLOAD_URL/variables.env?$(date +%s)")
BODY=$(echo "$RESPONSE" | sed -e 's/HTTPSTATUS\:.*//g')
STATUS=$(echo "$RESPONSE" | tr -d '\n' | sed -e 's/.*HTTPSTATUS://')
if [ "$STATUS" -eq 200 ]; then
echo "$BODY" > $PLANE_INSTALL_DIR/variables-upgrade.env
else
echo "Failed to download variables.env. HTTP Status: $STATUS"
echo "URL: $RELEASE_DOWNLOAD_URL/$APP_RELEASE/variables.env"
mv $PLANE_INSTALL_DIR/archive/$TS.docker-compose.yaml $PLANE_INSTALL_DIR/docker-compose.yaml
exit 1
fi
fi
if [ -f "$DOCKER_ENV_PATH" ]; if [ -f "$DOCKER_ENV_PATH" ];
then then
@@ -310,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 ' ' '.')
@@ -335,6 +391,34 @@ function restartServices() {
startServices startServices
} }
function upgrade() { function upgrade() {
local latest_release=$(checkLatestRelease)
echo ""
echo "Current release: $APP_RELEASE"
if [ "$latest_release" == "$APP_RELEASE" ]; then
echo ""
echo "You are already using the latest release"
exit 0
fi
echo "Latest release: $latest_release"
echo ""
# Check for confirmation to upgrade
echo "Do you want to upgrade to the latest release ($latest_release)?"
read -p "Continue? [y/N]: " confirm
if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
echo "Exiting..."
exit 0
fi
export APP_RELEASE=$latest_release
echo "Upgrading Plane to the latest release..."
echo ""
echo "***** STOPPING SERVICES ****" echo "***** STOPPING SERVICES ****"
stopServices stopServices
@@ -373,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
@@ -397,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
@@ -415,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=plane-app" --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 'plane-app'"
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
@@ -544,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
+144
View File
@@ -0,0 +1,144 @@
#!/bin/bash
+set -euo pipefail
function print_header() {
clear
cat <<"EOF"
--------------------------------------------
____ _ /////////
| _ \| | __ _ _ __ ___ /////////
| |_) | |/ _` | '_ \ / _ \ ///// /////
| __/| | (_| | | | | __/ ///// /////
|_| |_|\__,_|_| |_|\___| ////
////
--------------------------------------------
Project management tool from the future
--------------------------------------------
EOF
}
function restoreData() {
echo ""
echo "****************************************************"
echo "We are about to restore your data from the backup files."
echo "****************************************************"
echo ""
# set the backup folder path
BACKUP_FOLDER=${1}
if [ -z "$BACKUP_FOLDER" ]; then
BACKUP_FOLDER="$PWD/backup"
read -p "Enter the backup folder path [$BACKUP_FOLDER]: " BACKUP_FOLDER
if [ -z "$BACKUP_FOLDER" ]; then
BACKUP_FOLDER="$PWD/backup"
fi
fi
# check if the backup folder exists
if [ ! -d "$BACKUP_FOLDER" ]; then
echo "Error: Backup folder not found at $BACKUP_FOLDER"
exit 1
fi
# check if there are any .tar.gz files in the backup folder
if ! ls "$BACKUP_FOLDER"/*.tar.gz 1> /dev/null 2>&1; then
echo "Error: Backup folder does not contain .tar.gz files"
exit 1
fi
echo ""
echo "Using backup folder: $BACKUP_FOLDER"
echo ""
# ask for current install path
AIRGAPPED_INSTALL_PATH="$HOME/planeairgapped"
read -p "Enter the airgapped instance install path [$AIRGAPPED_INSTALL_PATH]: " AIRGAPPED_INSTALL_PATH
if [ -z "$AIRGAPPED_INSTALL_PATH" ]; then
AIRGAPPED_INSTALL_PATH="$HOME/planeairgapped"
fi
# check if the airgapped instance install path exists
if [ ! -d "$AIRGAPPED_INSTALL_PATH" ]; then
echo "Error: Airgapped instance install path not found at $AIRGAPPED_INSTALL_PATH"
exit 1
fi
echo ""
echo "Using airgapped instance install path: $AIRGAPPED_INSTALL_PATH"
echo ""
# check if the docker-compose.yaml exists
if [ ! -f "$AIRGAPPED_INSTALL_PATH/docker-compose.yml" ]; then
echo "Error: docker-compose.yml not found at $AIRGAPPED_INSTALL_PATH/docker-compose.yml"
exit 1
fi
local dockerServiceStatus
if command -v jq &> /dev/null; then
dockerServiceStatus=$($COMPOSE_CMD ls --filter name=plane-airgapped --format=json | jq -r .[0].Status)
else
dockerServiceStatus=$($COMPOSE_CMD ls --filter name=plane-airgapped | grep -o "running" | head -n 1)
fi
if [[ $dockerServiceStatus == "running" ]]; then
echo "Plane Airgapped is running. Please STOP the Plane Airgapped before restoring data."
exit 1
fi
CURRENT_USER_ID=$(id -u)
CURRENT_GROUP_ID=$(id -g)
# if the data folder not exists, create it
if [ ! -d "$AIRGAPPED_INSTALL_PATH/data" ]; then
mkdir -p "$AIRGAPPED_INSTALL_PATH/data"
chown -R $CURRENT_USER_ID:$CURRENT_GROUP_ID "$AIRGAPPED_INSTALL_PATH/data"
fi
for BACKUP_FILE in "$BACKUP_FOLDER/*.tar.gz"; do
if [ -e "$BACKUP_FILE" ]; then
# get the basefilename without the extension
BASE_FILE_NAME=$(basename "$BACKUP_FILE" ".tar.gz")
# extract the restoreFile to the airgapped instance install path
echo "Restoring $BASE_FILE_NAME"
rm -rf "$AIRGAPPED_INSTALL_PATH/data/$BASE_FILE_NAME" || true
tar -xvzf "$BACKUP_FILE" -C "$AIRGAPPED_INSTALL_PATH/data/"
if [ $? -ne 0 ]; then
echo "Error: Failed to extract $BACKUP_FILE"
exit 1
fi
chown -R $CURRENT_USER_ID:$CURRENT_GROUP_ID "$AIRGAPPED_INSTALL_PATH/data/$BASE_FILE_NAME"
if [ $? -ne 0 ]; then
echo "Error: Failed to change ownership of $AIRGAPPED_INSTALL_PATH/data/$BASE_FILE_NAME"
exit 1
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: $0 /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
print_header
restoreData "$@"
+4 -2
View File
@@ -66,8 +66,10 @@ function restoreData() {
exit 1 exit 1
fi fi
local volume_suffix
volume_suffix="_pgdata|_redisdata|_uploads|_rabbitmq_data"
local volumes local volumes
volumes=$(docker volume ls -f "name=plane-app" --format "{{.Name}}" | grep -E "_pgdata|_redisdata|_uploads") volumes=$(docker volume ls -f "name=plane-app" --format "{{.Name}}" | grep -E "$volume_suffix")
# Check if there are any matching volumes # Check if there are any matching volumes
if [ -z "$volumes" ]; then if [ -z "$volumes" ]; then
echo ".....No volumes found starting with 'plane-app'" echo ".....No volumes found starting with 'plane-app'"
@@ -87,7 +89,7 @@ function restoreData() {
echo "Found $BACKUP_FILE" echo "Found $BACKUP_FILE"
local docVol local docVol
docVol=$(docker volume ls -f "name=$restoreVolName" --format "{{.Name}}" | grep -E "_pgdata|_redisdata|_uploads") docVol=$(docker volume ls -f "name=$restoreVolName" --format "{{.Name}}" | grep -E "$volume_suffix")
if [ -z "$docVol" ]; then if [ -z "$docVol" ]; then
echo "Skipping: No volume found with name $restoreVolName" echo "Skipping: No volume found with name $restoreVolName"
+612
View File
@@ -0,0 +1,612 @@
#!/bin/bash
BRANCH=${BRANCH:-master}
SERVICE_FOLDER=plane-app
SCRIPT_DIR=$PWD
PLANE_INSTALL_DIR=$PWD/$SERVICE_FOLDER
export APP_RELEASE="stable"
export DOCKERHUB_USER=artifacts.plane.so/makeplane
export GH_REPO=makeplane/plane
export RELEASE_DOWNLOAD_URL="https://github.com/$GH_REPO/releases/download"
export FALLBACK_DOWNLOAD_URL="https://raw.githubusercontent.com/$GH_REPO/$BRANCH/deploy/selfhost"
OS_NAME=$(uname)
# Create necessary directories
mkdir -p $PLANE_INSTALL_DIR/archive
DOCKER_FILE_PATH=$PLANE_INSTALL_DIR/docker-compose.yml
DOCKER_ENV_PATH=$PLANE_INSTALL_DIR/plane.env
function print_header() {
clear
cat <<"EOF"
--------------------------------------------
____ _ /////////
| _ \| | __ _ _ __ ___ /////////
| |_) | |/ _` | '_ \ / _ \ ///// /////
| __/| | (_| | | | | __/ ///// /////
|_| |_|\__,_|_| |_|\___| ////
////
--------------------------------------------
Project management tool from the future
--------------------------------------------
EOF
}
function checkLatestRelease(){
echo "Checking for the latest release..." >&2
local latest_release=$(curl -s https://api.github.com/repos/$GH_REPO/releases/latest | grep -o '"tag_name": "[^"]*"' | sed 's/"tag_name": "//;s/"//g')
if [ -z "$latest_release" ]; then
echo "Failed to check for the latest release. Exiting..." >&2
exit 1
fi
echo $latest_release
}
# Function to read stack name from env file
function readStackName() {
if [ -f "$DOCKER_ENV_PATH" ]; then
local saved_stack_name=$(grep "^STACK_NAME=" "$DOCKER_ENV_PATH" | cut -d'=' -f2)
if [ -n "$saved_stack_name" ]; then
stack_name=$saved_stack_name
return 1
fi
fi
return 0
}
# Function to get stack name (either from env or user input)
function getStackName() {
read -p "Enter stack name [plane]: " input_stack_name
if [ -z "$input_stack_name" ]; then
input_stack_name="plane"
fi
stack_name=$input_stack_name
updateEnvFile "STACK_NAME" "$stack_name" "$DOCKER_ENV_PATH"
echo "Using stack name: $stack_name"
}
function syncEnvFile(){
echo "Syncing environment variables..." >&2
if [ -f "$PLANE_INSTALL_DIR/plane.env.bak" ]; then
# READ keys of plane.env and update the values from plane.env.bak
while IFS= read -r line
do
# ignore if the line is empty or starts with #
if [ -z "$line" ] || [[ $line == \#* ]]; then
continue
fi
key=$(echo "$line" | cut -d'=' -f1)
value=$(getEnvValue "$key" "$PLANE_INSTALL_DIR/plane.env.bak")
if [ -n "$value" ]; then
updateEnvFile "$key" "$value" "$DOCKER_ENV_PATH"
fi
done < "$DOCKER_ENV_PATH"
value=$(getEnvValue "STACK_NAME" "$PLANE_INSTALL_DIR/plane.env.bak")
if [ -n "$value" ]; then
updateEnvFile "STACK_NAME" "$value" "$DOCKER_ENV_PATH"
fi
fi
echo "Environment variables synced successfully" >&2
rm -f $PLANE_INSTALL_DIR/plane.env.bak
}
function getEnvValue() {
local key=$1
local file=$2
if [ -z "$key" ] || [ -z "$file" ]; then
echo "Invalid arguments supplied"
exit 1
fi
if [ -f "$file" ]; then
grep -q "^$key=" "$file"
if [ $? -eq 0 ]; then
local value
value=$(grep "^$key=" "$file" | cut -d'=' -f2)
echo "$value"
else
echo ""
fi
fi
}
function updateEnvFile() {
local key=$1
local value=$2
local file=$3
if [ -z "$key" ] || [ -z "$value" ] || [ -z "$file" ]; then
echo "Invalid arguments supplied"
exit 1
fi
if [ -f "$file" ]; then
# check if key exists in the file
grep -q "^$key=" "$file"
if [ $? -ne 0 ]; then
echo "$key=$value" >> "$file"
return
else
if [ "$OS_NAME" == "Darwin" ]; then
value=$(echo "$value" | sed 's/|/\\|/g')
sed -i '' "s|^$key=.*|$key=$value|g" "$file"
else
sed -i "s/^$key=.*/$key=$value/g" "$file"
fi
fi
else
echo "File not found: $file"
exit 1
fi
}
function download() {
cd $SCRIPT_DIR || exit 1
TS=$(date +%s)
if [ -f "$PLANE_INSTALL_DIR/docker-compose.yml" ]
then
mv $PLANE_INSTALL_DIR/docker-compose.yml $PLANE_INSTALL_DIR/archive/$TS.docker-compose.yml
fi
echo $RELEASE_DOWNLOAD_URL
echo $FALLBACK_DOWNLOAD_URL
echo $APP_RELEASE
RESPONSE=$(curl -H 'Cache-Control: no-cache, no-store' -s -w "HTTPSTATUS:%{http_code}" "$RELEASE_DOWNLOAD_URL/$APP_RELEASE/docker-compose.yml?$(date +%s)")
BODY=$(echo "$RESPONSE" | sed -e 's/HTTPSTATUS\:.*//g')
STATUS=$(echo "$RESPONSE" | tr -d '\n' | sed -e 's/.*HTTPSTATUS://')
if [ "$STATUS" -eq 200 ]; then
echo "$BODY" > $PLANE_INSTALL_DIR/docker-compose.yml
else
# Fallback to download from the raw github url
RESPONSE=$(curl -H 'Cache-Control: no-cache, no-store' -s -w "HTTPSTATUS:%{http_code}" "$FALLBACK_DOWNLOAD_URL/docker-compose.yml?$(date +%s)")
BODY=$(echo "$RESPONSE" | sed -e 's/HTTPSTATUS\:.*//g')
STATUS=$(echo "$RESPONSE" | tr -d '\n' | sed -e 's/.*HTTPSTATUS://')
if [ "$STATUS" -eq 200 ]; then
echo "$BODY" > $PLANE_INSTALL_DIR/docker-compose.yml
else
echo "Failed to download docker-compose.yml. HTTP Status: $STATUS"
echo "URL: $RELEASE_DOWNLOAD_URL/$APP_RELEASE/docker-compose.yml"
mv $PLANE_INSTALL_DIR/archive/$TS.docker-compose.yml $PLANE_INSTALL_DIR/docker-compose.yml
exit 1
fi
fi
RESPONSE=$(curl -H 'Cache-Control: no-cache, no-store' -s -w "HTTPSTATUS:%{http_code}" "$RELEASE_DOWNLOAD_URL/$APP_RELEASE/variables.env?$(date +%s)")
BODY=$(echo "$RESPONSE" | sed -e 's/HTTPSTATUS\:.*//g')
STATUS=$(echo "$RESPONSE" | tr -d '\n' | sed -e 's/.*HTTPSTATUS://')
if [ "$STATUS" -eq 200 ]; then
echo "$BODY" > $PLANE_INSTALL_DIR/variables-upgrade.env
else
# Fallback to download from the raw github url
RESPONSE=$(curl -H 'Cache-Control: no-cache, no-store' -s -w "HTTPSTATUS:%{http_code}" "$FALLBACK_DOWNLOAD_URL/variables.env?$(date +%s)")
BODY=$(echo "$RESPONSE" | sed -e 's/HTTPSTATUS\:.*//g')
STATUS=$(echo "$RESPONSE" | tr -d '\n' | sed -e 's/.*HTTPSTATUS://')
if [ "$STATUS" -eq 200 ]; then
echo "$BODY" > $PLANE_INSTALL_DIR/variables-upgrade.env
else
echo "Failed to download variables.env. HTTP Status: $STATUS"
echo "URL: $RELEASE_DOWNLOAD_URL/$APP_RELEASE/variables.env"
mv $PLANE_INSTALL_DIR/archive/$TS.docker-compose.yml $PLANE_INSTALL_DIR/docker-compose.yml
exit 1
fi
fi
if [ -f "$DOCKER_ENV_PATH" ];
then
cp "$DOCKER_ENV_PATH" "$PLANE_INSTALL_DIR/archive/$TS.env"
cp "$DOCKER_ENV_PATH" "$PLANE_INSTALL_DIR/plane.env.bak"
fi
mv $PLANE_INSTALL_DIR/variables-upgrade.env $DOCKER_ENV_PATH
syncEnvFile
updateEnvFile "APP_RELEASE" "$APP_RELEASE" "$DOCKER_ENV_PATH"
}
function deployStack() {
# Check if docker compose file and env file exist
if [ ! -f "$DOCKER_FILE_PATH" ] || [ ! -f "$DOCKER_ENV_PATH" ]; then
echo "Configuration files not found"
echo "Downloading it now......"
APP_RELEASE=$(checkLatestRelease)
download
fi
if [ -z "$stack_name" ]; then
getStackName
fi
echo "Starting ${stack_name} stack..."
# Pull envs
if [ -f "$DOCKER_ENV_PATH" ]; then
set -o allexport; source $DOCKER_ENV_PATH; set +o allexport;
else
echo "Environment file not found: $DOCKER_ENV_PATH"
exit 1
fi
# Deploy the stack
docker stack deploy -c $DOCKER_FILE_PATH $stack_name
echo "Waiting for services to be deployed..."
sleep 10
# Check migrator service
local migrator_service=$(docker service ls --filter name=${stack_name}_migrator -q)
if [ -n "$migrator_service" ]; then
echo ">> Waiting for Data Migration to finish"
while docker service ls --filter name=${stack_name}_migrator | grep -q "running"; do
echo -n "."
sleep 1
done
echo ""
# Get the most recent container for the migrator service
local migrator_container=$(docker ps -a --filter name=${stack_name}_migrator --latest -q)
if [ -n "$migrator_container" ]; then
# Get the exit code of the container
local exit_code=$(docker inspect --format='{{.State.ExitCode}}' $migrator_container)
if [ "$exit_code" != "0" ]; then
echo "Server failed to start ❌"
echo "Migration failed with exit code: $exit_code"
echo "Please check the logs for the 'migrator' service and resolve the issue(s)."
echo "Stop the services by running the command: ./swarm.sh stop"
exit 1
else
echo " Data Migration completed successfully ✅"
fi
else
echo "Warning: Could not find migrator container to check exit status"
fi
fi
# Check API service
local api_service=$(docker service ls --filter name=${stack_name}_api -q)
while docker service ls --filter name=${stack_name}_api | grep -q "running"; do
local running_container=$(docker ps --filter "name=${stack_name}_api" --filter "status=running" -q)
if [ -n "$running_container" ]; then
if docker container logs $running_container 2>/dev/null | grep -q "Application Startup Complete"; then
break
fi
fi
sleep 2
done
if [ -z "$api_service" ]; then
echo "Plane Server failed to start ❌"
echo "Please check the logs for the 'api' service and resolve the issue(s)."
echo "Stop the services by running the command: ./swarm.sh stop"
exit 1
fi
echo " Plane Server started successfully ✅"
echo ""
echo " You can access the application at $WEB_URL"
echo ""
}
function removeStack() {
if [ -z "$stack_name" ]; then
echo "Stack name not found"
exit 1
fi
echo "Removing ${stack_name} stack..."
docker stack rm "$stack_name"
echo "Waiting for services to be removed..."
while docker stack ls | grep -q "$stack_name"; do
sleep 1
done
sleep 20
echo "Services stopped successfully ✅"
}
function viewStatus() {
echo "Checking status of ${stack_name} stack..."
if [ -z "$stack_name" ]; then
echo "Stack name not found"
exit 1
fi
docker stack ps "$stack_name"
}
function redeployStack() {
removeStack
echo "ReDeploying ${stack_name} stack..."
deployStack
}
function upgrade() {
echo "Checking status of ${stack_name} stack..."
if [ -z "$stack_name" ]; then
echo "Stack name not found"
exit 1
fi
local latest_release=$(checkLatestRelease)
echo ""
echo "Current release: $APP_RELEASE"
if [ "$latest_release" == "$APP_RELEASE" ]; then
echo ""
echo "You are already using the latest release"
exit 0
fi
echo "Latest release: $latest_release"
echo ""
# Check for confirmation to upgrade
echo "Do you want to upgrade to the latest release ($latest_release)?"
read -p "Continue? [y/N]: " confirm
if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
echo "Exiting..."
exit 0
fi
export APP_RELEASE=$latest_release
# check if stack exists
echo "Upgrading ${stack_name} stack..."
# check env file and take backup
if [ -f "$DOCKER_ENV_PATH" ]; then
cp "$DOCKER_ENV_PATH" "${DOCKER_ENV_PATH}.bak"
fi
download
redeployStack
}
function viewSpecificLogs() {
local service=$1
# Input validation
if [ -z "$service" ]; then
echo "Error: Please specify a service name"
return 1
fi
# Main loop for service logs
while true; do
# Get all running containers for the service
local running_containers=$(docker ps --filter "name=${stack_name}_${service}" --filter "status=running" -q)
# If no running containers found, try service logs
if [ -z "$running_containers" ]; then
echo "No running containers found for ${stack_name}_${service}, checking service logs..."
if docker service inspect ${stack_name}_${service} >/dev/null 2>&1; then
echo "Press Ctrl+C or 'q' to exit logs"
docker service logs ${stack_name}_${service} -f
break
else
echo "Error: No running containers or services found for ${stack_name}_${service}"
return 1
fi
return
fi
# If multiple containers are running, let user choose
if [ $(echo "$running_containers" | grep -v '^$' | wc -l) -gt 1 ]; then
clear
echo "Multiple containers found for ${stack_name}_${service}:"
local i=1
# Use regular arrays instead of associative arrays
container_ids=()
container_names=()
while read -r container_id; do
if [ -n "$container_id" ]; then
local container_name=$(docker inspect --format '{{.Name}}' "$container_id" | sed 's/\///')
container_ids[$i]=$container_id
container_names[$i]=$container_name
echo "[$i] ${container_names[$i]} (${container_ids[$i]})"
i=$((i+1))
fi
done <<< "$running_containers"
echo -e "\nPlease select a container number:"
read -r selection
if [[ "$selection" =~ ^[0-9]+$ ]] && [ -n "${container_ids[$selection]}" ]; then
local selected_container=${container_ids[$selection]}
clear
echo "Showing logs for container: ${container_names[$selection]}"
echo "Press Ctrl+C or 'q' to return to container selection"
# Start watching logs in the background
docker container logs -f "$selected_container" &
local log_pid=$!
while true; do
read -r -n 1 input
if [[ $input == "q" ]]; then
kill $log_pid 2>/dev/null
wait $log_pid 2>/dev/null
break
fi
done
clear
else
echo "Error: Invalid selection"
sleep 2
fi
else
# Single container case
local container_name=$(docker inspect --format '{{.Name}}' "$running_containers" | sed 's/\///')
echo "Showing logs for container: $container_name"
echo "Press Ctrl+C or 'q' to exit logs"
docker container logs -f "$running_containers" &
local log_pid=$!
while true; do
read -r -n 1 input
if [[ $input == "q" ]]; then
kill $log_pid 2>/dev/null
wait $log_pid 2>/dev/null
break
fi
done
break
fi
done
}
function viewLogs(){
ARG_SERVICE_NAME=$2
if [ -z "$ARG_SERVICE_NAME" ];
then
echo
echo "Select a Service you want to view the logs for:"
echo " 1) Web"
echo " 2) Space"
echo " 3) API"
echo " 4) Worker"
echo " 5) Beat-Worker"
echo " 6) Migrator"
echo " 7) Proxy"
echo " 8) Redis"
echo " 9) Postgres"
echo " 10) Minio"
echo " 11) RabbitMQ"
echo " 0) Back to Main Menu"
echo
read -p "Service: " DOCKER_SERVICE_NAME
until (( DOCKER_SERVICE_NAME >= 0 && DOCKER_SERVICE_NAME <= 11 )); do
echo "Invalid selection. Please enter a number between 0 and 11."
read -p "Service: " DOCKER_SERVICE_NAME
done
if [ -z "$DOCKER_SERVICE_NAME" ];
then
echo "INVALID SERVICE NAME SUPPLIED"
else
case $DOCKER_SERVICE_NAME in
1) viewSpecificLogs "web";;
2) viewSpecificLogs "space";;
3) viewSpecificLogs "api";;
4) viewSpecificLogs "worker";;
5) viewSpecificLogs "beat-worker";;
6) viewSpecificLogs "migrator";;
7) viewSpecificLogs "proxy";;
8) viewSpecificLogs "plane-redis";;
9) viewSpecificLogs "plane-db";;
10) viewSpecificLogs "plane-minio";;
11) viewSpecificLogs "plane-mq";;
0) askForAction;;
*) echo "INVALID SERVICE NAME SUPPLIED";;
esac
fi
elif [ -n "$ARG_SERVICE_NAME" ];
then
ARG_SERVICE_NAME=$(echo "$ARG_SERVICE_NAME" | tr '[:upper:]' '[:lower:]')
case $ARG_SERVICE_NAME in
web) viewSpecificLogs "web";;
space) viewSpecificLogs "space";;
api) viewSpecificLogs "api";;
worker) viewSpecificLogs "worker";;
beat-worker) viewSpecificLogs "beat-worker";;
migrator) viewSpecificLogs "migrator";;
proxy) viewSpecificLogs "proxy";;
redis) viewSpecificLogs "plane-redis";;
postgres) viewSpecificLogs "plane-db";;
minio) viewSpecificLogs "plane-minio";;
rabbitmq) viewSpecificLogs "plane-mq";;
*) echo "INVALID SERVICE NAME SUPPLIED";;
esac
else
echo "INVALID SERVICE NAME SUPPLIED"
fi
}
function askForAction() {
# Rest of askForAction remains the same but use $stack_name instead of $STACK_NAME
local DEFAULT_ACTION=$1
if [ -z "$DEFAULT_ACTION" ]; then
echo
echo "Select an Action you want to perform:"
echo " 1) Deploy Stack"
echo " 2) Remove Stack"
echo " 3) View Stack Status"
echo " 4) Redeploy Stack"
echo " 5) Upgrade"
echo " 6) View Logs"
echo " 7) Exit"
echo
read -p "Action [3]: " ACTION
until [[ -z "$ACTION" || "$ACTION" =~ ^[1-6]$ ]]; do
echo "$ACTION: invalid selection."
read -p "Action [3]: " ACTION
done
if [ -z "$ACTION" ]; then
ACTION=3
fi
echo
fi
if [ "$ACTION" == "1" ] || [ "$DEFAULT_ACTION" == "deploy" ]; then
deployStack
elif [ "$ACTION" == "2" ] || [ "$DEFAULT_ACTION" == "remove" ]; then
removeStack
elif [ "$ACTION" == "3" ] || [ "$DEFAULT_ACTION" == "status" ]; then
viewStatus
elif [ "$ACTION" == "4" ] || [ "$DEFAULT_ACTION" == "redeploy" ]; then
redeployStack
elif [ "$ACTION" == "5" ] || [ "$DEFAULT_ACTION" == "upgrade" ]; then
upgrade
elif [ "$ACTION" == "6" ] || [ "$DEFAULT_ACTION" == "logs" ]; then
viewLogs "$@"
elif [ "$ACTION" == "7" ] || [ "$DEFAULT_ACTION" == "exit" ]; then
exit 0
else
echo "INVALID ACTION SUPPLIED"
fi
}
# Initialize stack name at script start
if [ -z "$stack_name" ]; then
readStackName
fi
# Sync environment variables
if [ -f "$DOCKER_ENV_PATH" ]; then
DOCKERHUB_USER=$(getEnvValue "DOCKERHUB_USER" "$DOCKER_ENV_PATH")
APP_RELEASE=$(getEnvValue "APP_RELEASE" "$DOCKER_ENV_PATH")
if [ -z "$DOCKERHUB_USER" ]; then
DOCKERHUB_USER=artifacts.plane.so/makeplane
updateEnvFile "DOCKERHUB_USER" "$DOCKERHUB_USER" "$DOCKER_ENV_PATH"
fi
if [ -z "$APP_RELEASE" ]; then
APP_RELEASE=stable
updateEnvFile "APP_RELEASE" "$APP_RELEASE" "$DOCKER_ENV_PATH"
fi
fi
# Main execution
print_header
askForAction "$@"
+13
View File
@@ -0,0 +1,13 @@
import utils from "../utils.js";
await utils.cloneOrPullRepo({
repo: "https://github.com/makeplane/plane.git",
path: "./repo",
branch: "preview",
});
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.removePorts("./code/docker-compose.yml");
+29 -4
View File
@@ -9,6 +9,9 @@ ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJhbm9uIiwKIC
SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJzZXJ2aWNlX3JvbGUiLAogICAgImlzcyI6ICJzdXBhYmFzZS1kZW1vIiwKICAgICJpYXQiOiAxNjQxNzY5MjAwLAogICAgImV4cCI6IDE3OTk1MzU2MDAKfQ.DaYlNEoUrrEn2Ig7tqibS-PHK5vgusbcbo7X36XVt4Q SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJzZXJ2aWNlX3JvbGUiLAogICAgImlzcyI6ICJzdXBhYmFzZS1kZW1vIiwKICAgICJpYXQiOiAxNjQxNzY5MjAwLAogICAgImV4cCI6IDE3OTk1MzU2MDAKfQ.DaYlNEoUrrEn2Ig7tqibS-PHK5vgusbcbo7X36XVt4Q
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
VAULT_ENC_KEY=your-encryption-key-32-chars-min
############ ############
# Database - You can change these to any PostgreSQL database that has logical replication enabled. # Database - You can change these to any PostgreSQL database that has logical replication enabled.
@@ -19,6 +22,23 @@ POSTGRES_DB=postgres
POSTGRES_PORT=5432 POSTGRES_PORT=5432
# default user is postgres # default user is postgres
############
# Supavisor -- Database pooler
############
# Port Supavisor listens on for transaction pooling connections
POOLER_PROXY_PORT_TRANSACTION=6543
# Maximum number of PostgreSQL connections Supavisor opens per pool
POOLER_DEFAULT_POOL_SIZE=20
# Maximum number of client connections Supavisor accepts per pool
POOLER_MAX_CLIENT_CONN=100
# Unique tenant identifier
POOLER_TENANT_ID=your-tenant-id
# Pool size for internal metadata storage used by Supavisor
# This is separate from client connections and used only by Supavisor itself
POOLER_DB_POOL_SIZE=5
############ ############
# API Proxy - Configuration for the Kong Reverse proxy. # API Proxy - Configuration for the Kong Reverse proxy.
############ ############
@@ -81,21 +101,26 @@ SUPABASE_PUBLIC_URL=http://localhost:8000
# Enable webp support # Enable webp support
IMGPROXY_ENABLE_WEBP_DETECTION=true IMGPROXY_ENABLE_WEBP_DETECTION=true
# Add your OpenAI API key to enable SQL Editor Assistant
OPENAI_API_KEY=
############ ############
# Functions - Configuration for Functions # Functions - Configuration for Functions
############ ############
# NOTE: VERIFY_JWT applies to all functions. Per-function VERIFY_JWT is not supported yet. # NOTE: VERIFY_JWT applies to all functions. Per-function VERIFY_JWT is not supported yet.
FUNCTIONS_VERIFY_JWT=false 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
+1 -1
View File
@@ -4,7 +4,7 @@ services:
studio: studio:
build: build:
context: .. context: ..
dockerfile: studio/Dockerfile dockerfile: apps/studio/Dockerfile
target: dev target: dev
ports: ports:
- 8082:8082 - 8082:8082
+1 -3
View File
@@ -1,5 +1,3 @@
version: "3.8"
services: services:
minio: minio:
@@ -33,7 +31,7 @@ services:
storage: storage:
container_name: supabase-storage container_name: supabase-storage
image: supabase/storage-api:v0.43.11 image: supabase/storage-api:v1.11.13
depends_on: depends_on:
db: db:
# Disable this if you are using an external Postgres database # Disable this if you are using an external Postgres database
+186 -109
View File
@@ -1,15 +1,16 @@
# Usage # Usage
# Start: docker compose up # Start: docker compose up
# With helpers: docker compose -f docker-compose.yml -f ./dev/docker-compose.dev.yml up # With helpers: docker compose -f docker-compose.yml -f ./dev/docker-compose.dev.yml up
# Stop: docker compose down # Stop: docker compose down
# Destroy: docker compose -f docker-compose.yml -f ./dev/docker-compose.dev.yml down -v --remove-orphans # Destroy: docker compose -f docker-compose.yml -f ./dev/docker-compose.dev.yml down -v --remove-orphans
# Reset everything: ./reset.sh
name: supabase name: supabase
version: "3.8"
services: services:
studio: studio:
image: supabase/studio:20240729-ce42139 image: supabase/studio:2025.06.30-sha-6f5982d
restart: unless-stopped restart: unless-stopped
healthcheck: healthcheck:
test: test:
@@ -17,9 +18,10 @@ services:
"CMD", "CMD",
"node", "node",
"-e", "-e",
"require('http').get('http://localhost:3000/api/profile', (r) => {if (r.statusCode !== 200) throw new Error(r.statusCode)})", "fetch('http://studio:3000/api/platform/profile').then((r) => {if
(r.status !== 200) throw new Error(r.status)})"
] ]
timeout: 5s timeout: 10s
interval: 5s interval: 5s
retries: 3 retries: 3
depends_on: depends_on:
@@ -31,6 +33,7 @@ services:
DEFAULT_ORGANIZATION_NAME: ${STUDIO_DEFAULT_ORGANIZATION} DEFAULT_ORGANIZATION_NAME: ${STUDIO_DEFAULT_ORGANIZATION}
DEFAULT_PROJECT_NAME: ${STUDIO_DEFAULT_PROJECT} DEFAULT_PROJECT_NAME: ${STUDIO_DEFAULT_PROJECT}
OPENAI_API_KEY: ${OPENAI_API_KEY:-}
SUPABASE_URL: http://kong:8000 SUPABASE_URL: http://kong:8000
SUPABASE_PUBLIC_URL: ${SUPABASE_PUBLIC_URL} SUPABASE_PUBLIC_URL: ${SUPABASE_PUBLIC_URL}
@@ -38,7 +41,7 @@ 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_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
@@ -49,8 +52,9 @@ services:
kong: kong:
image: kong:2.8.1 image: kong:2.8.1
restart: unless-stopped restart: unless-stopped
# https://unix.stackexchange.com/a/294837 volumes:
entrypoint: bash -c 'eval "echo \"$$(cat ~/temp.yml)\"" > ~/kong.yml && /docker-entrypoint.sh kong docker-start' # https://github.com/supabase/supabase/issues/12661
- ./volumes/api/kong.yml:/home/kong/temp.yml:ro,z
depends_on: depends_on:
analytics: analytics:
condition: service_healthy condition: service_healthy
@@ -66,18 +70,13 @@ services:
SUPABASE_SERVICE_KEY: ${SERVICE_ROLE_KEY} SUPABASE_SERVICE_KEY: ${SERVICE_ROLE_KEY}
DASHBOARD_USERNAME: ${DASHBOARD_USERNAME} DASHBOARD_USERNAME: ${DASHBOARD_USERNAME}
DASHBOARD_PASSWORD: ${DASHBOARD_PASSWORD} DASHBOARD_PASSWORD: ${DASHBOARD_PASSWORD}
volumes: # https://unix.stackexchange.com/a/294837
# https://github.com/supabase/supabase/issues/12661 entrypoint: bash -c 'eval "echo \"$$(cat ~/temp.yml)\"" > ~/kong.yml &&
- ./volumes/api/kong.yml:/home/kong/temp.yml:ro /docker-entrypoint.sh kong docker-start'
auth: auth:
image: supabase/gotrue:v2.158.1 image: supabase/gotrue:v2.176.1
depends_on: restart: unless-stopped
db:
# Disable this if you are using an external Postgres database
condition: service_healthy
analytics:
condition: service_healthy
healthcheck: healthcheck:
test: test:
[ [
@@ -86,12 +85,17 @@ services:
"--no-verbose", "--no-verbose",
"--tries=1", "--tries=1",
"--spider", "--spider",
"http://localhost:9999/health", "http://localhost:9999/health"
] ]
timeout: 5s timeout: 5s
interval: 5s interval: 5s
retries: 3 retries: 3
restart: unless-stopped depends_on:
db:
# Disable this if you are using an external Postgres database
condition: service_healthy
analytics:
condition: service_healthy
environment: environment:
GOTRUE_API_HOST: 0.0.0.0 GOTRUE_API_HOST: 0.0.0.0
GOTRUE_API_PORT: 9999 GOTRUE_API_PORT: 9999
@@ -113,6 +117,10 @@ services:
GOTRUE_EXTERNAL_EMAIL_ENABLED: ${ENABLE_EMAIL_SIGNUP} GOTRUE_EXTERNAL_EMAIL_ENABLED: ${ENABLE_EMAIL_SIGNUP}
GOTRUE_EXTERNAL_ANONYMOUS_USERS_ENABLED: ${ENABLE_ANONYMOUS_USERS} GOTRUE_EXTERNAL_ANONYMOUS_USERS_ENABLED: ${ENABLE_ANONYMOUS_USERS}
GOTRUE_MAILER_AUTOCONFIRM: ${ENABLE_EMAIL_AUTOCONFIRM} GOTRUE_MAILER_AUTOCONFIRM: ${ENABLE_EMAIL_AUTOCONFIRM}
# Uncomment to bypass nonce check in ID Token flow. Commonly set to true when using Google Sign In on mobile.
# GOTRUE_EXTERNAL_SKIP_NONCE_CHECK: true
# GOTRUE_MAILER_SECURE_EMAIL_CHANGE_ENABLED: true # GOTRUE_MAILER_SECURE_EMAIL_CHANGE_ENABLED: true
# GOTRUE_SMTP_MAX_FREQUENCY: 1s # GOTRUE_SMTP_MAX_FREQUENCY: 1s
GOTRUE_SMTP_ADMIN_EMAIL: ${SMTP_ADMIN_EMAIL} GOTRUE_SMTP_ADMIN_EMAIL: ${SMTP_ADMIN_EMAIL}
@@ -128,26 +136,35 @@ services:
GOTRUE_EXTERNAL_PHONE_ENABLED: ${ENABLE_PHONE_SIGNUP} GOTRUE_EXTERNAL_PHONE_ENABLED: ${ENABLE_PHONE_SIGNUP}
GOTRUE_SMS_AUTOCONFIRM: ${ENABLE_PHONE_AUTOCONFIRM} GOTRUE_SMS_AUTOCONFIRM: ${ENABLE_PHONE_AUTOCONFIRM}
# Uncomment to enable custom access token hook. You'll need to create a public.custom_access_token_hook function and grant necessary permissions. # Uncomment to enable custom access token hook. Please see: https://supabase.com/docs/guides/auth/auth-hooks for full list of hooks and additional details about custom_access_token_hook
# See: https://supabase.com/docs/guides/auth/auth-hooks#hook-custom-access-token for details
# GOTRUE_HOOK_CUSTOM_ACCESS_TOKEN_ENABLED="true"
# GOTRUE_HOOK_CUSTOM_ACCESS_TOKEN_URI="pg-functions://postgres/public/custom_access_token_hook"
# GOTRUE_HOOK_MFA_VERIFICATION_ATTEMPT_ENABLED="true" # GOTRUE_HOOK_CUSTOM_ACCESS_TOKEN_ENABLED: "true"
# GOTRUE_HOOK_MFA_VERIFICATION_ATTEMPT_URI="pg-functions://postgres/public/mfa_verification_attempt" # GOTRUE_HOOK_CUSTOM_ACCESS_TOKEN_URI: "pg-functions://postgres/public/custom_access_token_hook"
# GOTRUE_HOOK_CUSTOM_ACCESS_TOKEN_SECRETS: "<standard-base64-secret>"
# GOTRUE_HOOK_PASSWORD_VERIFICATION_ATTEMPT_ENABLED="true" # GOTRUE_HOOK_MFA_VERIFICATION_ATTEMPT_ENABLED: "true"
# GOTRUE_HOOK_PASSWORD_VERIFICATION_ATTEMPT_URI="pg-functions://postgres/public/password_verification_attempt" # GOTRUE_HOOK_MFA_VERIFICATION_ATTEMPT_URI: "pg-functions://postgres/public/mfa_verification_attempt"
# GOTRUE_HOOK_PASSWORD_VERIFICATION_ATTEMPT_ENABLED: "true"
# GOTRUE_HOOK_PASSWORD_VERIFICATION_ATTEMPT_URI: "pg-functions://postgres/public/password_verification_attempt"
# GOTRUE_HOOK_SEND_SMS_ENABLED: "false"
# GOTRUE_HOOK_SEND_SMS_URI: "pg-functions://postgres/public/custom_access_token_hook"
# GOTRUE_HOOK_SEND_SMS_SECRETS: "v1,whsec_VGhpcyBpcyBhbiBleGFtcGxlIG9mIGEgc2hvcnRlciBCYXNlNjQgc3RyaW5n"
# GOTRUE_HOOK_SEND_EMAIL_ENABLED: "false"
# GOTRUE_HOOK_SEND_EMAIL_URI: "http://host.docker.internal:54321/functions/v1/email_sender"
# GOTRUE_HOOK_SEND_EMAIL_SECRETS: "v1,whsec_VGhpcyBpcyBhbiBleGFtcGxlIG9mIGEgc2hvcnRlciBCYXNlNjQgc3RyaW5n"
rest: rest:
image: postgrest/postgrest:v12.2.0 image: postgrest/postgrest:v12.2.12
restart: unless-stopped
depends_on: depends_on:
db: db:
# Disable this if you are using an external Postgres database # Disable this if you are using an external Postgres database
condition: service_healthy condition: service_healthy
analytics: analytics:
condition: service_healthy condition: service_healthy
restart: unless-stopped
environment: environment:
PGRST_DB_URI: postgres://authenticator:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB} PGRST_DB_URI: postgres://authenticator:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}
PGRST_DB_SCHEMAS: ${PGRST_DB_SCHEMAS} PGRST_DB_SCHEMAS: ${PGRST_DB_SCHEMAS}
@@ -156,11 +173,12 @@ services:
PGRST_DB_USE_LEGACY_GUCS: "false" PGRST_DB_USE_LEGACY_GUCS: "false"
PGRST_APP_SETTINGS_JWT_SECRET: ${JWT_SECRET} PGRST_APP_SETTINGS_JWT_SECRET: ${JWT_SECRET}
PGRST_APP_SETTINGS_JWT_EXP: ${JWT_EXPIRY} PGRST_APP_SETTINGS_JWT_EXP: ${JWT_EXPIRY}
command: "postgrest" command: [ "postgrest" ]
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.30.23 image: supabase/realtime:v2.34.47
restart: unless-stopped
depends_on: depends_on:
db: db:
# Disable this if you are using an external Postgres database # Disable this if you are using an external Postgres database
@@ -178,12 +196,11 @@ services:
"/dev/null", "/dev/null",
"-H", "-H",
"Authorization: Bearer ${ANON_KEY}", "Authorization: Bearer ${ANON_KEY}",
"http://localhost:4000/api/tenants/realtime-dev/health", "http://localhost:4000/api/tenants/realtime-dev/health"
] ]
timeout: 5s timeout: 5s
interval: 5s interval: 5s
retries: 3 retries: 3
restart: unless-stopped
environment: environment:
PORT: 4000 PORT: 4000
DB_HOST: ${POSTGRES_HOST} DB_HOST: ${POSTGRES_HOST}
@@ -191,27 +208,23 @@ services:
DB_USER: supabase_admin DB_USER: supabase_admin
DB_PASSWORD: ${POSTGRES_PASSWORD} DB_PASSWORD: ${POSTGRES_PASSWORD}
DB_NAME: ${POSTGRES_DB} DB_NAME: ${POSTGRES_DB}
DB_AFTER_CONNECT_QUERY: "SET search_path TO _realtime" DB_AFTER_CONNECT_QUERY: 'SET search_path TO _realtime'
DB_ENC_KEY: supabaserealtime DB_ENC_KEY: supabaserealtime
API_JWT_SECRET: ${JWT_SECRET} API_JWT_SECRET: ${JWT_SECRET}
SECRET_KEY_BASE: UpNVntn3cDxHJpq99YMc1T1AQgQpc8kfYTuRgBiYa15BLrx8etQoXz3gZv1/u2oq SECRET_KEY_BASE: ${SECRET_KEY_BASE}
ERL_AFLAGS: -proto_dist inet_tcp ERL_AFLAGS: -proto_dist inet_tcp
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
# 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.10.1 image: supabase/storage-api:v1.24.7
depends_on: restart: unless-stopped
db: volumes:
# Disable this if you are using an external Postgres database - ./volumes/storage:/var/lib/storage:z
condition: service_healthy
rest:
condition: service_started
imgproxy:
condition: service_started
healthcheck: healthcheck:
test: test:
[ [
@@ -220,12 +233,19 @@ services:
"--no-verbose", "--no-verbose",
"--tries=1", "--tries=1",
"--spider", "--spider",
"http://localhost:5000/status", "http://storage:5000/status"
] ]
timeout: 5s timeout: 5s
interval: 5s interval: 5s
retries: 3 retries: 3
restart: unless-stopped depends_on:
db:
# Disable this if you are using an external Postgres database
condition: service_healthy
rest:
condition: service_started
imgproxy:
condition: service_started
environment: environment:
ANON_KEY: ${ANON_KEY} ANON_KEY: ${ANON_KEY}
SERVICE_KEY: ${SERVICE_ROLE_KEY} SERVICE_KEY: ${SERVICE_ROLE_KEY}
@@ -241,13 +261,14 @@ services:
GLOBAL_S3_BUCKET: stub GLOBAL_S3_BUCKET: stub
ENABLE_IMAGE_TRANSFORMATION: "true" ENABLE_IMAGE_TRANSFORMATION: "true"
IMGPROXY_URL: http://imgproxy:5001 IMGPROXY_URL: http://imgproxy:5001
volumes:
- ./volumes/storage:/var/lib/storage:z
imgproxy: imgproxy:
image: darthsim/imgproxy:v3.8.0 image: darthsim/imgproxy:v3.8.0
restart: unless-stopped
volumes:
- ./volumes/storage:/var/lib/storage:z
healthcheck: healthcheck:
test: ["CMD", "imgproxy", "health"] test: [ "CMD", "imgproxy", "health" ]
timeout: 5s timeout: 5s
interval: 5s interval: 5s
retries: 3 retries: 3
@@ -256,18 +277,16 @@ services:
IMGPROXY_LOCAL_FILESYSTEM_ROOT: / IMGPROXY_LOCAL_FILESYSTEM_ROOT: /
IMGPROXY_USE_ETAG: "true" IMGPROXY_USE_ETAG: "true"
IMGPROXY_ENABLE_WEBP_DETECTION: ${IMGPROXY_ENABLE_WEBP_DETECTION} IMGPROXY_ENABLE_WEBP_DETECTION: ${IMGPROXY_ENABLE_WEBP_DETECTION}
volumes:
- ./volumes/storage:/var/lib/storage:z
meta: meta:
image: supabase/postgres-meta:v0.83.2 image: supabase/postgres-meta:v0.89.3
restart: unless-stopped
depends_on: depends_on:
db: db:
# Disable this if you are using an external Postgres database # Disable this if you are using an external Postgres database
condition: service_healthy condition: service_healthy
analytics: analytics:
condition: service_healthy condition: service_healthy
restart: unless-stopped
environment: environment:
PG_META_PORT: 8080 PG_META_PORT: 8080
PG_META_DB_HOST: ${POSTGRES_HOST} PG_META_DB_HOST: ${POSTGRES_HOST}
@@ -277,8 +296,10 @@ services:
PG_META_DB_PASSWORD: ${POSTGRES_PASSWORD} PG_META_DB_PASSWORD: ${POSTGRES_PASSWORD}
functions: functions:
image: supabase/edge-runtime:v1.56.1 image: supabase/edge-runtime:v1.67.4
restart: unless-stopped restart: unless-stopped
volumes:
- ./volumes/functions:/home/deno/functions:Z
depends_on: depends_on:
analytics: analytics:
condition: service_healthy condition: service_healthy
@@ -290,80 +311,52 @@ services:
SUPABASE_DB_URL: postgresql://postgres:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB} SUPABASE_DB_URL: postgresql://postgres:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}
# TODO: Allow configuring VERIFY_JWT per function. This PR might help: https://github.com/supabase/cli/pull/786 # TODO: Allow configuring VERIFY_JWT per function. This PR might help: https://github.com/supabase/cli/pull/786
VERIFY_JWT: "${FUNCTIONS_VERIFY_JWT}" VERIFY_JWT: "${FUNCTIONS_VERIFY_JWT}"
volumes: command: [ "start", "--main-service", "/home/deno/functions/main" ]
- ./volumes/functions:/home/deno/functions:Z
command:
- start
- --main-service
- /home/deno/functions/main
analytics: analytics:
image: supabase/logflare:1.4.0 image: supabase/logflare:1.14.2
healthcheck:
test: ["CMD", "curl", "http://localhost:4000/health"]
timeout: 5s
interval: 5s
retries: 10
restart: unless-stopped restart: unless-stopped
depends_on:
db:
# Disable this if you are using an external Postgres database
condition: service_healthy
# Uncomment to use Big Query backend for analytics # Uncomment to use Big Query backend for analytics
# volumes: # volumes:
# - type: bind # - type: bind
# source: ${PWD}/gcloud.json # source: ${PWD}/gcloud.json
# target: /opt/app/rel/logflare/bin/gcloud.json # target: /opt/app/rel/logflare/bin/gcloud.json
# read_only: true # read_only: true
healthcheck:
test: [ "CMD", "curl", "http://localhost:4000/health" ]
timeout: 5s
interval: 5s
retries: 10
depends_on:
db:
# Disable this if you are using an external Postgres database
condition: service_healthy
environment: environment:
LOGFLARE_NODE_HOST: 127.0.0.1 LOGFLARE_NODE_HOST: 127.0.0.1
DB_USERNAME: supabase_admin DB_USERNAME: supabase_admin
DB_DATABASE: ${POSTGRES_DB} DB_DATABASE: _supabase
DB_HOSTNAME: ${POSTGRES_HOST} DB_HOSTNAME: ${POSTGRES_HOST}
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 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}/${POSTGRES_DB} POSTGRES_BACKEND_URL: postgresql://supabase_admin:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/_supabase
POSTGRES_BACKEND_SCHEMA: _analytics POSTGRES_BACKEND_SCHEMA: _analytics
LOGFLARE_FEATURE_FLAG_OVERRIDE: multibackend=true LOGFLARE_FEATURE_FLAG_OVERRIDE: multibackend=true
# Uncomment to use Big Query backend for analytics # Uncomment to use Big Query backend for analytics
# GOOGLE_PROJECT_ID: ${GOOGLE_PROJECT_ID} # GOOGLE_PROJECT_ID: ${GOOGLE_PROJECT_ID}
# GOOGLE_PROJECT_NUMBER: ${GOOGLE_PROJECT_NUMBER} # GOOGLE_PROJECT_NUMBER: ${GOOGLE_PROJECT_NUMBER}
# 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.1.1.78 image: supabase/postgres:15.8.1.060
healthcheck:
test: pg_isready -U postgres -h localhost
interval: 5s
timeout: 5s
retries: 10
depends_on:
vector:
condition: service_healthy
command:
- postgres
- -c
- config_file=/etc/postgresql/postgresql.conf
- -c
- log_min_messages=fatal # prevents Realtime polling queries from appearing in logs
restart: unless-stopped restart: unless-stopped
environment:
POSTGRES_HOST: /var/run/postgresql
PGPORT: ${POSTGRES_PORT}
POSTGRES_PORT: ${POSTGRES_PORT}
PGPASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
PGDATABASE: ${POSTGRES_DB}
POSTGRES_DB: ${POSTGRES_DB}
JWT_SECRET: ${JWT_SECRET}
JWT_EXP: ${JWT_EXPIRY}
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
# Must be superuser to create event trigger # Must be superuser to create event trigger
@@ -374,13 +367,47 @@ services:
- ./volumes/db/jwt.sql:/docker-entrypoint-initdb.d/init-scripts/99-jwt.sql:Z - ./volumes/db/jwt.sql:/docker-entrypoint-initdb.d/init-scripts/99-jwt.sql:Z
# PGDATA directory is persisted between restarts # PGDATA directory is persisted between restarts
- ./volumes/db/data:/var/lib/postgresql/data:Z - ./volumes/db/data:/var/lib/postgresql/data:Z
# Changes required for internal supabase data such as _analytics
- ./volumes/db/_supabase.sql:/docker-entrypoint-initdb.d/migrations/97-_supabase.sql:Z
# Changes required for Analytics support # Changes required for Analytics support
- ./volumes/db/logs.sql:/docker-entrypoint-initdb.d/migrations/99-logs.sql:Z - ./volumes/db/logs.sql:/docker-entrypoint-initdb.d/migrations/99-logs.sql:Z
# Changes required for Pooler support
- ./volumes/db/pooler.sql:/docker-entrypoint-initdb.d/migrations/99-pooler.sql:Z
# Use named volume to persist pgsodium decryption key between restarts # Use named volume to persist pgsodium decryption key between restarts
- db-config:/etc/postgresql-custom - db-config:/etc/postgresql-custom
healthcheck:
test: [ "CMD", "pg_isready", "-U", "postgres", "-h", "localhost" ]
interval: 5s
timeout: 5s
retries: 10
depends_on:
vector:
condition: service_healthy
environment:
POSTGRES_HOST: /var/run/postgresql
PGPORT: ${POSTGRES_PORT}
POSTGRES_PORT: ${POSTGRES_PORT}
PGPASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
PGDATABASE: ${POSTGRES_DB}
POSTGRES_DB: ${POSTGRES_DB}
JWT_SECRET: ${JWT_SECRET}
JWT_EXP: ${JWT_EXPIRY}
command:
[
"postgres",
"-c",
"config_file=/etc/postgresql/postgresql.conf",
"-c",
"log_min_messages=fatal" # prevents Realtime polling queries from appearing in logs
]
vector: vector:
image: timberio/vector:0.28.1-alpine image: timberio/vector:0.28.1-alpine
restart: unless-stopped
volumes:
- ./volumes/logs/vector.yml:/etc/vector/vector.yml:ro,z
- ${DOCKER_SOCKET_LOCATION}:/var/run/docker.sock:ro,z
healthcheck: healthcheck:
test: test:
[ [
@@ -389,17 +416,67 @@ services:
"--no-verbose", "--no-verbose",
"--tries=1", "--tries=1",
"--spider", "--spider",
"http://vector:9001/health", "http://vector:9001/health"
] ]
timeout: 5s timeout: 5s
interval: 5s interval: 5s
retries: 3 retries: 3
volumes:
- ./volumes/logs/vector.yml:/etc/vector/vector.yml:ro
- ${DOCKER_SOCKET_LOCATION}:/var/run/docker.sock:ro
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
supavisor:
image: supabase/supavisor:2.5.6
restart: unless-stopped
volumes:
- ./volumes/pooler/pooler.exs:/etc/pooler/pooler.exs:ro,z
healthcheck:
test:
[
"CMD",
"curl",
"-sSfL",
"--head",
"-o",
"/dev/null",
"http://127.0.0.1:4000/api/health"
]
interval: 10s
timeout: 5s
retries: 5
depends_on:
db:
condition: service_healthy
analytics:
condition: service_healthy
environment:
PORT: 4000
POSTGRES_PORT: ${POSTGRES_PORT}
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
DATABASE_URL: ecto://supabase_admin:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/_supabase
CLUSTER_POSTGRES: true
SECRET_KEY_BASE: ${SECRET_KEY_BASE}
VAULT_ENC_KEY: ${VAULT_ENC_KEY}
API_JWT_SECRET: ${JWT_SECRET}
METRICS_JWT_SECRET: ${JWT_SECRET}
REGION: local
ERL_AFLAGS: -proto_dist inet_tcp
POOLER_TENANT_ID: ${POOLER_TENANT_ID}
POOLER_DEFAULT_POOL_SIZE: ${POOLER_DEFAULT_POOL_SIZE}
POOLER_MAX_CLIENT_CONN: ${POOLER_MAX_CLIENT_CONN}
POOLER_POOL_MODE: transaction
DB_POOL_SIZE: ${POOLER_DB_POOL_SIZE}
command:
[
"/bin/sh",
"-c",
"/app/bin/migrate && /app/bin/supavisor eval \"$$(cat
/etc/pooler/pooler.exs)\" && /app/bin/server"
]
volumes: volumes:
db-config: db-config:
+44
View File
@@ -0,0 +1,44 @@
#!/bin/bash
echo "WARNING: This will remove all containers and container data, and will reset the .env file. This action cannot be undone!"
read -p "Are you sure you want to proceed? (y/N) " -n 1 -r
echo # Move to a new line
if [[ ! $REPLY =~ ^[Yy]$ ]]
then
echo "Operation cancelled."
exit 1
fi
echo "Stopping and removing all containers..."
docker compose -f docker-compose.yml -f ./dev/docker-compose.dev.yml down -v --remove-orphans
echo "Cleaning up bind-mounted directories..."
BIND_MOUNTS=(
"./volumes/db/data"
)
for DIR in "${BIND_MOUNTS[@]}"; do
if [ -d "$DIR" ]; then
echo "Deleting $DIR..."
rm -rf "$DIR"
else
echo "Directory $DIR does not exist. Skipping bind mount deletion step..."
fi
done
echo "Resetting .env file..."
if [ -f ".env" ]; then
echo "Removing existing .env file..."
rm -f .env
else
echo "No .env file found. Skipping .env removal step..."
fi
if [ -f ".env.example" ]; then
echo "Copying .env.example to .env..."
cp .env.example .env
else
echo ".env.example file not found. Skipping .env reset step..."
fi
echo "Cleanup complete!"
+3
View File
@@ -0,0 +1,3 @@
\set pguser `echo "$POSTGRES_USER"`
CREATE DATABASE _supabase WITH OWNER :pguser;
+2
View File
@@ -1,4 +1,6 @@
\set pguser `echo "$POSTGRES_USER"` \set pguser `echo "$POSTGRES_USER"`
\c _supabase
create schema if not exists _analytics; create schema if not exists _analytics;
alter schema _analytics owner to :pguser; alter schema _analytics owner to :pguser;
\c postgres
+6
View File
@@ -0,0 +1,6 @@
\set pguser `echo "$POSTGRES_USER"`
\c _supabase
create schema if not exists _supavisor;
alter schema _supavisor owner to :pguser;
\c postgres
+21 -7
View File
@@ -165,7 +165,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 +177,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 +189,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,10 +201,12 @@ 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:
@@ -208,7 +216,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=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 +228,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 +241,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'
+30
View File
@@ -0,0 +1,30 @@
{:ok, _} = Application.ensure_all_started(:supavisor)
{:ok, version} =
case Supavisor.Repo.query!("select version()") do
%{rows: [[ver]]} -> Supavisor.Helpers.parse_pg_version(ver)
_ -> nil
end
params = %{
"external_id" => System.get_env("POOLER_TENANT_ID"),
"db_host" => "db",
"db_port" => System.get_env("POSTGRES_PORT"),
"db_database" => System.get_env("POSTGRES_DB"),
"require_user" => false,
"auth_query" => "SELECT * FROM pgbouncer.get_auth($1)",
"default_max_clients" => System.get_env("POOLER_MAX_CLIENT_CONN"),
"default_pool_size" => System.get_env("POOLER_DEFAULT_POOL_SIZE"),
"default_parameter_status" => %{"server_version" => version},
"users" => [%{
"db_user" => "pgbouncer",
"db_password" => System.get_env("POSTGRES_PASSWORD"),
"mode_type" => System.get_env("POOLER_POOL_MODE"),
"pool_size" => System.get_env("POOLER_DEFAULT_POOL_SIZE"),
"is_manager" => true
}]
}
if !Supavisor.Tenants.get_tenant_by_external_id(params["external_id"]) do
{:ok, _} = Supavisor.Tenants.create_tenant(params)
end
+7
View File
@@ -0,0 +1,7 @@
import utils from "../utils.js";
await utils.cloneOrPullRepo({ repo: "https://github.com/supabase/supabase" });
await utils.copyDir("./repo/docker", "./code");
await utils.removeContainerNames("./code/docker-compose.yml");
await utils.removePorts("./code/docker-compose.yml");
+7 -14
View File
@@ -1,25 +1,18 @@
TAG=latest TAG=latest
POSTGRES_ADMIN_PASSWORD=replace_me_with_a_strong_password #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
PG_DATABASE_HOST=db:5432 SERVER_URL=https://$(PRIMARY_DOMAIN)
SERVER_URL=http://localhost:3000
# Uncoment if you are serving your front on another server than the API (eg. bucket)
# FRONT_BASE_URL=http://localhost:3000
# Use openssl rand -base64 32 for each secret # Use openssl rand -base64 32 for each secret
ACCESS_TOKEN_SECRET=replace_me_with_a_random_string_access APP_SECRET=replace_me_with_a_random_string
LOGIN_TOKEN_SECRET=replace_me_with_a_random_string_login
REFRESH_TOKEN_SECRET=replace_me_with_a_random_string_refresh
FILE_TOKEN_SECRET=replace_me_with_a_random_string_refresh
SIGN_IN_PREFILLED=true
STORAGE_TYPE=local STORAGE_TYPE=local
# STORAGE_S3_REGION=eu-west3 # STORAGE_S3_REGION=eu-west3
# STORAGE_S3_NAME=my-bucket # STORAGE_S3_NAME=my-bucket
# STORAGE_S3_ENDPOINT= # STORAGE_S3_ENDPOINT=
MESSAGE_QUEUE_TYPE=pg-boss
+16 -39
View File
@@ -1,50 +1,27 @@
dev-build: # Makefile for building Twenty CRM docker images.
@docker compose -f dev/docker-compose.yml down -v # Set the tag and/or target build platform using make command-line variables assignments.
@docker compose -f dev/docker-compose.yml build #
# Optional make variables:
# PLATFORM - defaults to 'linux/amd64'
# TAG - defaults to 'latest'
#
# Example: make
# Example: make PLATFORM=linux/aarch64 TAG=my-tag
dev-up: PLATFORM ?= linux/amd64
@docker compose -f dev/docker-compose.yml up -d TAG ?= latest
dev-start:
@docker compose -f dev/docker-compose.yml start
dev-stop:
@docker compose -f dev/docker-compose.yml stop
dev-down:
@docker compose -f dev/docker-compose.yml down -v
dev-sh:
@docker compose -f dev/docker-compose.yml exec twenty-dev sh
dev-postgres-build:
@docker stop twenty_postgres || true
@docker rm twenty_postgres || true
@docker volume rm twenty_db_data || true
@docker compose -f dev/docker-compose.yml up --build postgres -d
prod-build: prod-build:
@cd ../.. && docker build -f ./packages/twenty-docker/twenty/Dockerfile --tag twenty . && cd - @cd ../.. && docker build -f ./packages/twenty-docker/twenty/Dockerfile --platform $(PLATFORM) --tag twenty:$(TAG) . && cd -
prod-run: prod-run:
@docker run -d -p 3000:3000 --name twenty twenty @docker run -d -p 3000:3000 --name twenty twenty:$(TAG)
prod-postgres-build:
@cd ../.. && docker build -f ./packages/twenty-docker/twenty-postgres/Dockerfile --tag twenty-postgres . && cd -
prod-postgres-run: prod-postgres-run:
@docker run -d -p 5432:5432 -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres --name twenty-postgres twenty-postgres @docker run -d -p 5432:5432 -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres --name twenty-postgres twenty-postgres:$(TAG)
prod-website-build: prod-website-build:
@cd ../.. && docker build -f ./packages/twenty-docker/twenty-website/Dockerfile --tag twenty-website . && cd - @cd ../.. && docker build -f ./packages/twenty-docker/twenty-website/Dockerfile --platform $(PLATFORM) --tag twenty-website:$(TAG) . && cd -
prod-website-run: prod-website-run:
@docker run -d -p 3000:3000 --name twenty-website twenty-website @docker run -d -p 3000:3000 --name twenty-website twenty-website:$(TAG)
release-postgres:
@cd ../.. && docker buildx build \
--push \
--no-cache \
--platform linux/amd64,linux/arm64 \
-f ./packages/twenty-docker/twenty-postgres/Dockerfile -t twentycrm/twenty-postgres:$(version) -t twentycrm/twenty-postgres:latest . \
&& cd -
+78 -45
View File
@@ -1,72 +1,100 @@
version: "3.9"
name: twenty name: twenty
services: 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: server:
image: twentycrm/twenty:${TAG} image: twentycrm/twenty:${TAG:-latest}
volumes: volumes:
- server-local-data:/app/packages/twenty-server/${STORAGE_LOCAL_PATH:-.local-storage} - server-local-data:/app/packages/twenty-server/.local-storage
- docker-data:/app/docker-data
environment: environment:
PORT: 3000 NODE_PORT: 3000
PG_DATABASE_URL: postgres://twenty:twenty@${PG_DATABASE_HOST}/default 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} SERVER_URL: ${SERVER_URL}
FRONT_BASE_URL: ${FRONT_BASE_URL:-$SERVER_URL} REDIS_URL: ${REDIS_URL:-redis://redis:6379}
MESSAGE_QUEUE_TYPE: ${MESSAGE_QUEUE_TYPE} DISABLE_DB_MIGRATIONS: ${DISABLE_DB_MIGRATIONS}
DISABLE_CRON_JOBS_REGISTRATION: ${DISABLE_CRON_JOBS_REGISTRATION}
ENABLE_DB_MIGRATIONS: "true"
SIGN_IN_PREFILLED: ${SIGN_IN_PREFILLED}
STORAGE_TYPE: ${STORAGE_TYPE} STORAGE_TYPE: ${STORAGE_TYPE}
STORAGE_S3_REGION: ${STORAGE_S3_REGION} STORAGE_S3_REGION: ${STORAGE_S3_REGION}
STORAGE_S3_NAME: ${STORAGE_S3_NAME} STORAGE_S3_NAME: ${STORAGE_S3_NAME}
STORAGE_S3_ENDPOINT: ${STORAGE_S3_ENDPOINT} STORAGE_S3_ENDPOINT: ${STORAGE_S3_ENDPOINT}
ACCESS_TOKEN_SECRET: ${ACCESS_TOKEN_SECRET}
LOGIN_TOKEN_SECRET: ${LOGIN_TOKEN_SECRET} APP_SECRET: ${APP_SECRET:-replace_me_with_a_random_string}
REFRESH_TOKEN_SECRET: ${REFRESH_TOKEN_SECRET} # MESSAGING_PROVIDER_GMAIL_ENABLED: ${MESSAGING_PROVIDER_GMAIL_ENABLED}
FILE_TOKEN_SECRET: ${FILE_TOKEN_SECRET} # CALENDAR_PROVIDER_GOOGLE_ENABLED: ${CALENDAR_PROVIDER_GOOGLE_ENABLED}
# AUTH_GOOGLE_CLIENT_ID: ${AUTH_GOOGLE_CLIENT_ID}
# AUTH_GOOGLE_CLIENT_SECRET: ${AUTH_GOOGLE_CLIENT_SECRET}
# AUTH_GOOGLE_CALLBACK_URL: ${AUTH_GOOGLE_CALLBACK_URL}
# AUTH_GOOGLE_APIS_CALLBACK_URL: ${AUTH_GOOGLE_APIS_CALLBACK_URL}
# CALENDAR_PROVIDER_MICROSOFT_ENABLED: ${CALENDAR_PROVIDER_MICROSOFT_ENABLED}
# MESSAGING_PROVIDER_MICROSOFT_ENABLED: ${MESSAGING_PROVIDER_MICROSOFT_ENABLED}
# AUTH_MICROSOFT_ENABLED: ${AUTH_MICROSOFT_ENABLED}
# AUTH_MICROSOFT_CLIENT_ID: ${AUTH_MICROSOFT_CLIENT_ID}
# AUTH_MICROSOFT_CLIENT_SECRET: ${AUTH_MICROSOFT_CLIENT_SECRET}
# AUTH_MICROSOFT_CALLBACK_URL: ${AUTH_MICROSOFT_CALLBACK_URL}
# AUTH_MICROSOFT_APIS_CALLBACK_URL: ${AUTH_MICROSOFT_APIS_CALLBACK_URL}
# EMAIL_FROM_ADDRESS: ${EMAIL_FROM_ADDRESS:-contact@yourdomain.com}
# EMAIL_FROM_NAME: ${EMAIL_FROM_NAME:-"John from YourDomain"}
# EMAIL_SYSTEM_ADDRESS: ${EMAIL_SYSTEM_ADDRESS:-system@yourdomain.com}
# EMAIL_DRIVER: ${EMAIL_DRIVER:-smtp}
# EMAIL_SMTP_HOST: ${EMAIL_SMTP_HOST:-smtp.gmail.com}
# EMAIL_SMTP_PORT: ${EMAIL_SMTP_PORT:-465}
# EMAIL_SMTP_USER: ${EMAIL_SMTP_USER:-}
# EMAIL_SMTP_PASSWORD: ${EMAIL_SMTP_PASSWORD:-}
depends_on: depends_on:
change-vol-ownership:
condition: service_completed_successfully
db: db:
condition: service_healthy condition: service_healthy
healthcheck: healthcheck:
test: curl --fail http://localhost:3000/healthz test: curl --fail http://localhost:3000/healthz
interval: 5s interval: 5s
timeout: 5s timeout: 5s
retries: 10 retries: 20
restart: always restart: always
worker: worker:
image: twentycrm/twenty:${TAG} image: twentycrm/twenty:${TAG:-latest}
command: ["yarn", "worker:prod"] volumes:
- server-local-data:/app/packages/twenty-server/.local-storage
command: [ "yarn", "worker:prod" ]
environment: environment:
PG_DATABASE_URL: postgres://twenty:twenty@${PG_DATABASE_HOST}/default 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} SERVER_URL: ${SERVER_URL}
FRONT_BASE_URL: ${FRONT_BASE_URL:-$SERVER_URL} REDIS_URL: ${REDIS_URL:-redis://redis:6379}
MESSAGE_QUEUE_TYPE: ${MESSAGE_QUEUE_TYPE} DISABLE_DB_MIGRATIONS: "true" # it already runs on the server
DISABLE_CRON_JOBS_REGISTRATION: "true" # it already runs on the server
ENABLE_DB_MIGRATIONS: "false" # it already runs on the server
STORAGE_TYPE: ${STORAGE_TYPE} STORAGE_TYPE: ${STORAGE_TYPE}
STORAGE_S3_REGION: ${STORAGE_S3_REGION} STORAGE_S3_REGION: ${STORAGE_S3_REGION}
STORAGE_S3_NAME: ${STORAGE_S3_NAME} STORAGE_S3_NAME: ${STORAGE_S3_NAME}
STORAGE_S3_ENDPOINT: ${STORAGE_S3_ENDPOINT} STORAGE_S3_ENDPOINT: ${STORAGE_S3_ENDPOINT}
ACCESS_TOKEN_SECRET: ${ACCESS_TOKEN_SECRET}
LOGIN_TOKEN_SECRET: ${LOGIN_TOKEN_SECRET} APP_SECRET: ${APP_SECRET:-replace_me_with_a_random_string}
REFRESH_TOKEN_SECRET: ${REFRESH_TOKEN_SECRET} # MESSAGING_PROVIDER_GMAIL_ENABLED: ${MESSAGING_PROVIDER_GMAIL_ENABLED}
FILE_TOKEN_SECRET: ${FILE_TOKEN_SECRET} # CALENDAR_PROVIDER_GOOGLE_ENABLED: ${CALENDAR_PROVIDER_GOOGLE_ENABLED}
# AUTH_GOOGLE_CLIENT_ID: ${AUTH_GOOGLE_CLIENT_ID}
# AUTH_GOOGLE_CLIENT_SECRET: ${AUTH_GOOGLE_CLIENT_SECRET}
# AUTH_GOOGLE_CALLBACK_URL: ${AUTH_GOOGLE_CALLBACK_URL}
# AUTH_GOOGLE_APIS_CALLBACK_URL: ${AUTH_GOOGLE_APIS_CALLBACK_URL}
# CALENDAR_PROVIDER_MICROSOFT_ENABLED: ${CALENDAR_PROVIDER_MICROSOFT_ENABLED}
# MESSAGING_PROVIDER_MICROSOFT_ENABLED: ${MESSAGING_PROVIDER_MICROSOFT_ENABLED}
# AUTH_MICROSOFT_ENABLED: ${AUTH_MICROSOFT_ENABLED}
# AUTH_MICROSOFT_CLIENT_ID: ${AUTH_MICROSOFT_CLIENT_ID}
# AUTH_MICROSOFT_CLIENT_SECRET: ${AUTH_MICROSOFT_CLIENT_SECRET}
# AUTH_MICROSOFT_CALLBACK_URL: ${AUTH_MICROSOFT_CALLBACK_URL}
# AUTH_MICROSOFT_APIS_CALLBACK_URL: ${AUTH_MICROSOFT_APIS_CALLBACK_URL}
# EMAIL_FROM_ADDRESS: ${EMAIL_FROM_ADDRESS:-contact@yourdomain.com}
# EMAIL_FROM_NAME: ${EMAIL_FROM_NAME:-"John from YourDomain"}
# EMAIL_SYSTEM_ADDRESS: ${EMAIL_SYSTEM_ADDRESS:-system@yourdomain.com}
# EMAIL_DRIVER: ${EMAIL_DRIVER:-smtp}
# EMAIL_SMTP_HOST: ${EMAIL_SMTP_HOST:-smtp.gmail.com}
# EMAIL_SMTP_PORT: ${EMAIL_SMTP_PORT:-465}
# EMAIL_SMTP_USER: ${EMAIL_SMTP_USER:-}
# EMAIL_SMTP_PASSWORD: ${EMAIL_SMTP_PASSWORD:-}
depends_on: depends_on:
db: db:
condition: service_healthy condition: service_healthy
@@ -75,19 +103,24 @@ services:
restart: always restart: always
db: db:
image: twentycrm/twenty-postgres:${TAG} image: postgres:16
volumes: volumes:
- db-data:/bitnami/postgresql - db-data:/var/lib/postgresql/data
environment: environment:
POSTGRES_PASSWORD: ${POSTGRES_ADMIN_PASSWORD} POSTGRES_USER: ${PG_DATABASE_USER:-postgres}
POSTGRES_PASSWORD: ${PG_DATABASE_PASSWORD:-postgres}
healthcheck: healthcheck:
test: pg_isready -U twenty -d default test: pg_isready -U ${PG_DATABASE_USER:-postgres} -h localhost -d postgres
interval: 5s interval: 5s
timeout: 5s timeout: 5s
retries: 10 retries: 10
restart: always restart: always
redis:
image: redis
restart: always
command: [ "--maxmemory-policy", "noeviction" ]
volumes: volumes:
docker-data:
db-data: db-data:
server-local-data: server-local-data:
@@ -0,0 +1,15 @@
apiVersion: 1
datasources:
- name: ClickHouse
type: grafana-clickhouse-datasource
uid: clickhouse_datasource
jsonData:
server: twenty_clickhouse
defaultDatabase: twenty_dev
port: 9000
protocol: native
tlsSkipVerify: true
username: default
secureJsonData:
password: devPassword
+3
View File
@@ -1,4 +1,7 @@
# README # README
DISCLAIMER: The k8s and podman deployments are not maintained by the core team.
These files are provided and maintained by the community. Twenty core team
maintains support for docker deployment.
## Overview ## Overview
+31 -27
View File
@@ -22,33 +22,37 @@ spec:
app: twentycrm-db app: twentycrm-db
spec: spec:
volumes: volumes:
- name: twentycrm-db-data - name: twentycrm-db-data
persistentVolumeClaim: persistentVolumeClaim:
claimName: twentycrm-db-pvc claimName: twentycrm-db-pvc
containers: containers:
- env: - name: twentycrm
- name: POSTGRES_PASSWORD image: twentycrm/twenty-postgres-spilo:latest
value: "twenty" imagePullPolicy: Always
- name: BITNAMI_DEBUG env:
value: "true" - name: PGUSER_SUPERUSER
- image: twentycrm/twenty-postgres:latest value: "postgres"
imagePullPolicy: Always - name: PGPASSWORD_SUPERUSER
name: twentycrm value: "postgres"
ports: - name: SPILO_PROVIDER
- containerPort: 5432 value: "local"
name: tcp - name: ALLOW_NOSSL
protocol: TCP value: "true"
resources: ports:
requests: - containerPort: 5432
memory: "256Mi" name: tcp
cpu: "250m" protocol: TCP
limits: resources:
memory: "1024Mi" requests:
cpu: "1000m" memory: "256Mi"
stdin: true cpu: "250m"
tty: true limits:
volumeMounts: memory: "1024Mi"
- mountPath: /bitnami/postgresql cpu: "1000m"
name: twentycrm-db-data stdin: true
tty: true
volumeMounts:
- mountPath: /home/postgres/pgdata
name: twentycrm-db-data
dnsPolicy: ClusterFirst dnsPolicy: ClusterFirst
restartPolicy: Always restartPolicy: Always
@@ -0,0 +1,45 @@
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: twentycrm-redis
name: twentycrm-redis
namespace: twentycrm
spec:
progressDeadlineSeconds: 600
replicas: 1
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
type: RollingUpdate
selector:
matchLabels:
app: twentycrm-redis
template:
metadata:
labels:
app: twentycrm-redis
spec:
containers:
- name: redis
image: redis/redis-stack-server:latest
imagePullPolicy: Always
args: ["--maxmemory-policy", "noeviction"]
env:
- name: PORT
value: "6379"
ports:
- containerPort: 6379
name: redis
protocol: TCP
resources:
requests:
memory: "1024Mi"
cpu: "250m"
limits:
memory: "2048Mi"
cpu: "500m"
dnsPolicy: ClusterFirst
restartPolicy: Always
@@ -22,67 +22,55 @@ spec:
app: twentycrm-server app: twentycrm-server
spec: spec:
volumes: volumes:
- name: twentycrm-server-data - name: twentycrm-server-data
persistentVolumeClaim: persistentVolumeClaim:
claimName: twentycrm-server-pvc claimName: twentycrm-server-pvc
- name: twentycrm-docker-data
persistentVolumeClaim:
claimName: twentycrm-docker-data-pvc
containers: containers:
- env: - name: twentycrm
- name: PORT image: twentycrm/twenty:latest
value: 3000 imagePullPolicy: Always
- name: SERVER_URL env:
value: "https://crm.example.com:443" - name: NODE_PORT
- name: FRONT_BASE_URL value: 3000
value: "https://crm.example.com:443" - name: SERVER_URL
- name: PG_DATABASE_URL value: "https://crm.example.com:443"
value: "postgres://twenty:twenty@twenty-db.twentycrm.svc.cluster.local/default" - name: "PG_DATABASE_URL"
- name: ENABLE_DB_MIGRATIONS value: "postgres://postgres:postgres@twentycrm-db.twentycrm.svc.cluster.local/default"
value: "true" - name: "REDIS_URL"
- name: SIGN_IN_PREFILLED value: "redis://twentycrm-redis.twentycrm.svc.cluster.local:6379"
value: "true" - name: SIGN_IN_PREFILLED
- name: STORAGE_TYPE value: "false"
value: "local" - name: STORAGE_TYPE
- name: "MESSAGE_QUEUE_TYPE" value: "local"
value: "pg-boss" - name: "ACCESS_TOKEN_EXPIRES_IN"
- name: ACCESS_TOKEN_SECRET value: "7d"
valueFrom: - name: "LOGIN_TOKEN_EXPIRES_IN"
secretKeyRef: value: "1h"
name: tokens - name: APP_SECRET
key: accessToken valueFrom:
- name: LOGIN_TOKEN_SECRET secretKeyRef:
valueFrom: name: tokens
secretKeyRef: key: accessToken
name: tokens ports:
key: loginToken - containerPort: 3000
- name: REFRESH_TOKEN_SECRET name: http-tcp
valueFrom: protocol: TCP
secretKeyRef: resources:
name: tokens requests:
key: refreshToken memory: "256Mi"
- name: FILE_TOKEN_SECRET cpu: "250m"
valueFrom: limits:
secretKeyRef: memory: "1024Mi"
name: tokens cpu: "1000m"
key: fileToken stdin: true
- image: twentycrm/twenty:latest tty: true
imagePullPolicy: Always volumeMounts:
name: twentycrm - mountPath: /app/docker-data
ports: name: twentycrm-docker-data
- containerPort: 3000 - mountPath: /app/packages/twenty-server/.local-storage
name: http-tcp name: twentycrm-server-data
protocol: TCP
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "1024Mi"
cpu: "1000m"
stdin: true
tty: true
volumeMounts:
- mountPath: /app/docker-data
name: twentycrm-server-data
- mountPath: /app/.local-storage
name: twentycrm-server-data
dnsPolicy: ClusterFirst dnsPolicy: ClusterFirst
restartPolicy: Always restartPolicy: Always
@@ -21,58 +21,37 @@ spec:
labels: labels:
app: twentycrm-worker app: twentycrm-worker
spec: spec:
volumes:
- name: twentycrm-worker-data
persistentVolumeClaim:
claimName: twentycrm-worker-pvc
containers: containers:
- env: - name: twentycrm
- name: SERVER_URL image: twentycrm/twenty:latest
value: "https://crm.example.com:443" imagePullPolicy: Always
- name: FRONT_BASE_URL env:
value: "https://crm.example.com:443" - name: SERVER_URL
- name: PG_DATABASE_URL value: "https://crm.example.com:443"
value: "postgres://twenty:twenty@twenty-db.twentycrm.svc.cluster.local/default" - name: PG_DATABASE_URL
- name: ENABLE_DB_MIGRATIONS value: "postgres://postgres:postgres@twentycrm-db.twentycrm.svc.cluster.local/default"
value: "false" # it already runs on the server - name: DISABLE_DB_MIGRATIONS
- name: STORAGE_TYPE value: "false" # it already runs on the server
value: "local" - name: STORAGE_TYPE
- name: "MESSAGE_QUEUE_TYPE" value: "local"
value: "pg-boss" - name: "REDIS_URL"
- name: ACCESS_TOKEN_SECRET value: "redis://twentycrm-redis.twentycrm.svc.cluster.local:6379"
valueFrom: - name: APP_SECRET
secretKeyRef: valueFrom:
name: tokens secretKeyRef:
key: accessToken name: tokens
- name: LOGIN_TOKEN_SECRET key: accessToken
valueFrom: command:
secretKeyRef: - yarn
name: tokens - worker:prod
key: loginToken resources:
- name: REFRESH_TOKEN_SECRET requests:
valueFrom: memory: "1024Mi"
secretKeyRef: cpu: "250m"
name: tokens limits:
key: refreshToken memory: "2048Mi"
- name: FILE_TOKEN_SECRET cpu: "1000m"
valueFrom: stdin: true
secretKeyRef: tty: true
name: tokens
key: fileToken
- image: twentycrm/twenty:latest
imagePullPolicy: Always
name: twentycrm
command:
- yarn
- worker:prod
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "1024Mi"
cpu: "1000m"
stdin: true
tty: true
dnsPolicy: ClusterFirst dnsPolicy: ClusterFirst
restartPolicy: Always restartPolicy: Always
+14 -14
View File
@@ -4,21 +4,21 @@ metadata:
name: twentycrm name: twentycrm
namespace: twentycrm namespace: twentycrm
annotations: annotations:
nginx.ingress.kubernetes.io/configuration-snippet: | nginx.ingress.kubernetes.io/configuration-snippet: |
more_set_headers "X-Forwarded-For $http_x_forwarded_for"; more_set_headers "X-Forwarded-For $http_x_forwarded_for";
nginx.ingress.kubernetes.io/force-ssl-redirect: "false" nginx.ingress.kubernetes.io/force-ssl-redirect: "false"
kubernetes.io/ingress.class: "nginx" kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/backend-protocol: "HTTP" nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
spec: spec:
ingressClassName: nginx ingressClassName: nginx
rules: rules:
- host: crm.example.com - host: crm.example.com
http: http:
paths: paths:
- path: / - path: /
pathType: Prefix pathType: Prefix
backend: backend:
service: service:
name: twentycrm-server name: twentycrm-server
port: port:
name: http-tcp name: http-tcp
@@ -0,0 +1,11 @@
apiVersion: v1
kind: PersistentVolume
metadata:
name: twentycrm-docker-data-pv
spec:
storageClassName: default
capacity:
storage: 100Mi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
@@ -0,0 +1,13 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: twentycrm-docker-data-pvc
namespace: twentycrm
spec:
storageClassName: default
volumeName: twentycrm-docker-data-pv
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 100Mi
+3 -3
View File
@@ -6,9 +6,9 @@ metadata:
spec: spec:
internalTrafficPolicy: Cluster internalTrafficPolicy: Cluster
ports: ports:
- port: 5432 - port: 5432
protocol: TCP protocol: TCP
targetPort: 5432 targetPort: 5432
selector: selector:
app: twentycrm-db app: twentycrm-db
sessionAffinity: ClientIP sessionAffinity: ClientIP
@@ -0,0 +1,18 @@
apiVersion: v1
kind: Service
metadata:
name: twentycrm-redis
namespace: twentycrm
spec:
internalTrafficPolicy: Cluster
ports:
- port: 6379
protocol: TCP
targetPort: 6379
selector:
app: twentycrm-redis
sessionAffinity: ClientIP
sessionAffinityConfig:
clientIP:
timeoutSeconds: 10800
type: ClusterIP
@@ -6,10 +6,10 @@ metadata:
spec: spec:
internalTrafficPolicy: Cluster internalTrafficPolicy: Cluster
ports: ports:
- name: http-tcp - name: http-tcp
port: 3000 port: 3000
protocol: TCP protocol: TCP
targetPort: 3000 targetPort: 3000
selector: selector:
app: twentycrm-server app: twentycrm-server
sessionAffinity: ClientIP sessionAffinity: ClientIP
@@ -15,12 +15,12 @@ output:
<!-- BEGIN_TF_DOCS --> <!-- BEGIN_TF_DOCS -->
# TwentyCRM Terraform 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. 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 .` 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` To make configuration changes to how this doc is generated, see `./.terraform-docs.yml`
{{ .Content }} {{ .Content }}
<!-- END_TF_DOCS --> <!-- END_TF_DOCS -->
@@ -45,4 +45,4 @@ settings:
read-comments: true read-comments: true
required: true required: true
sensitive: true sensitive: true
type: true type: true
+20 -11
View File
@@ -1,9 +1,9 @@
<!-- BEGIN_TF_DOCS --> <!-- BEGIN_TF_DOCS -->
# TwentyCRM Terraform 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. 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 .` 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` To make configuration changes to how this doc is generated, see `./.terraform-docs.yml`
@@ -12,30 +12,37 @@ To make configuration changes to how this doc is generated, see `./.terraform-do
| Name | Version | | Name | Version |
|------|---------| |------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.9.2 | | <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.9.2 |
| <a name="requirement_kubernetes"></a> [kubernetes](#requirement\_kubernetes) | >= 2.31.0 | | <a name="requirement_kubernetes"></a> [kubernetes](#requirement\_kubernetes) | >= 2.32.0 |
| <a name="requirement_random"></a> [random](#requirement\_random) | >= 3.6.3 |
## Providers ## Providers
| Name | Version | | Name | Version |
|------|---------| |------|---------|
| <a name="provider_kubernetes"></a> [kubernetes](#provider\_kubernetes) | >= 2.31.0 | | <a name="provider_kubernetes"></a> [kubernetes](#provider\_kubernetes) | >= 2.32.0 |
| <a name="provider_random"></a> [random](#provider\_random) | >= 3.6.3 |
## Resources ## Resources
| Name | Type | | Name | Type |
|------|------| |------|------|
| [kubernetes_deployment.twentycrm_db](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/deployment) | resource | | [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_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_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_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_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.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.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.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_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_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_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 | | [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 ## Inputs
@@ -43,22 +50,24 @@ To make configuration changes to how this doc is generated, see `./.terraform-do
|------|-------------|------|---------|:--------:| |------|-------------|------|---------|:--------:|
| <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_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_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_token_accessToken"></a> [twentycrm\_token\_accessToken](#input\_twentycrm\_token\_accessToken) | TwentyCRM access Token | `string` | n/a | yes |
| <a name="input_twentycrm_token_fileToken"></a> [twentycrm\_token\_fileToken](#input\_twentycrm\_token\_fileToken) | TwentyCRM file Token | `string` | n/a | yes |
| <a name="input_twentycrm_token_loginToken"></a> [twentycrm\_token\_loginToken](#input\_twentycrm\_token\_loginToken) | TwentyCRM login Token | `string` | n/a | yes |
| <a name="input_twentycrm_token_refreshToken"></a> [twentycrm\_token\_refreshToken](#input\_twentycrm\_token\_refreshToken) | TwentyCRM refresh Token | `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_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:latest"` | 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_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_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_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_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_namespace"></a> [twentycrm\_namespace](#input\_twentycrm\_namespace) | Namespace for all TwentyCRM resources | `string` | `"twentycrm"` | 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/docker-data'. | `string` | `"/app/docker-data"` | 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_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_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_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_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_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 | | <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 --> <!-- END_TF_DOCS -->
@@ -0,0 +1,60 @@
resource "kubernetes_deployment" "twentycrm_redis" {
metadata {
name = "${var.twentycrm_app_name}-redis"
namespace = kubernetes_namespace.twentycrm.metadata.0.name
labels = {
app = "${var.twentycrm_app_name}-redis"
}
}
spec {
replicas = var.twentycrm_redis_replicas
selector {
match_labels = {
app = "${var.twentycrm_app_name}-redis"
}
}
strategy {
type = "RollingUpdate"
rolling_update {
max_surge = "1"
max_unavailable = "1"
}
}
template {
metadata {
labels = {
app = "${var.twentycrm_app_name}-redis"
}
}
spec {
container {
image = var.twentycrm_redis_image
name = "redis"
port {
container_port = 6379
protocol = "TCP"
}
resources {
requests = {
cpu = "250m"
memory = "1024Mi"
}
limits = {
cpu = "500m"
memory = "2048Mi"
}
}
}
dns_policy = "ClusterFirst"
restart_policy = "Always"
}
}
}
}
+27 -56
View File
@@ -37,44 +37,27 @@ resource "kubernetes_deployment" "twentycrm_server" {
stdin = true stdin = true
tty = true tty = true
security_context {
allow_privilege_escalation = true
privileged = true
run_as_user = 1000
}
env { env {
name = "PORT" name = "NODE_PORT"
value = "3000" value = "3000"
} }
env {
name = "DEBUG_MODE"
value = false
}
env { env {
name = "SERVER_URL" name = "SERVER_URL"
value = var.twentycrm_app_hostname value = var.twentycrm_app_hostname
} }
env {
name = "FRONT_BASE_URL"
value = var.twentycrm_app_hostname
}
env { env {
name = "PG_DATABASE_URL" name = "PG_DATABASE_URL"
value = "postgres://twenty:${var.twentycrm_pgdb_admin_password}@${var.twentycrm_app_name}-db.${kubernetes_namespace.twentycrm.metadata.0.name}.svc.cluster.local/default" 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 { env {
name = "ENABLE_DB_MIGRATIONS" name = "REDIS_URL"
value = "true" value = "redis://${kubernetes_service.twentycrm_redis.metadata.0.name}.${kubernetes_namespace.twentycrm.metadata.0.name}.svc.cluster.local:6379"
} }
env { env {
name = "SIGN_IN_PREFILLED" name = "DISABLE_DB_MIGRATIONS"
value = "true" value = "false"
} }
env { env {
@@ -82,11 +65,15 @@ resource "kubernetes_deployment" "twentycrm_server" {
value = "local" value = "local"
} }
env { env {
name = "MESSAGE_QUEUE_TYPE" name = "ACCESS_TOKEN_EXPIRES_IN"
value = "pg-boss" value = "7d"
} }
env { env {
name = "ACCESS_TOKEN_SECRET" name = "LOGIN_TOKEN_EXPIRES_IN"
value = "1h"
}
env {
name = "APP_SECRET"
value_from { value_from {
secret_key_ref { secret_key_ref {
name = "tokens" name = "tokens"
@@ -95,36 +82,6 @@ resource "kubernetes_deployment" "twentycrm_server" {
} }
} }
env {
name = "LOGIN_TOKEN_SECRET"
value_from {
secret_key_ref {
name = "tokens"
key = "loginToken"
}
}
}
env {
name = "REFRESH_TOKEN_SECRET"
value_from {
secret_key_ref {
name = "tokens"
key = "refreshToken"
}
}
}
env {
name = "FILE_TOKEN_SECRET"
value_from {
secret_key_ref {
name = "tokens"
key = "fileToken"
}
}
}
port { port {
container_port = 3000 container_port = 3000
protocol = "TCP" protocol = "TCP"
@@ -145,6 +102,11 @@ resource "kubernetes_deployment" "twentycrm_server" {
name = "server-data" name = "server-data"
mount_path = var.twentycrm_server_data_mount_path mount_path = var.twentycrm_server_data_mount_path
} }
volume_mount {
name = "docker-data"
mount_path = var.twentycrm_docker_data_mount_path
}
} }
volume { volume {
@@ -155,6 +117,14 @@ resource "kubernetes_deployment" "twentycrm_server" {
} }
} }
volume {
name = "docker-data"
persistent_volume_claim {
claim_name = kubernetes_persistent_volume_claim.docker_data.metadata.0.name
}
}
dns_policy = "ClusterFirst" dns_policy = "ClusterFirst"
restart_policy = "Always" restart_policy = "Always"
} }
@@ -162,6 +132,7 @@ resource "kubernetes_deployment" "twentycrm_server" {
} }
depends_on = [ depends_on = [
kubernetes_deployment.twentycrm_db, kubernetes_deployment.twentycrm_db,
kubernetes_deployment.twentycrm_redis,
kubernetes_secret.twentycrm_tokens kubernetes_secret.twentycrm_tokens
] ]
} }
+14 -46
View File
@@ -43,32 +43,28 @@ resource "kubernetes_deployment" "twentycrm_worker" {
value = var.twentycrm_app_hostname value = var.twentycrm_app_hostname
} }
env {
name = "FRONT_BASE_URL"
value = var.twentycrm_app_hostname
}
env { env {
name = "PG_DATABASE_URL" name = "PG_DATABASE_URL"
value = "postgres://twenty:${var.twentycrm_pgdb_admin_password}@${var.twentycrm_app_name}-db.${kubernetes_namespace.twentycrm.metadata.0.name}.svc.cluster.local/default" 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 { env {
name = "ENABLE_DB_MIGRATIONS" name = "REDIS_URL"
value = "false" #it already runs on the server 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 { env {
name = "STORAGE_TYPE" name = "STORAGE_TYPE"
value = "local" value = "local"
} }
env {
name = "MESSAGE_QUEUE_TYPE"
value = "pg-boss"
}
env { env {
name = "ACCESS_TOKEN_SECRET" name = "APP_SECRET"
value_from { value_from {
secret_key_ref { secret_key_ref {
name = "tokens" name = "tokens"
@@ -77,44 +73,14 @@ resource "kubernetes_deployment" "twentycrm_worker" {
} }
} }
env {
name = "LOGIN_TOKEN_SECRET"
value_from {
secret_key_ref {
name = "tokens"
key = "loginToken"
}
}
}
env {
name = "REFRESH_TOKEN_SECRET"
value_from {
secret_key_ref {
name = "tokens"
key = "refreshToken"
}
}
}
env {
name = "FILE_TOKEN_SECRET"
value_from {
secret_key_ref {
name = "tokens"
key = "fileToken"
}
}
}
resources { resources {
requests = { requests = {
cpu = "250m" cpu = "250m"
memory = "256Mi" memory = "1024Mi"
} }
limits = { limits = {
cpu = "1000m" cpu = "1000m"
memory = "1024Mi" memory = "2048Mi"
} }
} }
} }
@@ -126,6 +92,8 @@ resource "kubernetes_deployment" "twentycrm_worker" {
} }
depends_on = [ depends_on = [
kubernetes_deployment.twentycrm_db, kubernetes_deployment.twentycrm_db,
kubernetes_secret.twentycrm_tokens kubernetes_deployment.twentycrm_redis,
kubernetes_deployment.twentycrm_server,
kubernetes_secret.twentycrm_tokens,
] ]
} }
+5 -1
View File
@@ -13,7 +13,11 @@ terraform {
required_providers { required_providers {
kubernetes = { kubernetes = {
source = "hashicorp/kubernetes" source = "hashicorp/kubernetes"
version = ">= 2.31.0" version = ">= 2.32.0"
}
random = {
source = "hashicorp/random"
version = ">= 3.6.3"
} }
} }
} }
@@ -0,0 +1,19 @@
resource "kubernetes_persistent_volume" "docker_data" {
metadata {
name = "${var.twentycrm_app_name}-docker-data-pv"
}
spec {
storage_class_name = "default"
capacity = {
storage = var.twentycrm_docker_data_pv_capacity
}
access_modes = ["ReadWriteOnce"]
# refer to Terraform Docs for your specific implementation requirements
# https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/persistent_volume
persistent_volume_source {
local {
path = var.twentycrm_docker_data_pv_path
}
}
}
}
@@ -0,0 +1,15 @@
resource "kubernetes_persistent_volume_claim" "docker_data" {
metadata {
name = "${var.twentycrm_app_name}-docker-data-pvc"
namespace = kubernetes_namespace.twentycrm.metadata.0.name
}
spec {
access_modes = ["ReadWriteOnce"]
resources {
requests = {
storage = var.twentycrm_docker_data_pvc_requests
}
}
volume_name = kubernetes_persistent_volume.docker_data.metadata.0.name
}
}
+19 -6
View File
@@ -1,3 +1,18 @@
locals {
tokens = [
"accessToken",
"loginToken",
"refreshToken",
"fileToken"
]
}
resource "random_bytes" "this" {
for_each = toset(local.tokens)
length = 32
}
resource "kubernetes_secret" "twentycrm_tokens" { resource "kubernetes_secret" "twentycrm_tokens" {
metadata { metadata {
name = "tokens" name = "tokens"
@@ -5,11 +20,9 @@ resource "kubernetes_secret" "twentycrm_tokens" {
} }
data = { data = {
accessToken = var.twentycrm_token_accessToken accessToken = random_bytes.this["accessToken"].base64
loginToken = var.twentycrm_token_loginToken loginToken = random_bytes.this["loginToken"].base64
refreshToken = var.twentycrm_token_refreshToken refreshToken = random_bytes.this["refreshToken"].base64
fileToken = var.twentycrm_token_fileToken fileToken = random_bytes.this["fileToken"].base64
} }
# type = "kubernetes.io/basic-auth"
} }
@@ -0,0 +1,18 @@
resource "kubernetes_service" "twentycrm_redis" {
metadata {
name = "${var.twentycrm_app_name}-redis"
namespace = kubernetes_namespace.twentycrm.metadata.0.name
}
spec {
selector = {
app = "${var.twentycrm_app_name}-redis"
}
session_affinity = "ClientIP"
port {
port = 6379
target_port = 6379
}
type = "ClusterIP"
}
}
+39 -27
View File
@@ -1,30 +1,6 @@
###################### ######################
# Required Variables # # Required Variables #
###################### ######################
variable "twentycrm_token_accessToken" {
type = string
description = "TwentyCRM access Token"
sensitive = true
}
variable "twentycrm_token_loginToken" {
type = string
description = "TwentyCRM login Token"
sensitive = true
}
variable "twentycrm_token_refreshToken" {
type = string
description = "TwentyCRM refresh Token"
sensitive = true
}
variable "twentycrm_token_fileToken" {
type = string
description = "TwentyCRM file Token"
sensitive = true
}
variable "twentycrm_pgdb_admin_password" { variable "twentycrm_pgdb_admin_password" {
type = string type = string
description = "TwentyCRM password for postgres database." description = "TwentyCRM password for postgres database."
@@ -53,7 +29,7 @@ variable "twentycrm_server_image" {
variable "twentycrm_db_image" { variable "twentycrm_db_image" {
type = string type = string
default = "twentycrm/twenty-postgres:latest" default = "twentycrm/twenty-postgres-spilo:latest"
description = "TwentyCRM image for database deployment. This defaults to latest." description = "TwentyCRM image for database deployment. This defaults to latest."
} }
@@ -77,8 +53,8 @@ variable "twentycrm_db_replicas" {
variable "twentycrm_server_data_mount_path" { variable "twentycrm_server_data_mount_path" {
type = string type = string
default = "/app/docker-data" default = "/app/packages/twenty-server/.local-storage"
description = "TwentyCRM mount path for servers application data. Defaults to '/app/docker-data'." description = "TwentyCRM mount path for servers application data. Defaults to '/app/packages/twenty-server/.local-storage'."
} }
variable "twentycrm_db_pv_path" { variable "twentycrm_db_pv_path" {
@@ -122,3 +98,39 @@ variable "twentycrm_namespace" {
default = "twentycrm" default = "twentycrm"
description = "Namespace for all TwentyCRM resources" 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."
}
@@ -0,0 +1,24 @@
receivers:
otlp:
protocols:
http:
endpoint: "0.0.0.0:4318"
exporters:
clickhouse:
endpoint: tcp://twenty_clickhouse:9000
database: twenty_dev
username: default
password: devPassword
debug:
verbosity: detailed
processors:
batch:
service:
pipelines:
metrics:
receivers: [otlp]
processors: [batch]
exporters: [clickhouse, debug]
+48
View File
@@ -0,0 +1,48 @@
# How to deploy twenty on podman
DISCLAIMER: The k8s and podman deployments are not maintained by the core team.
These files are provided and maintained by the community. Twenty core team
maintains support for docker deployment.
## How to use
1. Edit `.env` file. At the minimum set `POSTGRES_PASSWORD`, `SERVER_URL`, and `APP_SECRET`.
2. Start twenty by running `podman-compose up -d`.
If you need to stop twenty, you can do so by running `podman-compose down`.
### Install systemd service (optional)
If you want to install a systemd service to run twenty, you can use the provided systemd service.
Edit `twentycrm.service` and change these two variables:
WorkingDirectory=/opt/apps/twenty
EnvironmentFile=/opt/apps/twenty/.env
`WorkingDirectory` should be changed to the path in which `podman-compose.yml` is located.
`EnvironmentFile` should be changed to the path in which your `.env`file is located.
You can run the script `install-systemd-user-service` to install the systemd service under the current user.
./install-systemd-user-service
Note: this script will enable the service and also start it. So it will assume that twenty is not currently running.
If you started it previously, bring it down using:
podman-compose down
## Compatibility
These files should be compatible with podman 4.3+.
I have tested this on Debian GNU/Linux 12 (bookworm) and with the podman that is distributed with the official Debian stable mirrors (podman v4.3.1+ds1-8+deb12u1, podman-compose v1.0.3-3).
+11
View File
@@ -0,0 +1,11 @@
#!/bin/bash
set -e
mkdir -p ~/.config/systemd/user
[ -f twentycrm.service ] || { echo "Error: twentycrm.service not found"; exit 1; }
cp twentycrm.service ~/.config/systemd/user
systemctl --user daemon-reload
systemctl --user enable twentycrm.service
systemctl --user start twentycrm.service
@@ -0,0 +1,71 @@
#!/bin/bash
set -e
if [ ! -f "$(dirname "$0")/.env" ]; then
echo "Error: .env file not found"
exit 1
fi
source "$(dirname "$0")/.env"
## steps to cleanup and start over from scratch - useful when testing
#podman pod stop twenty-pod
#podman pod rm twenty-pod
#podman volume rm twenty-db-data twenty-server-data twenty-redis-data
# end of cleanup
podman volume create twenty-db-data
podman volume create twenty-server-data
podman volume create twenty-redis-data
podman pod create --name twenty-pod -p 127.0.0.1:8080:3000
podman run -d --pod twenty-pod --name twenty-db \
-e POSTGRES_DB=twenty \
-e POSTGRES_USER=twenty \
-e POSTGRES_PASSWORD="$POSTGRES_PASSWORD" \
-v twenty-db-data:/var/lib/postgresql/data:Z \
docker.io/library/postgres:16
podman run -d --pod twenty-pod --name twenty-redis \
-v twenty-redis-data:/data:Z \
docker.io/library/redis:latest
podman run -d --pod twenty-pod --name twenty-server \
-e NODE_PORT=3000 \
-e SERVER_URL="$SERVER_URL" \
-e PG_DATABASE_URL="postgresql://twenty:$POSTGRES_PASSWORD@twenty-db:5432/twenty" \
-e REDIS_URL="redis://twenty-redis:6379" \
-e APP_SECRET="$APP_SECRET" \
-e NODE_ENV=production \
-e LOG_LEVEL=info \
-v twenty-server-data:/app/docker-data:Z \
docker.io/twentycrm/twenty:latest
podman run -d --pod twenty-pod --name twenty-worker \
--init \
-e SERVER_URL="$SERVER_URL" \
-e PG_DATABASE_URL="postgresql://twenty:$POSTGRES_PASSWORD@twenty-db:5432/twenty" \
-e REDIS_URL="redis://twenty-redis:6379" \
-e APP_SECRET="$APP_SECRET" \
-e DISABLE_DB_MIGRATIONS=true \
-e NODE_ENV=production \
-e LOG_LEVEL=info \
-v twenty-server-data:/app/docker-data:Z \
docker.io/twentycrm/twenty:latest \
yarn worker:prod
# wait some time, check status
sleep 30
podman ps --pod -f name=twenty-pod
mkdir -p ~/.config/systemd/user
if [ ! -f "twentycrm.service" ]; then
echo "Error: twentycrm.service file not found"
exit 1
fi
cp twentycrm.service ~/.config/systemd/user
systemctl --user daemon-reload
systemctl --user enable twentycrm.service
systemctl --user start twentycrm.service
+56
View File
@@ -0,0 +1,56 @@
version: "3.8"
services:
db:
container_name: twenty-db
image: postgres:16
environment:
POSTGRES_DB: twenty
POSTGRES_USER: twenty
POSTGRES_PASSWORD: ${PG_DATABASE_PASSWORD}
volumes:
- twenty-db-data:/var/lib/postgresql/data:Z
redis:
container_name: twenty-redis
image: redis:latest
command: ["--maxmemory-policy", "noeviction"]
volumes:
- twenty-redis-data:/data:Z
server:
container_name: twenty-server
image: twentycrm/twenty:latest
environment:
NODE_PORT: "3000"
SERVER_URL: ${SERVER_URL}
PG_DATABASE_URL: "postgresql://twenty:${PG_DATABASE_PASSWORD}@twenty-db:5432/twenty"
REDIS_URL: "redis://twenty-redis:6379"
APP_SECRET: ${APP_SECRET}
NODE_ENV: production
LOG_LEVEL: info
volumes:
- twenty-server-data:/app/docker-data:Z
ports:
- 127.0.0.1:8080:3000
worker:
container_name: twenty-worker
image: twentycrm/twenty:latest
command: yarn worker:prod
environment:
SERVER_URL: ${SERVER_URL}
PG_DATABASE_URL: "postgresql://twenty:${PG_DATABASE_PASSWORD}@twenty-db:5432/twenty"
REDIS_URL: "redis://twenty-redis:6379"
APP_SECRET: ${APP_SECRET}
DISABLE_DB_MIGRATIONS: "true"
NODE_ENV: production
LOG_LEVEL: info
volumes:
- twenty-server-data:/app/docker-data:Z
init: true
volumes:
twenty-db-data:
twenty-server-data:
twenty-redis-data:
+15
View File
@@ -0,0 +1,15 @@
[Unit]
Description=TwentyCRM Container Stack via Podman-Compose
After=network.target
[Service]
Type=simple
WorkingDirectory=/opt/apps/twenty
EnvironmentFile=/opt/apps/twenty/.env
ExecStart=/usr/bin/podman-compose -f podman-compose.yml up -d
ExecStop=/usr/bin/podman-compose -f podman-compose.yml down
RemainAfterExit=yes
[Install]
WantedBy=default.target
+22
View File
@@ -0,0 +1,22 @@
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
@@ -0,0 +1,167 @@
#!/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 32)" >> .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
+6 -16
View File
@@ -1,13 +1,12 @@
ARG POSTGRES_VERSION=15 ARG POSTGRES_VERSION=15
ARG SPILO_VERSION=3.2-p1 ARG SPILO_VERSION=3.2-p1
ARG PG_GRAPHQL_VERSION=1.5.6
ARG WRAPPERS_VERSION=0.2.0 ARG WRAPPERS_VERSION=0.2.0
# Build the mysql_fdw extension # Build the mysql_fdw extension
FROM debian:bookworm as build-mysql_fdw FROM debian:bookworm AS build-mysql_fdw
ARG POSTGRES_VERSION ARG POSTGRES_VERSION
ENV DEBIAN_FRONTEND noninteractive ENV DEBIAN_FRONTEND=noninteractive
RUN apt update && \ RUN apt update && \
apt install -y \ apt install -y \
build-essential \ build-essential \
@@ -18,14 +17,14 @@ RUN apt update && \
# Install mysql_fdw # Install mysql_fdw
RUN git clone https://github.com/EnterpriseDB/mysql_fdw.git RUN git clone https://github.com/EnterpriseDB/mysql_fdw.git
WORKDIR mysql_fdw WORKDIR /mysql_fdw
RUN make USE_PGXS=1 RUN make USE_PGXS=1
# Build libssl for wrappers # Build libssl for wrappers
FROM ubuntu:22.04 as build-libssl FROM ubuntu:22.04 AS build-libssl
ENV DEBIAN_FRONTEND noninteractive ENV DEBIAN_FRONTEND=noninteractive
RUN apt update && \ RUN apt update && \
apt install -y \ apt install -y \
build-essential \ build-essential \
@@ -38,10 +37,9 @@ WORKDIR /build/openssl
RUN ./config && make && make install RUN ./config && make && make install
# Extend the Spilo image with the pg_graphql and mysql_fdw extensions # Extend the Spilo image with the mysql_fdw extensions
FROM ghcr.io/zalando/spilo-${POSTGRES_VERSION}:${SPILO_VERSION} FROM ghcr.io/zalando/spilo-${POSTGRES_VERSION}:${SPILO_VERSION}
ARG POSTGRES_VERSION ARG POSTGRES_VERSION
ARG PG_GRAPHQL_VERSION
ARG WRAPPERS_VERSION ARG WRAPPERS_VERSION
ARG TARGETARCH ARG TARGETARCH
@@ -63,14 +61,6 @@ RUN curl -L "https://github.com/supabase/wrappers/releases/download/v${WRAPPERS_
COPY --from=build-libssl /usr/local/lib/libssl* /usr/local/lib/libcrypto* /usr/lib/ 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 --from=build-libssl /usr/local/lib/engines-1.1 /usr/lib/engines-1.1
# Copy pg_graphql
COPY ./packages/twenty-postgres/linux/${TARGETARCH}/${POSTGRES_VERSION}/pg_graphql/${PG_GRAPHQL_VERSION}/pg_graphql--${PG_GRAPHQL_VERSION}.sql \
/usr/share/postgresql/${POSTGRES_VERSION}/extension
COPY ./packages/twenty-postgres/linux/${TARGETARCH}/${POSTGRES_VERSION}/pg_graphql/${PG_GRAPHQL_VERSION}/pg_graphql.control \
/usr/share/postgresql/${POSTGRES_VERSION}/extension
COPY ./packages/twenty-postgres/linux/${TARGETARCH}/${POSTGRES_VERSION}/pg_graphql/${PG_GRAPHQL_VERSION}/pg_graphql.so \
/usr/lib/postgresql/${POSTGRES_VERSION}/lib/pg_graphql.so
# Copy mysql_fdw # Copy mysql_fdw
COPY --from=build-mysql_fdw /mysql_fdw/mysql_fdw.so \ COPY --from=build-mysql_fdw /mysql_fdw/mysql_fdw.so \
/usr/lib/postgresql/${POSTGRES_VERSION}/lib/mysql_fdw.so /usr/lib/postgresql/${POSTGRES_VERSION}/lib/mysql_fdw.so
-54
View File
@@ -1,54 +0,0 @@
ARG IMAGE_TAG='15.5.0-debian-11-r15'
FROM bitnami/postgresql:${IMAGE_TAG}
ARG PG_MAIN_VERSION=15
ARG PG_GRAPHQL_VERSION=1.5.6
ARG WRAPPERS_VERSION=0.2.0
ARG TARGETARCH
USER root
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 build-essential git curl default-libmysqlclient-dev -y
# Install precompiled pg_graphql extensions
COPY ./packages/twenty-postgres/linux/${TARGETARCH}/${PG_MAIN_VERSION}/pg_graphql/${PG_GRAPHQL_VERSION}/pg_graphql--${PG_GRAPHQL_VERSION}.sql \
/opt/bitnami/postgresql/share/extension/
COPY ./packages/twenty-postgres/linux/${TARGETARCH}/${PG_MAIN_VERSION}/pg_graphql/${PG_GRAPHQL_VERSION}/pg_graphql.control \
/opt/bitnami/postgresql/share/extension/
COPY ./packages/twenty-postgres/linux/${TARGETARCH}/${PG_MAIN_VERSION}/pg_graphql/${PG_GRAPHQL_VERSION}/pg_graphql.so \
/opt/bitnami/postgresql/lib/
# Install precompiled supabase wrappers extensions
RUN curl -L "https://github.com/supabase/wrappers/releases/download/v${WRAPPERS_VERSION}/wrappers-v${WRAPPERS_VERSION}-pg${PG_MAIN_VERSION}-${TARGETARCH}-linux-gnu.deb" -o wrappers.deb
RUN dpkg --install wrappers.deb
RUN cp /usr/share/postgresql/${PG_MAIN_VERSION}/extension/wrappers* /opt/bitnami/postgresql/share/extension/
RUN cp /usr/lib/postgresql/${PG_MAIN_VERSION}/lib/wrappers* /opt/bitnami/postgresql/lib/
RUN export PATH=/usr/local/pgsql/bin/:$PATH
RUN export PATH=/usr/local/mysql/bin/:$PATH
RUN git clone https://github.com/EnterpriseDB/mysql_fdw.git
WORKDIR mysql_fdw
RUN make USE_PGXS=1
RUN make USE_PGXS=1 install
COPY ./packages/twenty-docker/twenty-postgres/init.sql /docker-entrypoint-initdb.d/
USER 1001
ENTRYPOINT ["/opt/bitnami/scripts/postgresql/entrypoint.sh"]
CMD ["/opt/bitnami/scripts/postgresql/run.sh"]
-4
View File
@@ -1,4 +0,0 @@
CREATE DATABASE "default";
CREATE DATABASE "test";
CREATE USER twenty PASSWORD 'twenty';
ALTER ROLE twenty superuser;
+15 -2
View File
@@ -1,4 +1,4 @@
FROM node:18.17.1-alpine as twenty-website-build FROM node:22-alpine as twenty-website-build
WORKDIR /app WORKDIR /app
@@ -8,14 +8,22 @@ COPY ./yarn.lock .
COPY ./.yarnrc.yml . COPY ./.yarnrc.yml .
COPY ./.yarn/releases /app/.yarn/releases COPY ./.yarn/releases /app/.yarn/releases
COPY ./tools/eslint-rules /app/tools/eslint-rules COPY ./tools/eslint-rules /app/tools/eslint-rules
COPY ./packages/twenty-ui/package.json /app/packages/twenty-ui/
COPY ./packages/twenty-shared/package.json /app/packages/twenty-shared/
COPY ./packages/twenty-website/package.json /app/packages/twenty-website/package.json COPY ./packages/twenty-website/package.json /app/packages/twenty-website/package.json
RUN yarn RUN yarn
ENV KEYSTATIC_GITHUB_CLIENT_ID="<fake build value>"
ENV KEYSTATIC_GITHUB_CLIENT_SECRET="<fake build value>"
ENV KEYSTATIC_SECRET="<fake build value>"
ENV NEXT_PUBLIC_KEYSTATIC_GITHUB_APP_SLUG="<fake build value>"
COPY ./packages/twenty-ui /app/packages/twenty-ui
COPY ./packages/twenty-website /app/packages/twenty-website COPY ./packages/twenty-website /app/packages/twenty-website
RUN npx nx build twenty-website RUN npx nx build twenty-website
FROM node:18.17.1-alpine as twenty-website FROM node:22-alpine as twenty-website
WORKDIR /app/packages/twenty-website WORKDIR /app/packages/twenty-website
@@ -26,4 +34,9 @@ WORKDIR /app/packages/twenty-website
LABEL org.opencontainers.image.source=https://github.com/twentyhq/twenty 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." LABEL org.opencontainers.image.description="This image provides a consistent and reproducible environment for the website."
RUN chown -R 1000 /app
# Use non root user with uid 1000
USER 1000
CMD ["/bin/sh", "-c", "npx nx start"] CMD ["/bin/sh", "-c", "npx nx start"]
+16 -8
View File
@@ -1,5 +1,5 @@
# Base image for common dependencies # Base image for common dependencies
FROM node:18.17.1-alpine as common-deps FROM node:22-alpine as common-deps
WORKDIR /app WORKDIR /app
@@ -7,10 +7,12 @@ WORKDIR /app
COPY ./package.json ./yarn.lock ./.yarnrc.yml ./tsconfig.base.json ./nx.json /app/ COPY ./package.json ./yarn.lock ./.yarnrc.yml ./tsconfig.base.json ./nx.json /app/
COPY ./.yarn/releases /app/.yarn/releases COPY ./.yarn/releases /app/.yarn/releases
COPY ./.prettierrc /app/
COPY ./packages/twenty-emails/package.json /app/packages/twenty-emails/ COPY ./packages/twenty-emails/package.json /app/packages/twenty-emails/
COPY ./packages/twenty-server/package.json /app/packages/twenty-server/ COPY ./packages/twenty-server/package.json /app/packages/twenty-server/
COPY ./packages/twenty-server/patches /app/packages/twenty-server/patches COPY ./packages/twenty-server/patches /app/packages/twenty-server/patches
COPY ./packages/twenty-ui/package.json /app/packages/twenty-ui/ 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/ COPY ./packages/twenty-front/package.json /app/packages/twenty-front/
# Install all dependencies # Install all dependencies
@@ -22,6 +24,7 @@ FROM common-deps as twenty-server-build
# Copy sourcecode after installing dependences to accelerate subsequents builds # Copy sourcecode after installing dependences to accelerate subsequents builds
COPY ./packages/twenty-emails /app/packages/twenty-emails COPY ./packages/twenty-emails /app/packages/twenty-emails
COPY ./packages/twenty-shared /app/packages/twenty-shared
COPY ./packages/twenty-server /app/packages/twenty-server COPY ./packages/twenty-server /app/packages/twenty-server
RUN npx nx run twenty-server:build RUN npx nx run twenty-server:build
@@ -31,7 +34,7 @@ RUN mv /app/packages/twenty-server/dist/package.json /app/packages/twenty-server
RUN rm -rf /app/packages/twenty-server/dist RUN rm -rf /app/packages/twenty-server/dist
RUN mv /app/packages/twenty-server/build /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-server RUN yarn workspaces focus --production twenty-emails twenty-shared twenty-server
# Build the front # Build the front
@@ -41,24 +44,29 @@ ARG REACT_APP_SERVER_BASE_URL
COPY ./packages/twenty-front /app/packages/twenty-front COPY ./packages/twenty-front /app/packages/twenty-front
COPY ./packages/twenty-ui /app/packages/twenty-ui COPY ./packages/twenty-ui /app/packages/twenty-ui
COPY ./packages/twenty-shared /app/packages/twenty-shared
RUN npx nx build twenty-front RUN npx nx build twenty-front
# Final stage: Run the application # Final stage: Run the application
FROM node:18.17.1-alpine as twenty FROM node:22-alpine as twenty
# Used to run healthcheck in docker # Used to run healthcheck in docker
RUN apk add --no-cache curl jq 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 COPY ./packages/twenty-docker/twenty/entrypoint.sh /app/entrypoint.sh
RUN chmod +x /app/entrypoint.sh RUN chmod +x /app/entrypoint.sh
WORKDIR /app/packages/twenty-server WORKDIR /app/packages/twenty-server
ARG REACT_APP_SERVER_BASE_URL ARG REACT_APP_SERVER_BASE_URL
ENV REACT_APP_SERVER_BASE_URL $REACT_APP_SERVER_BASE_URL ENV REACT_APP_SERVER_BASE_URL $REACT_APP_SERVER_BASE_URL
ARG SENTRY_RELEASE
ENV SENTRY_RELEASE $SENTRY_RELEASE ARG APP_VERSION
ENV APP_VERSION $APP_VERSION
# Copy built applications from previous stages # Copy built applications from previous stages
COPY --chown=1000 --from=twenty-server-build /app /app COPY --chown=1000 --from=twenty-server-build /app /app
@@ -69,8 +77,8 @@ COPY --chown=1000 --from=twenty-front-build /app/packages/twenty-front/build /ap
LABEL org.opencontainers.image.source=https://github.com/twentyhq/twenty 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." 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 mkdir -p /app/.local-storage /app/packages/twenty-server/.local-storage && \
RUN chown -R 1000 /app chown -R 1000:1000 /app
# Use non root user with uid 1000 # Use non root user with uid 1000
USER 1000 USER 1000
+42 -9
View File
@@ -1,17 +1,50 @@
#!/bin/sh #!/bin/sh
set -e
setup_and_migrate_db() {
if [ "${DISABLE_DB_MIGRATIONS}" = "true" ]; then
echo "Database setup and migrations are disabled, skipping..."
return
fi
# Check if the initialization has already been done and that we enabled automatic migration
if [ "${ENABLE_DB_MIGRATIONS}" = "true" ] && [ ! -f /app/docker-data/db_status ]; then
echo "Running database setup and migrations..." echo "Running database setup and migrations..."
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}')
PGDATABASE=$(echo $PG_DATABASE_URL | awk -F '/' '{print $NF}' | cut -d'?' -f1)
# Run setup and migration scripts # Creating the database if it doesn't exist
NODE_OPTIONS="--max-old-space-size=1500" npx ts-node ./scripts/setup-db.ts db_count=$(PGPASSWORD=${PGPASS} psql -h ${PGHOST} -p ${PGPORT} -U ${PGUSER} -d postgres -tAc "SELECT COUNT(*) FROM pg_database WHERE datname = '${PGDATABASE}'")
yarn database:migrate:prod if [ "$db_count" = "0" ]; then
echo "Database ${PGDATABASE} does not exist, creating..."
PGPASSWORD=${PGPASS} psql -h ${PGHOST} -p ${PGPORT} -U ${PGUSER} -d postgres -c "CREATE DATABASE \"${PGDATABASE}\""
# Mark initialization as done # Run setup and migration scripts
echo "Successfuly migrated DB!" NODE_OPTIONS="--max-old-space-size=1500" tsx ./scripts/setup-db.ts
touch /app/docker-data/db_status yarn database:migrate:prod
fi fi
yarn command:prod upgrade
echo "Successfully migrated DB!"
}
register_background_jobs() {
if [ "${DISABLE_CRON_JOBS_REGISTRATION}" = "true" ]; then
echo "Cron job registration is disabled, skipping..."
return
fi
echo "Registering background sync jobs..."
if yarn command:prod cron:register:all; then
echo "Successfully registered all background sync jobs!"
else
echo "Warning: Failed to register background jobs, but continuing startup..."
fi
}
setup_and_migrate_db
register_background_jobs
# Continue with the original Docker command # Continue with the original Docker command
exec "$@" exec "$@"
+25
View File
@@ -0,0 +1,25 @@
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"
);
+16
View File
@@ -0,0 +1,16 @@
import { execa } from "execa";
import { glob } from "glob";
import path from "path";
const files = await glob("*/update.js", { absolute: true });
for (const file of files) {
console.log(`Executing ${file}`);
await execa("node", ["update.js"], {
stdio: "inherit",
cwd: path.dirname(file),
});
console.log(`--------------------------------`);
}
+92
View File
@@ -0,0 +1,92 @@
import { execa } from "execa";
import fs from "fs";
import yaml from "yaml";
async function cloneOrPullRepo({
repo,
path = "./repo",
branch = "main",
depth = 1,
}) {
if (!fs.existsSync(path)) {
console.log(`Cloning ${repo} into ${path}`);
await execa(
"git",
[
"clone",
["--depth", depth],
["--branch", branch],
"--single-branch",
repo,
path,
].flat()
);
} else {
console.log(`Pulling ${repo} into ${path}`);
await execa("git", ["pull"], { cwd: path });
}
}
async function removeContainerNames(path) {
console.log(`Removing container names from ${path}`);
const file = await fs.promises.readFile(path, "utf8");
const document = yaml.parseDocument(file);
document.get("services").items.forEach((item) => {
item.value.delete("container_name");
});
await fs.promises.writeFile(path, document.toString());
}
async function removePorts(path) {
console.log(`Removing ports from ${path}`);
const file = await fs.promises.readFile(path, "utf8");
const document = yaml.parseDocument(file);
document.get("services").items.forEach((item) => {
item.value.delete("ports");
});
await fs.promises.writeFile(path, document.toString());
}
async function copyDir(src, dest) {
console.log(`Copying ${src} to ${dest}`);
await execa("rm", ["-rf", dest]);
await execa("cp", ["-r", src, dest]);
}
async function downloadFile(url, dest) {
console.log(`Downloading ${url} to ${dest}`);
await execa("curl", ["-s", url, "-o", dest]);
}
async function renameFile(src, dest) {
console.log(`Renaming ${src} to ${dest}`);
await execa("mv", [src, dest]);
}
async function searchReplace(path, search, replace) {
console.log(`Searching and replacing ${search} with ${replace} in ${path}`);
const file = await fs.promises.readFile(path, "utf8");
const newFile = file.replaceAll(search, replace);
await fs.promises.writeFile(path, newFile);
}
export default {
cloneOrPullRepo,
removeContainerNames,
removePorts,
copyDir,
downloadFile,
renameFile,
searchReplace,
};