Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e0e7cbeeef | |||
| 405fd49534 | |||
| f57b86d84f | |||
| 5fac760f2a | |||
| aa05d8edec | |||
| 9c2502c8d8 | |||
| e9a2778e17 | |||
| e466f70643 | |||
| bce0268b02 | |||
| 3da4af5431 | |||
| 0b3cb0b5d3 | |||
| 9d7cf80691 | |||
| fec2d9955c | |||
| b16791dd7a | |||
| c82da10738 | |||
| f0fd148d95 | |||
| 334f94878b | |||
| e6ca3d4c99 | |||
| e75da89239 | |||
| 2466ad1785 | |||
| 662394d56d |
@@ -1 +1,2 @@
|
||||
repo
|
||||
node_modules
|
||||
|
||||
@@ -3,17 +3,24 @@ _APP_LOCALE=en
|
||||
_APP_OPTIONS_ABUSE=enabled
|
||||
_APP_OPTIONS_FORCE_HTTPS=disabled
|
||||
_APP_OPTIONS_FUNCTIONS_FORCE_HTTPS=disabled
|
||||
_APP_OPTIONS_ROUTER_FORCE_HTTPS=disabled
|
||||
_APP_OPTIONS_ROUTER_PROTECTION=disabled
|
||||
_APP_OPENSSL_KEY_V1=your-secret-key
|
||||
_APP_DOMAIN=localhost
|
||||
_APP_CUSTOM_DOMAIN_DENY_LIST=example.com,test.com,app.example.com
|
||||
_APP_DOMAIN_FUNCTIONS=functions.localhost
|
||||
_APP_DOMAIN_SITES=sites.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_EMAILS=
|
||||
_APP_CONSOLE_WHITELIST_IPS=
|
||||
_APP_CONSOLE_HOSTNAMES=
|
||||
_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_SECURITY_EMAIL_ADDRESS=certs@appwrite.io
|
||||
_APP_EMAIL_SECURITY=
|
||||
@@ -25,6 +32,9 @@ _APP_USAGE_AGGREGATION_INTERVAL=30
|
||||
_APP_USAGE_TIMESERIES_INTERVAL=30
|
||||
_APP_USAGE_DATABASE_INTERVAL=900
|
||||
_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_PORT=6379
|
||||
_APP_REDIS_USER=
|
||||
@@ -56,6 +66,7 @@ _APP_STORAGE_S3_ACCESS_KEY=
|
||||
_APP_STORAGE_S3_SECRET=
|
||||
_APP_STORAGE_S3_REGION=us-east-1
|
||||
_APP_STORAGE_S3_BUCKET=
|
||||
_APP_STORAGE_S3_ENDPOINT=
|
||||
_APP_STORAGE_DO_SPACES_ACCESS_KEY=
|
||||
_APP_STORAGE_DO_SPACES_SECRET=
|
||||
_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_BUCKET=
|
||||
_APP_FUNCTIONS_SIZE_LIMIT=30000000
|
||||
_APP_COMPUTE_SIZE_LIMIT=30000000
|
||||
_APP_FUNCTIONS_BUILD_SIZE_LIMIT=2000000000
|
||||
_APP_FUNCTIONS_TIMEOUT=900
|
||||
_APP_FUNCTIONS_BUILD_TIMEOUT=900
|
||||
_APP_COMPUTE_BUILD_TIMEOUT=900
|
||||
_APP_FUNCTIONS_CONTAINERS=10
|
||||
_APP_FUNCTIONS_CPUS=0
|
||||
_APP_COMPUTE_CPUS=0
|
||||
_APP_FUNCTIONS_MEMORY=0
|
||||
_APP_COMPUTE_MEMORY=0
|
||||
_APP_FUNCTIONS_MEMORY_SWAP=0
|
||||
_APP_FUNCTIONS_RUNTIMES=node-16.0,php-8.0,python-3.9,ruby-3.0
|
||||
_APP_EXECUTOR_SECRET=your-secret-key
|
||||
@@ -85,14 +101,19 @@ _APP_EXECUTOR_HOST=http://exc1/v1
|
||||
_APP_EXECUTOR_RUNTIME_NETWORK=appwrite_runtimes
|
||||
_APP_FUNCTIONS_ENVS=node-16.0,php-7.4,python-3.9,ruby-3.0
|
||||
_APP_FUNCTIONS_INACTIVE_THRESHOLD=60
|
||||
_APP_COMPUTE_INACTIVE_THRESHOLD=60
|
||||
DOCKERHUB_PULL_USERNAME=
|
||||
DOCKERHUB_PULL_PASSWORD=
|
||||
DOCKERHUB_PULL_EMAIL=
|
||||
OPEN_RUNTIMES_NETWORK=appwrite_runtimes
|
||||
_APP_FUNCTIONS_RUNTIMES_NETWORK=runtimes
|
||||
_APP_COMPUTE_RUNTIMES_NETWORK=runtimes
|
||||
_APP_DOCKER_HUB_USERNAME=
|
||||
_APP_DOCKER_HUB_PASSWORD=
|
||||
_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_PRIVATE_KEY=
|
||||
_APP_VCS_GITHUB_APP_ID=
|
||||
@@ -101,9 +122,11 @@ _APP_VCS_GITHUB_CLIENT_SECRET=
|
||||
_APP_VCS_GITHUB_WEBHOOK_SECRET=
|
||||
_APP_MAINTENANCE_INTERVAL=86400
|
||||
_APP_MAINTENANCE_DELAY=0
|
||||
_APP_MAINTENANCE_START_TIME=00:00
|
||||
_APP_MAINTENANCE_RETENTION_CACHE=2592000
|
||||
_APP_MAINTENANCE_RETENTION_EXECUTION=1209600
|
||||
_APP_MAINTENANCE_RETENTION_AUDIT=1209600
|
||||
_APP_MAINTENANCE_RETENTION_AUDIT_CONSOLE=15778800
|
||||
_APP_MAINTENANCE_RETENTION_ABUSE=86400
|
||||
_APP_MAINTENANCE_RETENTION_USAGE_HOURLY=8640000
|
||||
_APP_MAINTENANCE_RETENTION_SCHEDULES=86400
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
x-logging: &x-logging
|
||||
logging:
|
||||
driver: "json-file"
|
||||
driver: 'json-file'
|
||||
options:
|
||||
max-file: "5"
|
||||
max-size: "10m"
|
||||
max-file: '5'
|
||||
max-size: '10m'
|
||||
services:
|
||||
traefik:
|
||||
image: traefik:2.11
|
||||
@@ -28,7 +28,7 @@ services:
|
||||
- appwrite
|
||||
|
||||
appwrite:
|
||||
image: appwrite/appwrite:1.5.10
|
||||
image: appwrite/appwrite:1.7.4
|
||||
<<: *x-logging
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
@@ -49,10 +49,13 @@ services:
|
||||
- traefik.http.routers.appwrite_api_https.tls=true
|
||||
volumes:
|
||||
- appwrite-uploads:/storage/uploads:rw
|
||||
- appwrite-imports:/storage/imports:rw
|
||||
- appwrite-cache:/storage/cache:rw
|
||||
- appwrite-config:/storage/config:rw
|
||||
- appwrite-certificates:/storage/certificates:rw
|
||||
- appwrite-functions:/storage/functions:rw
|
||||
- appwrite-sites:/storage/sites:rw
|
||||
- appwrite-builds:/storage/builds:rw
|
||||
depends_on:
|
||||
- mariadb
|
||||
- redis
|
||||
@@ -61,8 +64,10 @@ services:
|
||||
- _APP_ENV
|
||||
- _APP_WORKER_PER_CORE
|
||||
- _APP_LOCALE
|
||||
- _APP_COMPRESSION_MIN_SIZE_BYTES
|
||||
- _APP_CONSOLE_WHITELIST_ROOT
|
||||
- _APP_CONSOLE_WHITELIST_EMAILS
|
||||
- _APP_CONSOLE_SESSION_ALERTS
|
||||
- _APP_CONSOLE_WHITELIST_IPS
|
||||
- _APP_CONSOLE_HOSTNAMES
|
||||
- _APP_SYSTEM_EMAIL_NAME
|
||||
@@ -72,10 +77,12 @@ services:
|
||||
- _APP_OPTIONS_ABUSE
|
||||
- _APP_OPTIONS_ROUTER_PROTECTION
|
||||
- _APP_OPTIONS_FORCE_HTTPS
|
||||
- _APP_OPTIONS_FUNCTIONS_FORCE_HTTPS
|
||||
- _APP_OPTIONS_ROUTER_FORCE_HTTPS
|
||||
- _APP_OPENSSL_KEY_V1
|
||||
- _APP_DOMAIN
|
||||
- _APP_DOMAIN_TARGET
|
||||
- _APP_DOMAIN_TARGET_CNAME
|
||||
- _APP_DOMAIN_TARGET_AAAA
|
||||
- _APP_DOMAIN_TARGET_A
|
||||
- _APP_DOMAIN_FUNCTIONS
|
||||
- _APP_REDIS_HOST
|
||||
- _APP_REDIS_PORT
|
||||
@@ -102,6 +109,7 @@ services:
|
||||
- _APP_STORAGE_S3_SECRET
|
||||
- _APP_STORAGE_S3_REGION
|
||||
- _APP_STORAGE_S3_BUCKET
|
||||
- _APP_STORAGE_S3_ENDPOINT
|
||||
- _APP_STORAGE_DO_SPACES_ACCESS_KEY
|
||||
- _APP_STORAGE_DO_SPACES_SECRET
|
||||
- _APP_STORAGE_DO_SPACES_REGION
|
||||
@@ -118,22 +126,26 @@ services:
|
||||
- _APP_STORAGE_WASABI_SECRET
|
||||
- _APP_STORAGE_WASABI_REGION
|
||||
- _APP_STORAGE_WASABI_BUCKET
|
||||
- _APP_FUNCTIONS_SIZE_LIMIT
|
||||
- _APP_COMPUTE_SIZE_LIMIT
|
||||
- _APP_FUNCTIONS_TIMEOUT
|
||||
- _APP_FUNCTIONS_BUILD_TIMEOUT
|
||||
- _APP_FUNCTIONS_CPUS
|
||||
- _APP_FUNCTIONS_MEMORY
|
||||
- _APP_SITES_TIMEOUT
|
||||
- _APP_COMPUTE_BUILD_TIMEOUT
|
||||
- _APP_COMPUTE_CPUS
|
||||
- _APP_COMPUTE_MEMORY
|
||||
- _APP_FUNCTIONS_RUNTIMES
|
||||
- _APP_SITES_RUNTIMES
|
||||
- _APP_DOMAIN_SITES
|
||||
- _APP_EXECUTOR_SECRET
|
||||
- _APP_EXECUTOR_HOST
|
||||
- _APP_LOGGING_PROVIDER
|
||||
- _APP_LOGGING_CONFIG
|
||||
- _APP_MAINTENANCE_INTERVAL
|
||||
- _APP_MAINTENANCE_DELAY
|
||||
- _APP_MAINTENANCE_START_TIME
|
||||
- _APP_MAINTENANCE_RETENTION_EXECUTION
|
||||
- _APP_MAINTENANCE_RETENTION_CACHE
|
||||
- _APP_MAINTENANCE_RETENTION_ABUSE
|
||||
- _APP_MAINTENANCE_RETENTION_AUDIT
|
||||
- _APP_MAINTENANCE_RETENTION_AUDIT_CONSOLE
|
||||
- _APP_MAINTENANCE_RETENTION_USAGE_HOURLY
|
||||
- _APP_MAINTENANCE_RETENTION_SCHEDULES
|
||||
- _APP_SMS_PROVIDER
|
||||
@@ -151,8 +163,29 @@ services:
|
||||
- _APP_MIGRATIONS_FIREBASE_CLIENT_SECRET
|
||||
- _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:
|
||||
image: appwrite/appwrite:1.5.10
|
||||
image: appwrite/appwrite:1.7.4
|
||||
entrypoint: realtime
|
||||
<<: *x-logging
|
||||
restart: unless-stopped
|
||||
@@ -191,11 +224,10 @@ services:
|
||||
- _APP_DB_USER
|
||||
- _APP_DB_PASS
|
||||
- _APP_USAGE_STATS
|
||||
- _APP_LOGGING_PROVIDER
|
||||
- _APP_LOGGING_CONFIG
|
||||
|
||||
appwrite-worker-audits:
|
||||
image: appwrite/appwrite:1.5.10
|
||||
image: appwrite/appwrite:1.7.4
|
||||
entrypoint: worker-audits
|
||||
<<: *x-logging
|
||||
restart: unless-stopped
|
||||
@@ -217,11 +249,10 @@ services:
|
||||
- _APP_DB_SCHEMA
|
||||
- _APP_DB_USER
|
||||
- _APP_DB_PASS
|
||||
- _APP_LOGGING_PROVIDER
|
||||
- _APP_LOGGING_CONFIG
|
||||
|
||||
appwrite-worker-webhooks:
|
||||
image: appwrite/appwrite:1.5.10
|
||||
image: appwrite/appwrite:1.7.4
|
||||
entrypoint: worker-webhooks
|
||||
<<: *x-logging
|
||||
restart: unless-stopped
|
||||
@@ -245,11 +276,10 @@ services:
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_LOGGING_PROVIDER
|
||||
- _APP_LOGGING_CONFIG
|
||||
|
||||
appwrite-worker-deletes:
|
||||
image: appwrite/appwrite:1.5.10
|
||||
image: appwrite/appwrite:1.7.4
|
||||
entrypoint: worker-deletes
|
||||
<<: *x-logging
|
||||
restart: unless-stopped
|
||||
@@ -262,6 +292,7 @@ services:
|
||||
- appwrite-uploads:/storage/uploads:rw
|
||||
- appwrite-cache:/storage/cache:rw
|
||||
- appwrite-functions:/storage/functions:rw
|
||||
- appwrite-sites:/storage/sites:rw
|
||||
- appwrite-builds:/storage/builds:rw
|
||||
- appwrite-certificates:/storage/certificates:rw
|
||||
environment:
|
||||
@@ -282,6 +313,7 @@ services:
|
||||
- _APP_STORAGE_S3_SECRET
|
||||
- _APP_STORAGE_S3_REGION
|
||||
- _APP_STORAGE_S3_BUCKET
|
||||
- _APP_STORAGE_S3_ENDPOINT
|
||||
- _APP_STORAGE_DO_SPACES_ACCESS_KEY
|
||||
- _APP_STORAGE_DO_SPACES_SECRET
|
||||
- _APP_STORAGE_DO_SPACES_REGION
|
||||
@@ -298,13 +330,18 @@ services:
|
||||
- _APP_STORAGE_WASABI_SECRET
|
||||
- _APP_STORAGE_WASABI_REGION
|
||||
- _APP_STORAGE_WASABI_BUCKET
|
||||
- _APP_LOGGING_PROVIDER
|
||||
- _APP_LOGGING_CONFIG
|
||||
- _APP_EXECUTOR_SECRET
|
||||
- _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:
|
||||
image: appwrite/appwrite:1.5.10
|
||||
image: appwrite/appwrite:1.7.4
|
||||
entrypoint: worker-databases
|
||||
<<: *x-logging
|
||||
restart: unless-stopped
|
||||
@@ -326,11 +363,10 @@ services:
|
||||
- _APP_DB_SCHEMA
|
||||
- _APP_DB_USER
|
||||
- _APP_DB_PASS
|
||||
- _APP_LOGGING_PROVIDER
|
||||
- _APP_LOGGING_CONFIG
|
||||
|
||||
appwrite-worker-builds:
|
||||
image: appwrite/appwrite:1.5.10
|
||||
image: appwrite/appwrite:1.7.4
|
||||
entrypoint: worker-builds
|
||||
<<: *x-logging
|
||||
restart: unless-stopped
|
||||
@@ -341,7 +377,9 @@ services:
|
||||
- mariadb
|
||||
volumes:
|
||||
- appwrite-functions:/storage/functions:rw
|
||||
- appwrite-sites:/storage/sites:rw
|
||||
- appwrite-builds:/storage/builds:rw
|
||||
- appwrite-uploads:/storage/uploads:rw
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_WORKER_PER_CORE
|
||||
@@ -357,24 +395,25 @@ services:
|
||||
- _APP_DB_SCHEMA
|
||||
- _APP_DB_USER
|
||||
- _APP_DB_PASS
|
||||
- _APP_LOGGING_PROVIDER
|
||||
- _APP_LOGGING_CONFIG
|
||||
- _APP_VCS_GITHUB_APP_NAME
|
||||
- _APP_VCS_GITHUB_PRIVATE_KEY
|
||||
- _APP_VCS_GITHUB_APP_ID
|
||||
- _APP_FUNCTIONS_TIMEOUT
|
||||
- _APP_FUNCTIONS_BUILD_TIMEOUT
|
||||
- _APP_FUNCTIONS_CPUS
|
||||
- _APP_FUNCTIONS_MEMORY
|
||||
- _APP_FUNCTIONS_SIZE_LIMIT
|
||||
- _APP_SITES_TIMEOUT
|
||||
- _APP_COMPUTE_BUILD_TIMEOUT
|
||||
- _APP_COMPUTE_CPUS
|
||||
- _APP_COMPUTE_MEMORY
|
||||
- _APP_COMPUTE_SIZE_LIMIT
|
||||
- _APP_OPTIONS_FORCE_HTTPS
|
||||
- _APP_OPTIONS_FUNCTIONS_FORCE_HTTPS
|
||||
- _APP_OPTIONS_ROUTER_FORCE_HTTPS
|
||||
- _APP_DOMAIN
|
||||
- _APP_STORAGE_DEVICE
|
||||
- _APP_STORAGE_S3_ACCESS_KEY
|
||||
- _APP_STORAGE_S3_SECRET
|
||||
- _APP_STORAGE_S3_REGION
|
||||
- _APP_STORAGE_S3_BUCKET
|
||||
- _APP_STORAGE_S3_ENDPOINT
|
||||
- _APP_STORAGE_DO_SPACES_ACCESS_KEY
|
||||
- _APP_STORAGE_DO_SPACES_SECRET
|
||||
- _APP_STORAGE_DO_SPACES_REGION
|
||||
@@ -391,9 +430,10 @@ services:
|
||||
- _APP_STORAGE_WASABI_SECRET
|
||||
- _APP_STORAGE_WASABI_REGION
|
||||
- _APP_STORAGE_WASABI_BUCKET
|
||||
- _APP_DOMAIN_SITES
|
||||
|
||||
appwrite-worker-certificates:
|
||||
image: appwrite/appwrite:1.5.10
|
||||
image: appwrite/appwrite:1.7.4
|
||||
entrypoint: worker-certificates
|
||||
<<: *x-logging
|
||||
restart: unless-stopped
|
||||
@@ -410,7 +450,9 @@ services:
|
||||
- _APP_WORKER_PER_CORE
|
||||
- _APP_OPENSSL_KEY_V1
|
||||
- _APP_DOMAIN
|
||||
- _APP_DOMAIN_TARGET
|
||||
- _APP_DOMAIN_TARGET_CNAME
|
||||
- _APP_DOMAIN_TARGET_AAAA
|
||||
- _APP_DOMAIN_TARGET_A
|
||||
- _APP_DOMAIN_FUNCTIONS
|
||||
- _APP_EMAIL_CERTIFICATES
|
||||
- _APP_REDIS_HOST
|
||||
@@ -422,11 +464,10 @@ services:
|
||||
- _APP_DB_SCHEMA
|
||||
- _APP_DB_USER
|
||||
- _APP_DB_PASS
|
||||
- _APP_LOGGING_PROVIDER
|
||||
- _APP_LOGGING_CONFIG
|
||||
|
||||
appwrite-worker-functions:
|
||||
image: appwrite/appwrite:1.5.10
|
||||
image: appwrite/appwrite:1.7.4
|
||||
entrypoint: worker-functions
|
||||
<<: *x-logging
|
||||
restart: unless-stopped
|
||||
@@ -440,6 +481,8 @@ services:
|
||||
- _APP_ENV
|
||||
- _APP_WORKER_PER_CORE
|
||||
- _APP_OPENSSL_KEY_V1
|
||||
- _APP_DOMAIN
|
||||
- _APP_OPTIONS_FORCE_HTTPS
|
||||
- _APP_REDIS_HOST
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
@@ -450,19 +493,19 @@ services:
|
||||
- _APP_DB_USER
|
||||
- _APP_DB_PASS
|
||||
- _APP_FUNCTIONS_TIMEOUT
|
||||
- _APP_FUNCTIONS_BUILD_TIMEOUT
|
||||
- _APP_FUNCTIONS_CPUS
|
||||
- _APP_FUNCTIONS_MEMORY
|
||||
- _APP_SITES_TIMEOUT
|
||||
- _APP_COMPUTE_BUILD_TIMEOUT
|
||||
- _APP_COMPUTE_CPUS
|
||||
- _APP_COMPUTE_MEMORY
|
||||
- _APP_EXECUTOR_SECRET
|
||||
- _APP_EXECUTOR_HOST
|
||||
- _APP_USAGE_STATS
|
||||
- _APP_DOCKER_HUB_USERNAME
|
||||
- _APP_DOCKER_HUB_PASSWORD
|
||||
- _APP_LOGGING_CONFIG
|
||||
- _APP_LOGGING_PROVIDER
|
||||
|
||||
appwrite-worker-mails:
|
||||
image: appwrite/appwrite:1.5.10
|
||||
image: appwrite/appwrite:1.7.4
|
||||
entrypoint: worker-mails
|
||||
<<: *x-logging
|
||||
restart: unless-stopped
|
||||
@@ -490,11 +533,12 @@ services:
|
||||
- _APP_SMTP_SECURE
|
||||
- _APP_SMTP_USERNAME
|
||||
- _APP_SMTP_PASSWORD
|
||||
- _APP_LOGGING_PROVIDER
|
||||
- _APP_LOGGING_CONFIG
|
||||
- _APP_DOMAIN
|
||||
- _APP_OPTIONS_FORCE_HTTPS
|
||||
|
||||
appwrite-worker-messaging:
|
||||
image: appwrite/appwrite:1.5.10
|
||||
image: appwrite/appwrite:1.7.4
|
||||
entrypoint: worker-messaging
|
||||
<<: *x-logging
|
||||
restart: unless-stopped
|
||||
@@ -517,7 +561,6 @@ services:
|
||||
- _APP_DB_SCHEMA
|
||||
- _APP_DB_USER
|
||||
- _APP_DB_PASS
|
||||
- _APP_LOGGING_PROVIDER
|
||||
- _APP_LOGGING_CONFIG
|
||||
- _APP_SMS_FROM
|
||||
- _APP_SMS_PROVIDER
|
||||
@@ -526,6 +569,7 @@ services:
|
||||
- _APP_STORAGE_S3_SECRET
|
||||
- _APP_STORAGE_S3_REGION
|
||||
- _APP_STORAGE_S3_BUCKET
|
||||
- _APP_STORAGE_S3_ENDPOINT
|
||||
- _APP_STORAGE_DO_SPACES_ACCESS_KEY
|
||||
- _APP_STORAGE_DO_SPACES_SECRET
|
||||
- _APP_STORAGE_DO_SPACES_REGION
|
||||
@@ -544,12 +588,14 @@ services:
|
||||
- _APP_STORAGE_WASABI_BUCKET
|
||||
|
||||
appwrite-worker-migrations:
|
||||
image: appwrite/appwrite:1.5.10
|
||||
image: appwrite/appwrite:1.7.4
|
||||
entrypoint: worker-migrations
|
||||
<<: *x-logging
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
volumes:
|
||||
- appwrite-imports:/storage/imports:rw
|
||||
depends_on:
|
||||
- mariadb
|
||||
environment:
|
||||
@@ -557,7 +603,9 @@ services:
|
||||
- _APP_WORKER_PER_CORE
|
||||
- _APP_OPENSSL_KEY_V1
|
||||
- _APP_DOMAIN
|
||||
- _APP_DOMAIN_TARGET
|
||||
- _APP_DOMAIN_TARGET_CNAME
|
||||
- _APP_DOMAIN_TARGET_AAAA
|
||||
- _APP_DOMAIN_TARGET_A
|
||||
- _APP_EMAIL_SECURITY
|
||||
- _APP_REDIS_HOST
|
||||
- _APP_REDIS_PORT
|
||||
@@ -568,13 +616,12 @@ services:
|
||||
- _APP_DB_SCHEMA
|
||||
- _APP_DB_USER
|
||||
- _APP_DB_PASS
|
||||
- _APP_LOGGING_PROVIDER
|
||||
- _APP_LOGGING_CONFIG
|
||||
- _APP_MIGRATIONS_FIREBASE_CLIENT_ID
|
||||
- _APP_MIGRATIONS_FIREBASE_CLIENT_SECRET
|
||||
|
||||
appwrite-task-maintenance:
|
||||
image: appwrite/appwrite:1.5.10
|
||||
image: appwrite/appwrite:1.7.4
|
||||
entrypoint: maintenance
|
||||
<<: *x-logging
|
||||
restart: unless-stopped
|
||||
@@ -586,7 +633,9 @@ services:
|
||||
- _APP_ENV
|
||||
- _APP_WORKER_PER_CORE
|
||||
- _APP_DOMAIN
|
||||
- _APP_DOMAIN_TARGET
|
||||
- _APP_DOMAIN_TARGET_CNAME
|
||||
- _APP_DOMAIN_TARGET_AAAA
|
||||
- _APP_DOMAIN_TARGET_A
|
||||
- _APP_DOMAIN_FUNCTIONS
|
||||
- _APP_OPENSSL_KEY_V1
|
||||
- _APP_REDIS_HOST
|
||||
@@ -603,12 +652,13 @@ services:
|
||||
- _APP_MAINTENANCE_RETENTION_CACHE
|
||||
- _APP_MAINTENANCE_RETENTION_ABUSE
|
||||
- _APP_MAINTENANCE_RETENTION_AUDIT
|
||||
- _APP_MAINTENANCE_RETENTION_AUDIT_CONSOLE
|
||||
- _APP_MAINTENANCE_RETENTION_USAGE_HOURLY
|
||||
- _APP_MAINTENANCE_RETENTION_SCHEDULES
|
||||
|
||||
appwrite-worker-usage:
|
||||
image: appwrite/appwrite:1.5.10
|
||||
entrypoint: worker-usage
|
||||
appwrite-task-stats-resources:
|
||||
image: appwrite/appwrite:1.7.4
|
||||
entrypoint: stats-resources
|
||||
<<: *x-logging
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
@@ -630,14 +680,42 @@ services:
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_USAGE_STATS
|
||||
- _APP_LOGGING_PROVIDER
|
||||
- _APP_LOGGING_CONFIG
|
||||
- _APP_USAGE_AGGREGATION_INTERVAL
|
||||
- _APP_DATABASE_SHARED_TABLES
|
||||
- _APP_STATS_RESOURCES_INTERVAL
|
||||
|
||||
appwrite-worker-usage-dump:
|
||||
image: appwrite/appwrite:1.5.10
|
||||
entrypoint: worker-usage-dump
|
||||
appwrite-worker-stats-resources:
|
||||
image: appwrite/appwrite:1.7.4
|
||||
entrypoint: worker-stats-resources
|
||||
<<: *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:
|
||||
- appwrite
|
||||
depends_on:
|
||||
@@ -657,12 +735,11 @@ services:
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_USAGE_STATS
|
||||
- _APP_LOGGING_PROVIDER
|
||||
- _APP_LOGGING_CONFIG
|
||||
- _APP_USAGE_AGGREGATION_INTERVAL
|
||||
|
||||
appwrite-task-scheduler-functions:
|
||||
image: appwrite/appwrite:1.5.10
|
||||
image: appwrite/appwrite:1.7.4
|
||||
entrypoint: schedule-functions
|
||||
<<: *x-logging
|
||||
restart: unless-stopped
|
||||
@@ -685,8 +762,32 @@ services:
|
||||
- _APP_DB_USER
|
||||
- _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:
|
||||
image: appwrite/appwrite:1.5.10
|
||||
image: appwrite/appwrite:1.7.4
|
||||
entrypoint: schedule-messages
|
||||
<<: *x-logging
|
||||
restart: unless-stopped
|
||||
@@ -718,12 +819,19 @@ services:
|
||||
environment:
|
||||
- _APP_ASSISTANT_OPENAI_API_KEY
|
||||
|
||||
appwrite-browser:
|
||||
image: appwrite/browser:0.2.4
|
||||
<<: *x-logging
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
|
||||
openruntimes-executor:
|
||||
hostname: exc1
|
||||
<<: *x-logging
|
||||
restart: unless-stopped
|
||||
stop_signal: SIGINT
|
||||
image: openruntimes/executor:0.5.7
|
||||
image: openruntimes/executor:0.7.14
|
||||
networks:
|
||||
- appwrite
|
||||
- runtimes
|
||||
@@ -731,25 +839,27 @@ services:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- appwrite-builds:/storage/builds:rw
|
||||
- appwrite-functions:/storage/functions:rw
|
||||
- appwrite-sites:/storage/sites:rw
|
||||
# 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)
|
||||
- /tmp:/tmp:rw
|
||||
environment:
|
||||
- OPR_EXECUTOR_INACTIVE_TRESHOLD=$_APP_FUNCTIONS_INACTIVE_THRESHOLD
|
||||
- OPR_EXECUTOR_MAINTENANCE_INTERVAL=$_APP_FUNCTIONS_MAINTENANCE_INTERVAL
|
||||
- OPR_EXECUTOR_NETWORK=$_APP_FUNCTIONS_RUNTIMES_NETWORK
|
||||
- OPR_EXECUTOR_INACTIVE_TRESHOLD=$_APP_COMPUTE_INACTIVE_THRESHOLD
|
||||
- OPR_EXECUTOR_MAINTENANCE_INTERVAL=$_APP_COMPUTE_MAINTENANCE_INTERVAL
|
||||
- OPR_EXECUTOR_NETWORK=$_APP_COMPUTE_RUNTIMES_NETWORK
|
||||
- OPR_EXECUTOR_DOCKER_HUB_USERNAME=$_APP_DOCKER_HUB_USERNAME
|
||||
- OPR_EXECUTOR_DOCKER_HUB_PASSWORD=$_APP_DOCKER_HUB_PASSWORD
|
||||
- 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_LOGGING_PROVIDER=$_APP_LOGGING_PROVIDER
|
||||
- OPR_EXECUTOR_RUNTIME_VERSIONS=v5
|
||||
- OPR_EXECUTOR_LOGGING_CONFIG=$_APP_LOGGING_CONFIG
|
||||
- OPR_EXECUTOR_STORAGE_DEVICE=$_APP_STORAGE_DEVICE
|
||||
- OPR_EXECUTOR_STORAGE_S3_ACCESS_KEY=$_APP_STORAGE_S3_ACCESS_KEY
|
||||
- OPR_EXECUTOR_STORAGE_S3_SECRET=$_APP_STORAGE_S3_SECRET
|
||||
- OPR_EXECUTOR_STORAGE_S3_REGION=$_APP_STORAGE_S3_REGION
|
||||
- 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_SECRET=$_APP_STORAGE_DO_SPACES_SECRET
|
||||
- OPR_EXECUTOR_STORAGE_DO_SPACES_REGION=$_APP_STORAGE_DO_SPACES_REGION
|
||||
@@ -781,22 +891,19 @@ services:
|
||||
- MYSQL_USER=${_APP_DB_USER}
|
||||
- MYSQL_PASSWORD=${_APP_DB_PASS}
|
||||
- MARIADB_AUTO_UPGRADE=1
|
||||
command: "mysqld --innodb-flush-method=fsync"
|
||||
command: 'mysqld --innodb-flush-method=fsync'
|
||||
|
||||
redis:
|
||||
image: redis:7.2.4-alpine
|
||||
<<: *x-logging
|
||||
restart: unless-stopped
|
||||
command: >
|
||||
redis-server
|
||||
--maxmemory 512mb
|
||||
--maxmemory-policy allkeys-lru
|
||||
--maxmemory-samples 5
|
||||
redis-server --maxmemory 512mb
|
||||
--maxmemory-policy allkeys-lru --maxmemory-samples 5
|
||||
networks:
|
||||
- appwrite
|
||||
volumes:
|
||||
- appwrite-redis:/data:rw
|
||||
|
||||
# clamav:
|
||||
# image: appwrite/clamav:1.2.0
|
||||
# container_name: appwrite-clamav
|
||||
@@ -819,7 +926,9 @@ volumes:
|
||||
appwrite-redis:
|
||||
appwrite-cache:
|
||||
appwrite-uploads:
|
||||
appwrite-imports:
|
||||
appwrite-certificates:
|
||||
appwrite-functions:
|
||||
appwrite-sites:
|
||||
appwrite-builds:
|
||||
appwrite-config:
|
||||
|
||||
@@ -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
@@ -39,6 +39,12 @@ APP_WEB_URL=
|
||||
# File preview or download Url prefix.
|
||||
# used to display File preview or download Url to the front-end or as Multi-model inputs;
|
||||
# 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=
|
||||
|
||||
# ------------------------------
|
||||
@@ -48,6 +54,16 @@ FILES_URL=
|
||||
# The log level for the application.
|
||||
# Supported values are `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL`
|
||||
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.
|
||||
# It is recommended to turn on this configuration for local development
|
||||
@@ -58,7 +74,11 @@ DEBUG=false
|
||||
# which is convenient for debugging.
|
||||
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.
|
||||
# You can generate a strong key using `openssl rand -base64 42`.
|
||||
SECRET_KEY=sk-9f73s3ljTXVcMT3Blb3ljTqtsKiGHXVcMT3BlbkFJLK7U
|
||||
@@ -66,6 +86,7 @@ SECRET_KEY=sk-9f73s3ljTXVcMT3Blb3ljTqtsKiGHXVcMT3BlbkFJLK7U
|
||||
# Password for admin user initialization.
|
||||
# If left unset, admin user will not be prompted for a password
|
||||
# when creating the initial admin account.
|
||||
# The length of the password cannot exceed 30 characters.
|
||||
INIT_PASSWORD=
|
||||
|
||||
# Deployment environment.
|
||||
@@ -75,7 +96,7 @@ INIT_PASSWORD=
|
||||
DEPLOY_ENV=PRODUCTION
|
||||
|
||||
# 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
|
||||
|
||||
# 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.
|
||||
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.
|
||||
APP_MAX_ACTIVE_REQUESTS=0
|
||||
APP_MAX_EXECUTION_TIME=1200
|
||||
|
||||
# ------------------------------
|
||||
# Container Startup Related Configuration
|
||||
@@ -105,15 +133,18 @@ DIFY_BIND_ADDRESS=0.0.0.0
|
||||
# API service binding port number, default 5001.
|
||||
DIFY_PORT=5001
|
||||
|
||||
# The number of API server workers, i.e., the number of gevent workers.
|
||||
# Formula: number of cpu cores x 2 + 1
|
||||
# The number of API server workers, i.e., the number of workers.
|
||||
# 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
|
||||
SERVER_WORKER_AMOUNT=
|
||||
SERVER_WORKER_AMOUNT=1
|
||||
|
||||
# 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.
|
||||
CELERY_WORKER_CLASS=
|
||||
|
||||
@@ -153,6 +184,12 @@ CELERY_MIN_WORKERS=
|
||||
API_TOOL_DEFAULT_CONNECT_TIMEOUT=10
|
||||
API_TOOL_DEFAULT_READ_TIMEOUT=60
|
||||
|
||||
# -------------------------------
|
||||
# Datasource Configuration
|
||||
# --------------------------------
|
||||
ENABLE_WEBSITE_JINAREADER=true
|
||||
ENABLE_WEBSITE_FIRECRAWL=true
|
||||
ENABLE_WEBSITE_WATERCRAWL=true
|
||||
|
||||
# ------------------------------
|
||||
# Database Configuration
|
||||
@@ -213,6 +250,25 @@ REDIS_PORT=6379
|
||||
REDIS_USERNAME=
|
||||
REDIS_PASSWORD=difyai123456
|
||||
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
|
||||
@@ -221,9 +277,17 @@ REDIS_USE_SSL=false
|
||||
# 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>`
|
||||
# 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
|
||||
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
|
||||
# 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.
|
||||
# Supported values are `local` and `s3` and `azure-blob` and `google-storage` and `tencent-cos`,
|
||||
# Default: `local`
|
||||
STORAGE_TYPE=local
|
||||
STORAGE_TYPE=opendal
|
||||
|
||||
# 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_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.
|
||||
# If set to false, the access key and secret key must be provided.
|
||||
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
|
||||
# The name of the Azure Blob Storage account to use for storing files.
|
||||
#
|
||||
AZURE_BLOB_ACCOUNT_NAME=difyai
|
||||
# The access key to use for authenticating with the Azure Blob Storage account.
|
||||
AZURE_BLOB_ACCOUNT_KEY=difyai
|
||||
# The name of the Azure Blob Storage container to use for storing files.
|
||||
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
|
||||
|
||||
# Google Storage Configuration
|
||||
# The name of the Google Storage bucket to use for storing files.
|
||||
#
|
||||
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=your-google-service-account-json-base64-string
|
||||
GOOGLE_STORAGE_SERVICE_ACCOUNT_JSON_BASE64=
|
||||
|
||||
# The Alibaba Cloud OSS configurations,
|
||||
# only available when STORAGE_TYPE is `aliyun-oss`
|
||||
#
|
||||
ALIYUN_OSS_BUCKET_NAME=your-bucket-name
|
||||
ALIYUN_OSS_ACCESS_KEY=your-access-key
|
||||
ALIYUN_OSS_SECRET_KEY=your-secret-key
|
||||
ALIYUN_OSS_ENDPOINT=https://oss-ap-southeast-1-internal.aliyuncs.com
|
||||
ALIYUN_OSS_REGION=ap-southeast-1
|
||||
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
|
||||
# The name of the Tencent COS bucket to use for storing files.
|
||||
#
|
||||
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
|
||||
# The secret id to use for authenticating with the Tencent COS service.
|
||||
TENCENT_COS_SECRET_ID=your-secret-id
|
||||
# The region of the Tencent COS service.
|
||||
TENCENT_COS_REGION=your-region
|
||||
# The scheme of the Tencent COS service.
|
||||
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
|
||||
# ------------------------------
|
||||
|
||||
# The type of vector store to use.
|
||||
# Supported values are `weaviate`, `qdrant`, `milvus`, `myscale`, `relyt`, `pgvector`, `chroma`, `opensearch`, `tidb_vector`, `oracle`, `tencent`, `elasticsearch`.
|
||||
# The type of vector store to use.
|
||||
# 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
|
||||
|
||||
# The Weaviate endpoint URL. Only available when VECTOR_STORE is `weaviate`.
|
||||
WEAVIATE_ENDPOINT=http://weaviate:8080
|
||||
# The Weaviate API key.
|
||||
WEAVIATE_API_KEY=WVF5YThaHlkYwhGUSmCRgsX3tD5ngdN8pkih
|
||||
|
||||
# The Qdrant endpoint URL. Only available when VECTOR_STORE is `qdrant`.
|
||||
QDRANT_URL=http://qdrant:6333
|
||||
# The Qdrant API key.
|
||||
QDRANT_API_KEY=difyai123456
|
||||
# The Qdrant client timeout setting.
|
||||
QDRANT_CLIENT_TIMEOUT=20
|
||||
# The Qdrant client enable gRPC mode.
|
||||
QDRANT_GRPC_ENABLED=false
|
||||
# The Qdrant server gRPC mode PORT.
|
||||
QDRANT_GRPC_PORT=6334
|
||||
QDRANT_REPLICATION_FACTOR=1
|
||||
|
||||
# Milvus configuration Only available when VECTOR_STORE is `milvus`.
|
||||
# The milvus host.
|
||||
MILVUS_HOST=127.0.0.1
|
||||
# The milvus host.
|
||||
MILVUS_PORT=19530
|
||||
# The milvus username.
|
||||
MILVUS_USER=root
|
||||
# The milvus password.
|
||||
MILVUS_PASSWORD=Milvus
|
||||
# The milvus tls switch.
|
||||
MILVUS_SECURE=false
|
||||
# Milvus configuration. Only available when VECTOR_STORE is `milvus`.
|
||||
# The milvus uri.
|
||||
MILVUS_URI=http://host.docker.internal:19530
|
||||
MILVUS_DATABASE=
|
||||
MILVUS_TOKEN=
|
||||
MILVUS_USER=
|
||||
MILVUS_PASSWORD=
|
||||
MILVUS_ENABLE_HYBRID_SEARCH=False
|
||||
MILVUS_ANALYZER_PARAMS=
|
||||
|
||||
# MyScale configuration, only available when VECTOR_STORE is `myscale`
|
||||
# For multi-language support, please set MYSCALE_FTS_PARAMS with referring to:
|
||||
@@ -344,34 +435,99 @@ MYSCALE_PASSWORD=
|
||||
MYSCALE_DATABASE=dify
|
||||
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_PORT=5432
|
||||
PGVECTOR_USER=postgres
|
||||
PGVECTOR_PASSWORD=difyai123456
|
||||
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_PORT=4000
|
||||
TIDB_VECTOR_USER=xxx.root
|
||||
TIDB_VECTOR_PASSWORD=xxxxxx
|
||||
TIDB_VECTOR_USER=
|
||||
TIDB_VECTOR_PASSWORD=
|
||||
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_HOST=127.0.0.1
|
||||
CHROMA_PORT=8000
|
||||
CHROMA_TENANT=default_tenant
|
||||
CHROMA_DATABASE=default_database
|
||||
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_HOST=oracle
|
||||
ORACLE_PORT=1521
|
||||
ORACLE_USER=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_HOST=db
|
||||
@@ -383,9 +539,14 @@ RELYT_DATABASE=postgres
|
||||
# open search configuration, only available when VECTOR_STORE is `opensearch`
|
||||
OPENSEARCH_HOST=opensearch
|
||||
OPENSEARCH_PORT=9200
|
||||
OPENSEARCH_SECURE=true
|
||||
OPENSEARCH_VERIFY_CERTS=true
|
||||
OPENSEARCH_AUTH_METHOD=basic
|
||||
OPENSEARCH_USER=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_DB_URL=http://127.0.0.1
|
||||
@@ -395,12 +556,74 @@ TENCENT_VECTOR_DB_USERNAME=dify
|
||||
TENCENT_VECTOR_DB_DATABASE=dify
|
||||
TENCENT_VECTOR_DB_SHARD=1
|
||||
TENCENT_VECTOR_DB_REPLICAS=2
|
||||
TENCENT_VECTOR_DB_ENABLE_HYBRID_SEARCH=false
|
||||
|
||||
# ElasticSearch configuration, only available when VECTOR_STORE is `elasticsearch`
|
||||
ELASTICSEARCH_HOST=0.0.0.0
|
||||
ELASTICSEARCH_PORT=9200
|
||||
ELASTICSEARCH_USERNAME=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
|
||||
@@ -412,42 +635,68 @@ UPLOAD_FILE_SIZE_LIMIT=15
|
||||
# The maximum number of files that can be uploaded at a time, default 5.
|
||||
UPLOAD_FILE_BATCH_LIMIT=5
|
||||
|
||||
# ETl type, support: `dify`, `Unstructured`
|
||||
# ETL type, support: `dify`, `Unstructured`
|
||||
# `dify` Dify's proprietary file extraction scheme
|
||||
# `Unstructured` Unstructured.io file extraction scheme
|
||||
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
|
||||
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
|
||||
# ------------------------------
|
||||
|
||||
# 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 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.
|
||||
# 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.
|
||||
MULTIMODAL_SEND_IMAGE_FORMAT=base64
|
||||
|
||||
# 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_FORMAT=base64
|
||||
# Upload image file size limit, default 10M.
|
||||
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
|
||||
# Used for application monitoring and error log tracking.
|
||||
# ------------------------------
|
||||
SENTRY_DSN=
|
||||
|
||||
# API Service Sentry DSN address, default is empty, when empty,
|
||||
# all monitoring information is not reported to Sentry.
|
||||
# If not set, Sentry error reporting will be disabled.
|
||||
API_SENTRY_DSN=
|
||||
|
||||
# API Service The reporting ratio of Sentry events, if it is 0.01, it is 1%.
|
||||
API_SENTRY_TRACES_SAMPLE_RATE=1.0
|
||||
|
||||
# API Service The reporting ratio of Sentry profiles, if it is 0.01, it is 1%.
|
||||
API_SENTRY_PROFILES_SAMPLE_RATE=1.0
|
||||
|
||||
@@ -478,15 +727,18 @@ NOTION_INTERNAL_SECRET=
|
||||
# Mail related configuration
|
||||
# ------------------------------
|
||||
|
||||
# Mail type, support: resend, smtp
|
||||
# Mail type, support: resend, smtp, sendgrid
|
||||
MAIL_TYPE=resend
|
||||
|
||||
# Default send from email address, if not specified
|
||||
# If using SendGrid, use the 'from' field for authentication if necessary.
|
||||
MAIL_DEFAULT_SEND_FROM=
|
||||
|
||||
# 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
|
||||
|
||||
|
||||
# SMTP server configuration, used when MAIL_TYPE is `smtp`
|
||||
SMTP_SERVER=
|
||||
SMTP_PORT=465
|
||||
@@ -495,43 +747,91 @@ SMTP_PASSWORD=
|
||||
SMTP_USE_TLS=true
|
||||
SMTP_OPPORTUNISTIC_TLS=false
|
||||
|
||||
# Sendgid configuration
|
||||
SENDGRID_API_KEY=
|
||||
|
||||
# ------------------------------
|
||||
# Others Configuration
|
||||
# ------------------------------
|
||||
|
||||
# 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),
|
||||
# Default: 72.
|
||||
INVITE_EXPIRY_HOURS=72
|
||||
|
||||
# Reset password token valid time (hours),
|
||||
# Default: 24.
|
||||
RESET_PASSWORD_TOKEN_EXPIRY_HOURS=24
|
||||
# Reset password token valid time (minutes),
|
||||
RESET_PASSWORD_TOKEN_EXPIRY_MINUTES=5
|
||||
|
||||
# The sandbox service endpoint.
|
||||
CODE_EXECUTION_ENDPOINT=http://sandbox:8194
|
||||
CODE_EXECUTION_API_KEY=dify-sandbox
|
||||
CODE_MAX_NUMBER=9223372036854775807
|
||||
CODE_MIN_NUMBER=-9223372036854775808
|
||||
CODE_MAX_DEPTH=5
|
||||
CODE_MAX_PRECISION=20
|
||||
CODE_MAX_STRING_LENGTH=80000
|
||||
TEMPLATE_TRANSFORM_MAX_LENGTH=80000
|
||||
CODE_MAX_STRING_ARRAY_LENGTH=30
|
||||
CODE_MAX_OBJECT_ARRAY_LENGTH=30
|
||||
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_HTTP_URL=http://ssrf_proxy:3128
|
||||
# SSRF Proxy server HTTPS URL
|
||||
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
|
||||
# ------------------------------
|
||||
|
||||
PGUSER=${DB_USERNAME}
|
||||
# The name of the default postgres user.
|
||||
POSTGRES_USER=${DB_USERNAME}
|
||||
# The password for the default postgres user.
|
||||
POSTGRES_PASSWORD=${DB_PASSWORD}
|
||||
# The name of the default postgres database.
|
||||
@@ -562,7 +862,7 @@ SANDBOX_PORT=8194
|
||||
# Environment Variables for weaviate Service
|
||||
# (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_AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED=true
|
||||
WEAVIATE_DEFAULT_VECTORIZER_MODULE=none
|
||||
@@ -587,7 +887,7 @@ CHROMA_IS_PERSISTENT=TRUE
|
||||
|
||||
# ------------------------------
|
||||
# Environment Variables for Oracle Service
|
||||
# (only used when VECTOR_STORE is Oracle)
|
||||
# (only used when VECTOR_STORE is oracle)
|
||||
# ------------------------------
|
||||
ORACLE_PWD=Dify123456
|
||||
ORACLE_CHARACTERSET=AL32UTF8
|
||||
@@ -689,6 +989,10 @@ SSRF_HTTP_PORT=3128
|
||||
SSRF_COREDUMP_DIR=/var/spool/squid
|
||||
SSRF_REVERSE_PROXY_PORT=8194
|
||||
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
|
||||
@@ -721,4 +1025,113 @@ POSITION_TOOL_EXCLUDES=
|
||||
# Example: POSITION_PROVIDER_PINS=openai,openllm
|
||||
POSITION_PROVIDER_PINS=
|
||||
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
@@ -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.
|
||||
- **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`
|
||||
|
||||
@@ -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.
|
||||
- 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**:
|
||||
- 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
|
||||
|
||||
@@ -36,7 +38,8 @@ Welcome to the new `docker` directory for deploying Dify using Docker Compose. T
|
||||
- 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).
|
||||
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
|
||||
|
||||
@@ -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.
|
||||
- **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
|
||||
|
||||
@@ -83,12 +86,16 @@ The `.env.example` file provided in the Docker setup is extensive and covers a w
|
||||
|
||||
7. **Vector Database Configuration**:
|
||||
- `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**:
|
||||
- `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`.
|
||||
|
||||
### Additional Information
|
||||
|
||||
+13
-13
@@ -2,8 +2,8 @@
|
||||
|
||||
## Short description
|
||||
|
||||
Docker-compose certbot configurations with Backward compatibility (without certbot container).
|
||||
Use `docker-compose --profile certbot up` to use this features.
|
||||
docker compose certbot configurations with Backward compatibility (without certbot container).
|
||||
Use `docker compose --profile certbot up` to use this features.
|
||||
|
||||
## 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:
|
||||
```shell
|
||||
sudo docker network prune
|
||||
sudo docker-compose --profile certbot up --force-recreate -d
|
||||
docker network prune
|
||||
docker compose --profile certbot up --force-recreate -d
|
||||
```
|
||||
then after the containers launched:
|
||||
```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
|
||||
```properties
|
||||
NGINX_HTTPS_ENABLED=true
|
||||
```
|
||||
execute command:
|
||||
```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.
|
||||
[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:
|
||||
|
||||
```shell
|
||||
sudo docker-compose exec -it certbot /bin/sh /update-cert.sh
|
||||
sudo docker-compose exec nginx nginx -s reload
|
||||
docker compose exec -it certbot /bin/sh /update-cert.sh
|
||||
docker compose exec nginx nginx -s reload
|
||||
```
|
||||
|
||||
## 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.
|
||||
|
||||
```shell
|
||||
sudo docker-compose --profile certbot up -d --no-deps --force-recreate certbot
|
||||
sudo docker-compose exec -it certbot /bin/sh /update-cert.sh
|
||||
docker compose --profile certbot up -d --no-deps --force-recreate certbot
|
||||
docker compose exec -it certbot /bin/sh /update-cert.sh
|
||||
```
|
||||
|
||||
Then, reload the nginx container if necessary.
|
||||
|
||||
```shell
|
||||
sudo docker-compose exec nginx nginx -s reload
|
||||
docker compose exec nginx nginx -s reload
|
||||
```
|
||||
|
||||
## 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.
|
||||
|
||||
```shell
|
||||
sudo docker-compose up -d
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
@@ -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
|
||||
Executable
+44
@@ -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
|
||||
@@ -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:
|
||||
@@ -16,26 +16,39 @@ services:
|
||||
-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
|
||||
- ${PGDATA_HOST_VOLUME:-./volumes/db/data}:/var/lib/postgresql/data
|
||||
ports:
|
||||
- "${EXPOSE_POSTGRES_PORT:-5432}:5432"
|
||||
healthcheck:
|
||||
test: [ "CMD", "pg_isready" ]
|
||||
interval: 1s
|
||||
timeout: 3s
|
||||
retries: 30
|
||||
|
||||
# The redis cache.
|
||||
redis:
|
||||
image: redis:6-alpine
|
||||
restart: always
|
||||
env_file:
|
||||
- ./middleware.env
|
||||
environment:
|
||||
REDISCLI_AUTH: ${REDIS_PASSWORD:-difyai123456}
|
||||
volumes:
|
||||
# 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.
|
||||
command: redis-server --requirepass difyai123456
|
||||
command: redis-server --requirepass ${REDIS_PASSWORD:-difyai123456}
|
||||
ports:
|
||||
- "${EXPOSE_REDIS_PORT:-6379}:6379"
|
||||
healthcheck:
|
||||
test: [ "CMD", "redis-cli", "ping" ]
|
||||
|
||||
# The DifySandbox
|
||||
sandbox:
|
||||
image: langgenius/dify-sandbox:0.2.6
|
||||
image: langgenius/dify-sandbox:0.2.12
|
||||
restart: always
|
||||
env_file:
|
||||
- ./middleware.env
|
||||
environment:
|
||||
# The DifySandbox configurations
|
||||
# Make sure you are changing this key for your deployment with a strong key.
|
||||
@@ -47,14 +60,81 @@ services:
|
||||
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
|
||||
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
|
||||
# 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:
|
||||
image: ubuntu/squid:latest
|
||||
restart: always
|
||||
@@ -62,6 +142,8 @@ services:
|
||||
- ./ssrf_proxy/squid.conf.template:/etc/squid/squid.conf.template
|
||||
- ./ssrf_proxy/docker-entrypoint.sh:/docker-entrypoint-mount.sh
|
||||
entrypoint: [ "sh", "-c", "cp /docker-entrypoint-mount.sh /docker-entrypoint.sh && sed -i 's/\r$$//' /docker-entrypoint.sh && chmod +x /docker-entrypoint.sh && /docker-entrypoint.sh" ]
|
||||
env_file:
|
||||
- ./middleware.env
|
||||
environment:
|
||||
# pls clearly modify the squid env vars to fit your network environment.
|
||||
HTTP_PORT: ${SSRF_HTTP_PORT:-3128}
|
||||
@@ -80,11 +162,12 @@ services:
|
||||
weaviate:
|
||||
image: semitechnologies/weaviate:1.19.0
|
||||
profiles:
|
||||
- ""
|
||||
- weaviate
|
||||
restart: always
|
||||
volumes:
|
||||
# Mount the Weaviate data directory to the container.
|
||||
- ./volumes/weaviate:/var/lib/weaviate
|
||||
- ${WEAVIATE_HOST_VOLUME:-./volumes/weaviate}:/var/lib/weaviate
|
||||
env_file:
|
||||
- ./middleware.env
|
||||
environment:
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 170 KiB |
+708
-143
File diff suppressed because it is too large
Load Diff
Executable
+25
@@ -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
|
||||
Executable
+112
@@ -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()
|
||||
@@ -1,13 +1,14 @@
|
||||
# ------------------------------
|
||||
# Environment Variables for db Service
|
||||
# ------------------------------
|
||||
PGUSER=postgres
|
||||
POSTGRES_USER=postgres
|
||||
# The password for the default postgres user.
|
||||
POSTGRES_PASSWORD=difyai123456
|
||||
# The name of the default postgres database.
|
||||
POSTGRES_DB=dify
|
||||
# postgres data directory
|
||||
PGDATA=/var/lib/postgresql/data/pgdata
|
||||
PGDATA_HOST_VOLUME=./volumes/db/data
|
||||
|
||||
# Maximum number of connections to the database
|
||||
# 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
|
||||
POSTGRES_EFFECTIVE_CACHE_SIZE=4096MB
|
||||
|
||||
# -----------------------------
|
||||
# Environment Variables for redis Service
|
||||
# -----------------------------
|
||||
REDIS_HOST_VOLUME=./volumes/redis/data
|
||||
REDIS_PASSWORD=difyai123456
|
||||
|
||||
# ------------------------------
|
||||
# Environment Variables for sandbox Service
|
||||
# ------------------------------
|
||||
SANDBOX_API_KEY=dify-sandbox
|
||||
SANDBOX_GIN_MODE=release
|
||||
SANDBOX_WORKER_TIMEOUT=15
|
||||
@@ -48,7 +56,6 @@ SANDBOX_ENABLE_NETWORK=true
|
||||
SANDBOX_HTTP_PROXY=http://ssrf_proxy:3128
|
||||
SANDBOX_HTTPS_PROXY=http://ssrf_proxy:3128
|
||||
SANDBOX_PORT=8194
|
||||
# ------------------------------
|
||||
|
||||
# ------------------------------
|
||||
# Environment Variables for ssrf_proxy Service
|
||||
@@ -70,6 +77,7 @@ WEAVIATE_AUTHENTICATION_APIKEY_ALLOWED_KEYS=WVF5YThaHlkYwhGUSmCRgsX3tD5ngdN8pkih
|
||||
WEAVIATE_AUTHENTICATION_APIKEY_USERS=hello@dify.ai
|
||||
WEAVIATE_AUTHORIZATION_ADMINLIST_ENABLED=true
|
||||
WEAVIATE_AUTHORIZATION_ADMINLIST_USERS=hello@dify.ai
|
||||
WEAVIATE_HOST_VOLUME=./volumes/weaviate
|
||||
|
||||
# ------------------------------
|
||||
# Docker Compose Service Expose Host Port Configurations
|
||||
@@ -79,3 +87,74 @@ EXPOSE_REDIS_PORT=6379
|
||||
EXPOSE_SANDBOX_PORT=8194
|
||||
EXPOSE_SSRF_PROXY_PORT=3128
|
||||
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;
|
||||
}
|
||||
|
||||
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 / {
|
||||
proxy_pass http://web:3000;
|
||||
include proxy.conf;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
HTTPS_CONFIG=''
|
||||
|
||||
if [ "${NGINX_HTTPS_ENABLED}" = "true" ]; then
|
||||
# Check if the certificate and key files for the specified domain exist
|
||||
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
|
||||
envsubst '${HTTPS_CONFIG}' < /etc/nginx/conf.d/default.conf.template > /etc/nginx/conf.d/default.conf
|
||||
fi
|
||||
export HTTPS_CONFIG
|
||||
|
||||
if [ "${NGINX_ENABLE_CERTBOT_CHALLENGE}" = "true" ]; then
|
||||
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/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
|
||||
exec nginx -g 'daemon off;'
|
||||
exec nginx -g 'daemon off;'
|
||||
|
||||
@@ -6,4 +6,4 @@ ssl_certificate_key ${SSL_CERTIFICATE_KEY_PATH};
|
||||
ssl_protocols ${NGINX_SSL_PROTOCOLS};
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_session_cache shared:SSL:10m;
|
||||
ssl_session_timeout 10m;
|
||||
ssl_session_timeout 10m;
|
||||
|
||||
@@ -31,4 +31,4 @@ http {
|
||||
client_max_body_size ${NGINX_CLIENT_MAX_BODY_SIZE};
|
||||
|
||||
include /etc/nginx/conf.d/*.conf;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Port $server_port;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Connection "";
|
||||
proxy_buffering off;
|
||||
|
||||
Executable
+24
@@ -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,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 fe80::/10 # RFC 4291 link-local (directly plugged) machines
|
||||
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 21 # ftp
|
||||
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 777 # multiling http
|
||||
acl CONNECT method CONNECT
|
||||
acl allowed_domains dstdomain .marketplace.dify.ai
|
||||
http_access allow allowed_domains
|
||||
http_access deny !Safe_ports
|
||||
http_access deny CONNECT !SSL_ports
|
||||
http_access allow localhost manager
|
||||
@@ -41,10 +44,13 @@ refresh_pattern . 0 20% 4320
|
||||
|
||||
# cache_dir ufs /var/spool/squid 100 16 256
|
||||
# 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 ################################
|
||||
http_port ${REVERSE_PROXY_PORT} accel vhost
|
||||
cache_peer ${SANDBOX_HOST} parent ${SANDBOX_PORT} 0 no-query originserver
|
||||
acl src_all 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
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
DB_INITIALISED="/opt/oracle/oradata/dbinit"
|
||||
#[ -f ${DB_INITIALISED} ] && exit
|
||||
#touch ${DB_INITIALISED}
|
||||
if [ -f ${DB_INITIALISED} ]; then
|
||||
DB_INITIALIZED="/opt/oracle/oradata/dbinit"
|
||||
#[ -f ${DB_INITIALIZED} ] && exit
|
||||
#touch ${DB_INITIALIZED}
|
||||
if [ -f ${DB_INITIALIZED} ]; then
|
||||
echo 'File exists. Standards for have been Init'
|
||||
exit
|
||||
else
|
||||
echo 'File does not exist. Standards for first time Strart up this DB'
|
||||
"$ORACLE_HOME"/bin/sqlplus -s "/ as sysdba" @"/opt/oracle/scripts/startup/init_user.script";
|
||||
touch ${DB_INITIALISED}
|
||||
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";
|
||||
touch ${DB_INITIALIZED}
|
||||
fi
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
show pdbs;
|
||||
ALTER SYSTEM SET PROCESSES=500 SCOPE=SPFILE;
|
||||
ALTER SYSTEM SET PROCESSES=500 SCOPE=SPFILE;
|
||||
alter session set container= freepdb1;
|
||||
create user dify identified by dify DEFAULT TABLESPACE users quota unlimited on users;
|
||||
grant DB_DEVELOPER_ROLE to dify;
|
||||
|
||||
BEGIN
|
||||
CTX_DDL.CREATE_PREFERENCE('my_chinese_vgram_lexer','CHINESE_VGRAM_LEXER');
|
||||
CTX_DDL.CREATE_PREFERENCE('dify.world_lexer','WORLD_LEXER');
|
||||
END;
|
||||
/
|
||||
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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>
|
||||
</default>
|
||||
</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: ''
|
||||
@@ -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");
|
||||
Generated
+705
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -5,13 +5,15 @@ WEB_REPLICAS=1
|
||||
SPACE_REPLICAS=1
|
||||
ADMIN_REPLICAS=1
|
||||
API_REPLICAS=1
|
||||
WORKER_REPLICAS=1
|
||||
BEAT_WORKER_REPLICAS=1
|
||||
LIVE_REPLICAS=1
|
||||
|
||||
NGINX_PORT=80
|
||||
WEB_URL=http://${APP_DOMAIN}
|
||||
DEBUG=0
|
||||
SENTRY_DSN=
|
||||
SENTRY_ENVIRONMENT=production
|
||||
CORS_ALLOWED_ORIGINS=http://${APP_DOMAIN}
|
||||
API_BASE_URL=http://api:8000
|
||||
|
||||
#DB SETTINGS
|
||||
PGHOST=plane-db
|
||||
@@ -28,6 +30,14 @@ REDIS_HOST=plane-redis
|
||||
REDIS_PORT=6379
|
||||
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=60gp0byfz2dvffa45cxl20p1scy9xbpf6d8c5y0geejgkyp1b5
|
||||
|
||||
@@ -38,9 +48,6 @@ AWS_ACCESS_KEY_ID=access-key
|
||||
AWS_SECRET_ACCESS_KEY=secret-key
|
||||
AWS_S3_ENDPOINT_URL=http://plane-minio:9000
|
||||
AWS_S3_BUCKET_NAME=uploads
|
||||
MINIO_ROOT_USER=access-key
|
||||
MINIO_ROOT_PASSWORD=secret-key
|
||||
BUCKET_NAME=uploads
|
||||
FILE_SIZE_LIMIT=5242880
|
||||
|
||||
# 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`
|
||||
# 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
@@ -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
|
||||
- Use the terminal (or gitbash) window to run all the future steps
|
||||
|
||||
### Downloading Latest Stable Release
|
||||
### Downloading Latest Release
|
||||
|
||||
```
|
||||
mkdir 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
|
||||
```
|
||||
@@ -77,8 +89,9 @@ Lets get started by running the `./setup.sh` command.
|
||||
|
||||
This will prompt you with the below options.
|
||||
|
||||
#### Docker Compose
|
||||
```bash
|
||||
Select a Action you want to perform:
|
||||
Select an Action you want to perform:
|
||||
1) Install (x86_64)
|
||||
2) Start
|
||||
3) Stop
|
||||
@@ -87,17 +100,42 @@ Select a Action you want to perform:
|
||||
6) View Logs
|
||||
7) Backup Data
|
||||
8) Exit
|
||||
|
||||
Action [2]: 1
|
||||
```
|
||||
|
||||
For the 1st time setup, type "1" as action input.
|
||||
|
||||
This will create a create a folder `plane-app` or `plane-app-preview` (in case of preview deployment) and will download 2 files inside that
|
||||
This will create a folder `plane-app` and will download 2 files inside that
|
||||
|
||||
- `docker-compose.yaml`
|
||||
- `plane.env`
|
||||
|
||||
Again the `options [1-8]` will be popped up and this time hit `8` to exit.
|
||||
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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -171,14 +211,34 @@ If all goes well, you must see something like this
|
||||
|
||||

|
||||
|
||||
#### 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
|
||||
|
||||
#### Docker Compose
|
||||
```bash
|
||||
Select a Action you want to perform:
|
||||
1) Install (x86_64)
|
||||
@@ -197,14 +257,32 @@ If all goes well, you must see something like this
|
||||
|
||||

|
||||
|
||||
#### 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.
|
||||
|
||||
Lets again run the `./setup.sh` command. You will again be prompted with the below options. This time select `5` to upgrade the release.
|
||||
|
||||
#### Docker Compose
|
||||
|
||||
```bash
|
||||
Select a Action you want to perform:
|
||||
1) Install (x86_64)
|
||||
@@ -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`
|
||||
|
||||
#### Docker Swarm
|
||||
|
||||
Lets again run the `./setup.sh` command. You will again be prompted with the below options. This time select `5` to upgrade the release.
|
||||
|
||||
```bash
|
||||
1) Deploy Stack
|
||||
2) Remove Stack
|
||||
3) View Stack Status
|
||||
4) Redeploy Stack
|
||||
5) Upgrade
|
||||
6) View Logs
|
||||
7) Exit
|
||||
|
||||
Action [3]: 5
|
||||
```
|
||||
|
||||
By choosing this, it will stop the services and then will download the latest `docker-compose.yaml` and `plane.env`.
|
||||
|
||||
Once done, choose `7` to exit from prompt.
|
||||
|
||||
> It is very important for you to validate the `plane.env` for the new changes.
|
||||
|
||||
Once done with making changes in `plane.env` file, jump on to `Redeploy Stack`
|
||||
|
||||
---
|
||||
|
||||
### View Logs
|
||||
|
||||
There would a time when you might want to check what is happening inside the API, Worker or any other container.
|
||||
|
||||
Lets again run the `./setup.sh` command. You will again be prompted with the below options. This time select `6` to view logs.
|
||||
Lets again run the `./setup.sh` command. You will again be prompted with the below options.
|
||||
|
||||
This time select `6` to view logs.
|
||||
|
||||
#### Docker Compose
|
||||
|
||||
```bash
|
||||
Select a Action you want to perform:
|
||||
@@ -253,7 +359,22 @@ Select a Action you want to perform:
|
||||
Action [2]: 6
|
||||
```
|
||||
|
||||
#### Docker Swarm
|
||||
|
||||
|
||||
```bash
|
||||
1) Deploy Stack
|
||||
2) Remove Stack
|
||||
3) View Stack Status
|
||||
4) Redeploy Stack
|
||||
5) Upgrade
|
||||
6) View Logs
|
||||
7) Exit
|
||||
|
||||
Action [3]: 6
|
||||
```
|
||||
|
||||
#### Service Menu Options for Logs
|
||||
This will further open sub-menu with list of services
|
||||
```bash
|
||||
Select a Service you want to view the logs for:
|
||||
@@ -267,9 +388,10 @@ Select a Service you want to view the logs for:
|
||||
8) Redis
|
||||
9) Postgres
|
||||
10) Minio
|
||||
11) RabbitMQ
|
||||
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
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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`.
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
@@ -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>
|
||||
<summary><h2>Upgrading from v0.13.2 to v0.14.x</h2></summary>
|
||||
|
||||
|
||||
+141
-88
@@ -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
|
||||
environment:
|
||||
- NGINX_PORT=${NGINX_PORT:-80}
|
||||
- WEB_URL=${WEB_URL:-http://localhost}
|
||||
- DEBUG=${DEBUG:-0}
|
||||
- SENTRY_DSN=${SENTRY_DSN}
|
||||
- SENTRY_ENVIRONMENT=${SENTRY_ENVIRONMENT:-"production"}
|
||||
- CORS_ALLOWED_ORIGINS=${CORS_ALLOWED_ORIGINS}
|
||||
# Gunicorn Workers
|
||||
- GUNICORN_WORKERS=${GUNICORN_WORKERS:-1}
|
||||
#DB SETTINGS
|
||||
- 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}
|
||||
WEB_URL: ${WEB_URL:-http://localhost}
|
||||
DEBUG: ${DEBUG:-0}
|
||||
CORS_ALLOWED_ORIGINS: ${CORS_ALLOWED_ORIGINS}
|
||||
GUNICORN_WORKERS: 1
|
||||
USE_MINIO: ${USE_MINIO:-1}
|
||||
DATABASE_URL: ${DATABASE_URL:-postgresql://plane:plane@plane-db/plane}
|
||||
SECRET_KEY: ${SECRET_KEY:-60gp0byfz2dvffa45cxl20p1scy9xbpf6d8c5y0geejgkyp1b5}
|
||||
AMQP_URL: ${AMQP_URL:-amqp://plane:plane@plane-mq:5672/plane}
|
||||
API_KEY_RATE_LIMIT: ${API_KEY_RATE_LIMIT:-60/minute}
|
||||
MINIO_ENDPOINT_SSL: ${MINIO_ENDPOINT_SSL:-0}
|
||||
|
||||
services:
|
||||
web:
|
||||
<<: *app-env
|
||||
image: ${DOCKERHUB_USER:-makeplane}/plane-frontend:${APP_RELEASE:-stable}
|
||||
platform: ${DOCKER_PLATFORM:-}
|
||||
pull_policy: if_not_present
|
||||
restart: unless-stopped
|
||||
image: artifacts.plane.so/makeplane/plane-frontend:${APP_RELEASE:-stable}
|
||||
command: node web/server.js web
|
||||
deploy:
|
||||
replicas: ${WEB_REPLICAS:-1}
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
depends_on:
|
||||
- api
|
||||
- worker
|
||||
|
||||
space:
|
||||
<<: *app-env
|
||||
image: ${DOCKERHUB_USER:-makeplane}/plane-space:${APP_RELEASE:-stable}
|
||||
platform: ${DOCKER_PLATFORM:-}
|
||||
pull_policy: if_not_present
|
||||
restart: unless-stopped
|
||||
image: artifacts.plane.so/makeplane/plane-space:${APP_RELEASE:-stable}
|
||||
command: node space/server.js space
|
||||
deploy:
|
||||
replicas: ${SPACE_REPLICAS:-1}
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
depends_on:
|
||||
- api
|
||||
- worker
|
||||
- web
|
||||
|
||||
admin:
|
||||
<<: *app-env
|
||||
image: ${DOCKERHUB_USER:-makeplane}/plane-admin:${APP_RELEASE:-stable}
|
||||
platform: ${DOCKER_PLATFORM:-}
|
||||
pull_policy: if_not_present
|
||||
restart: unless-stopped
|
||||
image: artifacts.plane.so/makeplane/plane-admin:${APP_RELEASE:-stable}
|
||||
command: node admin/server.js admin
|
||||
deploy:
|
||||
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:
|
||||
- api
|
||||
- web
|
||||
|
||||
api:
|
||||
<<: *app-env
|
||||
image: ${DOCKERHUB_USER:-makeplane}/plane-backend:${APP_RELEASE:-stable}
|
||||
platform: ${DOCKER_PLATFORM:-}
|
||||
pull_policy: if_not_present
|
||||
restart: unless-stopped
|
||||
image: artifacts.plane.so/makeplane/plane-backend:${APP_RELEASE:-stable}
|
||||
command: ./bin/docker-entrypoint-api.sh
|
||||
deploy:
|
||||
replicas: ${API_REPLICAS:-1}
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
volumes:
|
||||
- logs_api:/code/plane/logs
|
||||
environment:
|
||||
<<: [ *app-env, *db-env, *redis-env, *minio-env, *aws-s3-env, *proxy-env ]
|
||||
depends_on:
|
||||
- plane-db
|
||||
- plane-redis
|
||||
- plane-mq
|
||||
|
||||
worker:
|
||||
<<: *app-env
|
||||
image: ${DOCKERHUB_USER:-makeplane}/plane-backend:${APP_RELEASE:-stable}
|
||||
platform: ${DOCKER_PLATFORM:-}
|
||||
pull_policy: if_not_present
|
||||
restart: unless-stopped
|
||||
image: artifacts.plane.so/makeplane/plane-backend:${APP_RELEASE:-stable}
|
||||
command: ./bin/docker-entrypoint-worker.sh
|
||||
deploy:
|
||||
replicas: ${WORKER_REPLICAS:-1}
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
volumes:
|
||||
- logs_worker:/code/plane/logs
|
||||
environment:
|
||||
<<: [ *app-env, *db-env, *redis-env, *minio-env, *aws-s3-env, *proxy-env ]
|
||||
depends_on:
|
||||
- api
|
||||
- plane-db
|
||||
- plane-redis
|
||||
- plane-mq
|
||||
|
||||
beat-worker:
|
||||
<<: *app-env
|
||||
image: ${DOCKERHUB_USER:-makeplane}/plane-backend:${APP_RELEASE:-stable}
|
||||
platform: ${DOCKER_PLATFORM:-}
|
||||
pull_policy: if_not_present
|
||||
restart: unless-stopped
|
||||
image: artifacts.plane.so/makeplane/plane-backend:${APP_RELEASE:-stable}
|
||||
command: ./bin/docker-entrypoint-beat.sh
|
||||
deploy:
|
||||
replicas: ${BEAT_WORKER_REPLICAS:-1}
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
volumes:
|
||||
- logs_beat-worker:/code/plane/logs
|
||||
environment:
|
||||
<<: [ *app-env, *db-env, *redis-env, *minio-env, *aws-s3-env, *proxy-env ]
|
||||
depends_on:
|
||||
- api
|
||||
- plane-db
|
||||
- plane-redis
|
||||
- plane-mq
|
||||
|
||||
migrator:
|
||||
<<: *app-env
|
||||
image: ${DOCKERHUB_USER:-makeplane}/plane-backend:${APP_RELEASE:-stable}
|
||||
platform: ${DOCKER_PLATFORM:-}
|
||||
pull_policy: if_not_present
|
||||
restart: "no"
|
||||
image: artifacts.plane.so/makeplane/plane-backend:${APP_RELEASE:-stable}
|
||||
command: ./bin/docker-entrypoint-migrator.sh
|
||||
deploy:
|
||||
replicas: 1
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
volumes:
|
||||
- logs_migrator:/code/plane/logs
|
||||
environment:
|
||||
<<: [ *app-env, *db-env, *redis-env, *minio-env, *aws-s3-env, *proxy-env ]
|
||||
depends_on:
|
||||
- plane-db
|
||||
- plane-redis
|
||||
|
||||
# Comment this if you already have a database running
|
||||
plane-db:
|
||||
<<: *app-env
|
||||
image: postgres:15.7-alpine
|
||||
pull_policy: if_not_present
|
||||
restart: unless-stopped
|
||||
command: postgres -c 'max_connections=1000'
|
||||
deploy:
|
||||
replicas: 1
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
environment:
|
||||
<<: *db-env
|
||||
volumes:
|
||||
- pgdata:/var/lib/postgresql/data
|
||||
|
||||
plane-redis:
|
||||
<<: *app-env
|
||||
image: valkey/valkey:7.2.5-alpine
|
||||
pull_policy: if_not_present
|
||||
restart: unless-stopped
|
||||
deploy:
|
||||
replicas: 1
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
volumes:
|
||||
- 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:
|
||||
<<: *app-env
|
||||
image: minio/minio:latest
|
||||
pull_policy: if_not_present
|
||||
restart: unless-stopped
|
||||
command: server /export --console-address ":9090"
|
||||
deploy:
|
||||
replicas: 1
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
environment:
|
||||
<<: *minio-env
|
||||
volumes:
|
||||
- uploads:/export
|
||||
|
||||
# Comment this if you already have a reverse proxy running
|
||||
proxy:
|
||||
<<: *app-env
|
||||
image: ${DOCKERHUB_USER:-makeplane}/plane-proxy:${APP_RELEASE:-stable}
|
||||
platform: ${DOCKER_PLATFORM:-}
|
||||
pull_policy: if_not_present
|
||||
restart: unless-stopped
|
||||
image: artifacts.plane.so/makeplane/plane-proxy:${APP_RELEASE:-stable}
|
||||
environment:
|
||||
<<: *proxy-env
|
||||
deploy:
|
||||
replicas: 1
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
depends_on:
|
||||
- web
|
||||
- api
|
||||
@@ -182,3 +234,4 @@ volumes:
|
||||
logs_worker:
|
||||
logs_beat-worker:
|
||||
logs_migrator:
|
||||
rabbitmq_data:
|
||||
|
||||
+153
-40
@@ -4,9 +4,12 @@ BRANCH=${BRANCH:-master}
|
||||
SCRIPT_DIR=$PWD
|
||||
SERVICE_FOLDER=plane-app
|
||||
PLANE_INSTALL_DIR=$PWD/$SERVICE_FOLDER
|
||||
export APP_RELEASE="stable"
|
||||
export DOCKERHUB_USER=makeplane
|
||||
export APP_RELEASE=stable
|
||||
export DOCKERHUB_USER=artifacts.plane.so/makeplane
|
||||
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)
|
||||
OS_NAME=$(uname)
|
||||
@@ -16,13 +19,6 @@ mkdir -p $PLANE_INSTALL_DIR/archive
|
||||
DOCKER_FILE_PATH=$PLANE_INSTALL_DIR/docker-compose.yaml
|
||||
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() {
|
||||
clear
|
||||
|
||||
@@ -59,6 +55,17 @@ function spinner() {
|
||||
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(){
|
||||
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"
|
||||
return
|
||||
else
|
||||
# if key exists, update the value
|
||||
sed "${SED_PREFIX[@]}" "s/^$key=.*/$key=$value/g" "$file"
|
||||
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"
|
||||
@@ -182,7 +193,7 @@ function buildYourOwnImage(){
|
||||
local PLANE_TEMP_CODE_DIR=~/tmp/plane
|
||||
rm -rf $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
|
||||
|
||||
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 ""
|
||||
|
||||
if [ "$APP_RELEASE" == "stable" ]; then
|
||||
export APP_RELEASE=$(checkLatestRelease)
|
||||
fi
|
||||
|
||||
local build_image=$(initialize)
|
||||
|
||||
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
|
||||
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)
|
||||
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)
|
||||
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.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" ];
|
||||
then
|
||||
@@ -310,7 +366,7 @@ function startServices() {
|
||||
|
||||
local api_container_id=$(docker container ls -q -f "name=$SERVICE_FOLDER-api")
|
||||
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
|
||||
local message=">> Waiting for API Service to Start"
|
||||
local dots=$(printf '%*s' $idx2 | tr ' ' '.')
|
||||
@@ -335,6 +391,34 @@ function restartServices() {
|
||||
startServices
|
||||
}
|
||||
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 ****"
|
||||
stopServices
|
||||
|
||||
@@ -373,12 +457,13 @@ function viewLogs(){
|
||||
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 <= 10 )); do
|
||||
echo "Invalid selection. Please enter a number between 1 and 11."
|
||||
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
|
||||
|
||||
@@ -397,6 +482,7 @@ function viewLogs(){
|
||||
8) viewSpecificLogs "plane-redis";;
|
||||
9) viewSpecificLogs "plane-db";;
|
||||
10) viewSpecificLogs "plane-minio";;
|
||||
11) viewSpecificLogs "plane-mq";;
|
||||
0) askForAction;;
|
||||
*) echo "INVALID SERVICE NAME SUPPLIED";;
|
||||
esac
|
||||
@@ -415,49 +501,76 @@ function viewLogs(){
|
||||
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 backupSingleVolume() {
|
||||
backupFolder=$1
|
||||
selectedVolume=$2
|
||||
# Backup data from Docker volume to the backup folder
|
||||
# docker run --rm -v "$selectedVolume":/source -v "$backupFolder":/backup busybox sh -c 'cp -r /source/* /backup/'
|
||||
local tobereplaced="plane-app_"
|
||||
local replacewith=""
|
||||
function backup_container_dir() {
|
||||
local BACKUP_FOLDER=$1
|
||||
local CONTAINER_NAME=$2
|
||||
local CONTAINER_DATA_DIR=$3
|
||||
local SERVICE_FOLDER=$4
|
||||
|
||||
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 \
|
||||
-e TAR_NAME="$svcName" \
|
||||
-v "$selectedVolume":/"$svcName" \
|
||||
-v "$backupFolder":/backup \
|
||||
busybox sh -c 'tar -czf "/backup/${TAR_NAME}.tar.gz" /${TAR_NAME}'
|
||||
# Create a temporary directory for the backup
|
||||
mkdir -p "$BACKUP_FOLDER/$SERVICE_FOLDER"
|
||||
|
||||
# Copy the data directory from the running container
|
||||
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() {
|
||||
local datetime=$(date +"%Y%m%d-%H%M")
|
||||
local BACKUP_FOLDER=$PLANE_INSTALL_DIR/backup/$datetime
|
||||
mkdir -p "$BACKUP_FOLDER"
|
||||
|
||||
volumes=$(docker volume ls -f "name=plane-app" --format "{{.Name}}" | grep -E "_pgdata|_redisdata|_uploads")
|
||||
# Check if there are any matching volumes
|
||||
if [ -z "$volumes" ]; then
|
||||
echo "No volumes found starting with 'plane-app'"
|
||||
# Check if docker-compose.yml exists
|
||||
if [ ! -f "$DOCKER_FILE_PATH" ]; then
|
||||
echo "Error: docker-compose.yml not found at $DOCKER_FILE_PATH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
for vol in $volumes; do
|
||||
echo "Backing Up $vol"
|
||||
backupSingleVolume "$BACKUP_FOLDER" "$vol"
|
||||
done
|
||||
backup_container_dir "$BACKUP_FOLDER" "plane-db" "/var/lib/postgresql/data" "pgdata" || exit 1
|
||||
backup_container_dir "$BACKUP_FOLDER" "plane-minio" "/export" "uploads" || exit 1
|
||||
backup_container_dir "$BACKUP_FOLDER" "plane-mq" "/var/lib/rabbitmq" "rabbitmq_data" || exit 1
|
||||
backup_container_dir "$BACKUP_FOLDER" "plane-redis" "/data" "redisdata" || exit 1
|
||||
|
||||
echo ""
|
||||
echo "Backup completed successfully. Backup files are stored in $BACKUP_FOLDER"
|
||||
echo ""
|
||||
|
||||
}
|
||||
function askForAction() {
|
||||
local DEFAULT_ACTION=$1
|
||||
@@ -544,7 +657,7 @@ if [ -f "$DOCKER_ENV_PATH" ]; then
|
||||
CUSTOM_BUILD=$(getEnvValue "CUSTOM_BUILD" "$DOCKER_ENV_PATH")
|
||||
|
||||
if [ -z "$DOCKERHUB_USER" ]; then
|
||||
DOCKERHUB_USER=makeplane
|
||||
DOCKERHUB_USER=artifacts.plane.so/makeplane
|
||||
updateEnvFile "DOCKERHUB_USER" "$DOCKERHUB_USER" "$DOCKER_ENV_PATH"
|
||||
fi
|
||||
|
||||
|
||||
Executable
+144
@@ -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 "$@"
|
||||
@@ -66,8 +66,10 @@ function restoreData() {
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local volume_suffix
|
||||
volume_suffix="_pgdata|_redisdata|_uploads|_rabbitmq_data"
|
||||
local volumes
|
||||
volumes=$(docker volume ls -f "name=plane-app" --format "{{.Name}}" | grep -E "_pgdata|_redisdata|_uploads")
|
||||
volumes=$(docker volume ls -f "name=plane-app" --format "{{.Name}}" | grep -E "$volume_suffix")
|
||||
# Check if there are any matching volumes
|
||||
if [ -z "$volumes" ]; then
|
||||
echo ".....No volumes found starting with 'plane-app'"
|
||||
@@ -87,7 +89,7 @@ function restoreData() {
|
||||
echo "Found $BACKUP_FILE"
|
||||
|
||||
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
|
||||
echo "Skipping: No volume found with name $restoreVolName"
|
||||
|
||||
Executable
+612
@@ -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 "$@"
|
||||
@@ -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");
|
||||
@@ -9,6 +9,9 @@ ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJhbm9uIiwKIC
|
||||
SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJzZXJ2aWNlX3JvbGUiLAogICAgImlzcyI6ICJzdXBhYmFzZS1kZW1vIiwKICAgICJpYXQiOiAxNjQxNzY5MjAwLAogICAgImV4cCI6IDE3OTk1MzU2MDAKfQ.DaYlNEoUrrEn2Ig7tqibS-PHK5vgusbcbo7X36XVt4Q
|
||||
DASHBOARD_USERNAME=supabase
|
||||
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.
|
||||
@@ -19,6 +22,23 @@ POSTGRES_DB=postgres
|
||||
POSTGRES_PORT=5432
|
||||
# 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.
|
||||
############
|
||||
@@ -81,21 +101,26 @@ SUPABASE_PUBLIC_URL=http://localhost:8000
|
||||
# Enable webp support
|
||||
IMGPROXY_ENABLE_WEBP_DETECTION=true
|
||||
|
||||
# Add your OpenAI API key to enable SQL Editor Assistant
|
||||
OPENAI_API_KEY=
|
||||
|
||||
|
||||
############
|
||||
# Functions - Configuration for Functions
|
||||
############
|
||||
# NOTE: VERIFY_JWT applies to all functions. Per-function VERIFY_JWT is not supported yet.
|
||||
FUNCTIONS_VERIFY_JWT=false
|
||||
|
||||
|
||||
############
|
||||
# Logs - Configuration for Logflare
|
||||
# Logs - Configuration for Analytics
|
||||
# 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
|
||||
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=/var/run/docker.sock
|
||||
|
||||
@@ -4,7 +4,7 @@ services:
|
||||
studio:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: studio/Dockerfile
|
||||
dockerfile: apps/studio/Dockerfile
|
||||
target: dev
|
||||
ports:
|
||||
- 8082:8082
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
|
||||
minio:
|
||||
@@ -33,7 +31,7 @@ services:
|
||||
|
||||
storage:
|
||||
container_name: supabase-storage
|
||||
image: supabase/storage-api:v0.43.11
|
||||
image: supabase/storage-api:v1.11.13
|
||||
depends_on:
|
||||
db:
|
||||
# Disable this if you are using an external Postgres database
|
||||
|
||||
+186
-109
@@ -1,15 +1,16 @@
|
||||
# Usage
|
||||
# Start: docker compose up
|
||||
# With helpers: docker compose -f docker-compose.yml -f ./dev/docker-compose.dev.yml up
|
||||
# Stop: docker compose down
|
||||
# Destroy: docker compose -f docker-compose.yml -f ./dev/docker-compose.dev.yml down -v --remove-orphans
|
||||
# Start: docker compose up
|
||||
# With helpers: docker compose -f docker-compose.yml -f ./dev/docker-compose.dev.yml up
|
||||
# Stop: docker compose down
|
||||
# Destroy: docker compose -f docker-compose.yml -f ./dev/docker-compose.dev.yml down -v --remove-orphans
|
||||
# Reset everything: ./reset.sh
|
||||
|
||||
name: supabase
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
|
||||
studio:
|
||||
image: supabase/studio:20240729-ce42139
|
||||
image: supabase/studio:2025.06.30-sha-6f5982d
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test:
|
||||
@@ -17,9 +18,10 @@ services:
|
||||
"CMD",
|
||||
"node",
|
||||
"-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
|
||||
retries: 3
|
||||
depends_on:
|
||||
@@ -31,6 +33,7 @@ services:
|
||||
|
||||
DEFAULT_ORGANIZATION_NAME: ${STUDIO_DEFAULT_ORGANIZATION}
|
||||
DEFAULT_PROJECT_NAME: ${STUDIO_DEFAULT_PROJECT}
|
||||
OPENAI_API_KEY: ${OPENAI_API_KEY:-}
|
||||
|
||||
SUPABASE_URL: http://kong:8000
|
||||
SUPABASE_PUBLIC_URL: ${SUPABASE_PUBLIC_URL}
|
||||
@@ -38,7 +41,7 @@ services:
|
||||
SUPABASE_SERVICE_KEY: ${SERVICE_ROLE_KEY}
|
||||
AUTH_JWT_SECRET: ${JWT_SECRET}
|
||||
|
||||
LOGFLARE_API_KEY: ${LOGFLARE_API_KEY}
|
||||
LOGFLARE_PRIVATE_ACCESS_TOKEN: ${LOGFLARE_PRIVATE_ACCESS_TOKEN}
|
||||
LOGFLARE_URL: http://analytics:4000
|
||||
NEXT_PUBLIC_ENABLE_LOGS: true
|
||||
# Comment to use Big Query backend for analytics
|
||||
@@ -49,8 +52,9 @@ services:
|
||||
kong:
|
||||
image: kong:2.8.1
|
||||
restart: unless-stopped
|
||||
# https://unix.stackexchange.com/a/294837
|
||||
entrypoint: bash -c 'eval "echo \"$$(cat ~/temp.yml)\"" > ~/kong.yml && /docker-entrypoint.sh kong docker-start'
|
||||
volumes:
|
||||
# https://github.com/supabase/supabase/issues/12661
|
||||
- ./volumes/api/kong.yml:/home/kong/temp.yml:ro,z
|
||||
depends_on:
|
||||
analytics:
|
||||
condition: service_healthy
|
||||
@@ -66,18 +70,13 @@ services:
|
||||
SUPABASE_SERVICE_KEY: ${SERVICE_ROLE_KEY}
|
||||
DASHBOARD_USERNAME: ${DASHBOARD_USERNAME}
|
||||
DASHBOARD_PASSWORD: ${DASHBOARD_PASSWORD}
|
||||
volumes:
|
||||
# https://github.com/supabase/supabase/issues/12661
|
||||
- ./volumes/api/kong.yml:/home/kong/temp.yml:ro
|
||||
# https://unix.stackexchange.com/a/294837
|
||||
entrypoint: bash -c 'eval "echo \"$$(cat ~/temp.yml)\"" > ~/kong.yml &&
|
||||
/docker-entrypoint.sh kong docker-start'
|
||||
|
||||
auth:
|
||||
image: supabase/gotrue:v2.158.1
|
||||
depends_on:
|
||||
db:
|
||||
# Disable this if you are using an external Postgres database
|
||||
condition: service_healthy
|
||||
analytics:
|
||||
condition: service_healthy
|
||||
image: supabase/gotrue:v2.176.1
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test:
|
||||
[
|
||||
@@ -86,12 +85,17 @@ services:
|
||||
"--no-verbose",
|
||||
"--tries=1",
|
||||
"--spider",
|
||||
"http://localhost:9999/health",
|
||||
"http://localhost:9999/health"
|
||||
]
|
||||
timeout: 5s
|
||||
interval: 5s
|
||||
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:
|
||||
GOTRUE_API_HOST: 0.0.0.0
|
||||
GOTRUE_API_PORT: 9999
|
||||
@@ -113,6 +117,10 @@ services:
|
||||
GOTRUE_EXTERNAL_EMAIL_ENABLED: ${ENABLE_EMAIL_SIGNUP}
|
||||
GOTRUE_EXTERNAL_ANONYMOUS_USERS_ENABLED: ${ENABLE_ANONYMOUS_USERS}
|
||||
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_SMTP_MAX_FREQUENCY: 1s
|
||||
GOTRUE_SMTP_ADMIN_EMAIL: ${SMTP_ADMIN_EMAIL}
|
||||
@@ -128,26 +136,35 @@ services:
|
||||
|
||||
GOTRUE_EXTERNAL_PHONE_ENABLED: ${ENABLE_PHONE_SIGNUP}
|
||||
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.
|
||||
# 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"
|
||||
# Uncomment to enable custom access token hook. Please see: https://supabase.com/docs/guides/auth/auth-hooks for full list of hooks and additional details about custom_access_token_hook
|
||||
|
||||
# GOTRUE_HOOK_MFA_VERIFICATION_ATTEMPT_ENABLED="true"
|
||||
# GOTRUE_HOOK_MFA_VERIFICATION_ATTEMPT_URI="pg-functions://postgres/public/mfa_verification_attempt"
|
||||
# GOTRUE_HOOK_CUSTOM_ACCESS_TOKEN_ENABLED: "true"
|
||||
# GOTRUE_HOOK_CUSTOM_ACCESS_TOKEN_URI: "pg-functions://postgres/public/custom_access_token_hook"
|
||||
# GOTRUE_HOOK_CUSTOM_ACCESS_TOKEN_SECRETS: "<standard-base64-secret>"
|
||||
|
||||
# GOTRUE_HOOK_PASSWORD_VERIFICATION_ATTEMPT_ENABLED="true"
|
||||
# GOTRUE_HOOK_PASSWORD_VERIFICATION_ATTEMPT_URI="pg-functions://postgres/public/password_verification_attempt"
|
||||
# GOTRUE_HOOK_MFA_VERIFICATION_ATTEMPT_ENABLED: "true"
|
||||
# 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:
|
||||
image: postgrest/postgrest:v12.2.0
|
||||
image: postgrest/postgrest:v12.2.12
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
db:
|
||||
# Disable this if you are using an external Postgres database
|
||||
condition: service_healthy
|
||||
analytics:
|
||||
condition: service_healthy
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
PGRST_DB_URI: postgres://authenticator:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}
|
||||
PGRST_DB_SCHEMAS: ${PGRST_DB_SCHEMAS}
|
||||
@@ -156,11 +173,12 @@ services:
|
||||
PGRST_DB_USE_LEGACY_GUCS: "false"
|
||||
PGRST_APP_SETTINGS_JWT_SECRET: ${JWT_SECRET}
|
||||
PGRST_APP_SETTINGS_JWT_EXP: ${JWT_EXPIRY}
|
||||
command: "postgrest"
|
||||
command: [ "postgrest" ]
|
||||
|
||||
realtime:
|
||||
# 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:
|
||||
db:
|
||||
# Disable this if you are using an external Postgres database
|
||||
@@ -178,12 +196,11 @@ services:
|
||||
"/dev/null",
|
||||
"-H",
|
||||
"Authorization: Bearer ${ANON_KEY}",
|
||||
"http://localhost:4000/api/tenants/realtime-dev/health",
|
||||
"http://localhost:4000/api/tenants/realtime-dev/health"
|
||||
]
|
||||
timeout: 5s
|
||||
interval: 5s
|
||||
retries: 3
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
PORT: 4000
|
||||
DB_HOST: ${POSTGRES_HOST}
|
||||
@@ -191,27 +208,23 @@ services:
|
||||
DB_USER: supabase_admin
|
||||
DB_PASSWORD: ${POSTGRES_PASSWORD}
|
||||
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
|
||||
API_JWT_SECRET: ${JWT_SECRET}
|
||||
SECRET_KEY_BASE: UpNVntn3cDxHJpq99YMc1T1AQgQpc8kfYTuRgBiYa15BLrx8etQoXz3gZv1/u2oq
|
||||
SECRET_KEY_BASE: ${SECRET_KEY_BASE}
|
||||
ERL_AFLAGS: -proto_dist inet_tcp
|
||||
DNS_NODES: "''"
|
||||
RLIMIT_NOFILE: "10000"
|
||||
APP_NAME: realtime
|
||||
SEED_SELF_HOST: true
|
||||
RUN_JANITOR: true
|
||||
|
||||
# To use S3 backed storage: docker compose -f docker-compose.yml -f docker-compose.s3.yml up
|
||||
storage:
|
||||
image: supabase/storage-api:v1.10.1
|
||||
depends_on:
|
||||
db:
|
||||
# Disable this if you are using an external Postgres database
|
||||
condition: service_healthy
|
||||
rest:
|
||||
condition: service_started
|
||||
imgproxy:
|
||||
condition: service_started
|
||||
image: supabase/storage-api:v1.24.7
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- ./volumes/storage:/var/lib/storage:z
|
||||
healthcheck:
|
||||
test:
|
||||
[
|
||||
@@ -220,12 +233,19 @@ services:
|
||||
"--no-verbose",
|
||||
"--tries=1",
|
||||
"--spider",
|
||||
"http://localhost:5000/status",
|
||||
"http://storage:5000/status"
|
||||
]
|
||||
timeout: 5s
|
||||
interval: 5s
|
||||
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:
|
||||
ANON_KEY: ${ANON_KEY}
|
||||
SERVICE_KEY: ${SERVICE_ROLE_KEY}
|
||||
@@ -241,13 +261,14 @@ services:
|
||||
GLOBAL_S3_BUCKET: stub
|
||||
ENABLE_IMAGE_TRANSFORMATION: "true"
|
||||
IMGPROXY_URL: http://imgproxy:5001
|
||||
volumes:
|
||||
- ./volumes/storage:/var/lib/storage:z
|
||||
|
||||
imgproxy:
|
||||
image: darthsim/imgproxy:v3.8.0
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- ./volumes/storage:/var/lib/storage:z
|
||||
healthcheck:
|
||||
test: ["CMD", "imgproxy", "health"]
|
||||
test: [ "CMD", "imgproxy", "health" ]
|
||||
timeout: 5s
|
||||
interval: 5s
|
||||
retries: 3
|
||||
@@ -256,18 +277,16 @@ services:
|
||||
IMGPROXY_LOCAL_FILESYSTEM_ROOT: /
|
||||
IMGPROXY_USE_ETAG: "true"
|
||||
IMGPROXY_ENABLE_WEBP_DETECTION: ${IMGPROXY_ENABLE_WEBP_DETECTION}
|
||||
volumes:
|
||||
- ./volumes/storage:/var/lib/storage:z
|
||||
|
||||
meta:
|
||||
image: supabase/postgres-meta:v0.83.2
|
||||
image: supabase/postgres-meta:v0.89.3
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
db:
|
||||
# Disable this if you are using an external Postgres database
|
||||
condition: service_healthy
|
||||
analytics:
|
||||
condition: service_healthy
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
PG_META_PORT: 8080
|
||||
PG_META_DB_HOST: ${POSTGRES_HOST}
|
||||
@@ -277,8 +296,10 @@ services:
|
||||
PG_META_DB_PASSWORD: ${POSTGRES_PASSWORD}
|
||||
|
||||
functions:
|
||||
image: supabase/edge-runtime:v1.56.1
|
||||
image: supabase/edge-runtime:v1.67.4
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- ./volumes/functions:/home/deno/functions:Z
|
||||
depends_on:
|
||||
analytics:
|
||||
condition: service_healthy
|
||||
@@ -290,80 +311,52 @@ services:
|
||||
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
|
||||
VERIFY_JWT: "${FUNCTIONS_VERIFY_JWT}"
|
||||
volumes:
|
||||
- ./volumes/functions:/home/deno/functions:Z
|
||||
command:
|
||||
- start
|
||||
- --main-service
|
||||
- /home/deno/functions/main
|
||||
command: [ "start", "--main-service", "/home/deno/functions/main" ]
|
||||
|
||||
analytics:
|
||||
image: supabase/logflare:1.4.0
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "http://localhost:4000/health"]
|
||||
timeout: 5s
|
||||
interval: 5s
|
||||
retries: 10
|
||||
image: supabase/logflare:1.14.2
|
||||
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
|
||||
# volumes:
|
||||
# - type: bind
|
||||
# source: ${PWD}/gcloud.json
|
||||
# target: /opt/app/rel/logflare/bin/gcloud.json
|
||||
# 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:
|
||||
LOGFLARE_NODE_HOST: 127.0.0.1
|
||||
DB_USERNAME: supabase_admin
|
||||
DB_DATABASE: ${POSTGRES_DB}
|
||||
DB_DATABASE: _supabase
|
||||
DB_HOSTNAME: ${POSTGRES_HOST}
|
||||
DB_PORT: ${POSTGRES_PORT}
|
||||
DB_PASSWORD: ${POSTGRES_PASSWORD}
|
||||
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_SUPABASE_MODE: true
|
||||
LOGFLARE_MIN_CLUSTER_SIZE: 1
|
||||
|
||||
# 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
|
||||
LOGFLARE_FEATURE_FLAG_OVERRIDE: multibackend=true
|
||||
# Uncomment to use Big Query backend for analytics
|
||||
# GOOGLE_PROJECT_ID: ${GOOGLE_PROJECT_ID}
|
||||
# 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:
|
||||
image: supabase/postgres:15.1.1.78
|
||||
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
|
||||
image: supabase/postgres:15.8.1.060
|
||||
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/db/realtime.sql:/docker-entrypoint-initdb.d/migrations/99-realtime.sql:Z
|
||||
# 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
|
||||
# PGDATA directory is persisted between restarts
|
||||
- ./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
|
||||
- ./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
|
||||
- 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:
|
||||
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:
|
||||
test:
|
||||
[
|
||||
@@ -389,17 +416,67 @@ services:
|
||||
"--no-verbose",
|
||||
"--tries=1",
|
||||
"--spider",
|
||||
"http://vector:9001/health",
|
||||
"http://vector:9001/health"
|
||||
]
|
||||
timeout: 5s
|
||||
interval: 5s
|
||||
retries: 3
|
||||
volumes:
|
||||
- ./volumes/logs/vector.yml:/etc/vector/vector.yml:ro
|
||||
- ${DOCKER_SOCKET_LOCATION}:/var/run/docker.sock:ro
|
||||
environment:
|
||||
LOGFLARE_API_KEY: ${LOGFLARE_API_KEY}
|
||||
command: ["--config", "etc/vector/vector.yml"]
|
||||
LOGFLARE_PUBLIC_ACCESS_TOKEN: ${LOGFLARE_PUBLIC_ACCESS_TOKEN}
|
||||
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:
|
||||
db-config:
|
||||
|
||||
Executable
+44
@@ -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!"
|
||||
@@ -0,0 +1,3 @@
|
||||
\set pguser `echo "$POSTGRES_USER"`
|
||||
|
||||
CREATE DATABASE _supabase WITH OWNER :pguser;
|
||||
@@ -1,4 +1,6 @@
|
||||
\set pguser `echo "$POSTGRES_USER"`
|
||||
|
||||
\c _supabase
|
||||
create schema if not exists _analytics;
|
||||
alter schema _analytics owner to :pguser;
|
||||
\c postgres
|
||||
|
||||
@@ -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
|
||||
@@ -165,7 +165,9 @@ sinks:
|
||||
method: 'post'
|
||||
request:
|
||||
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:
|
||||
type: 'http'
|
||||
inputs:
|
||||
@@ -175,7 +177,9 @@ sinks:
|
||||
method: 'post'
|
||||
request:
|
||||
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:
|
||||
type: 'http'
|
||||
inputs:
|
||||
@@ -185,7 +189,9 @@ sinks:
|
||||
method: 'post'
|
||||
request:
|
||||
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:
|
||||
type: 'http'
|
||||
inputs:
|
||||
@@ -195,10 +201,12 @@ sinks:
|
||||
method: 'post'
|
||||
request:
|
||||
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
|
||||
# lead to broken queries from studio. This works by the assumption that containers are started in the
|
||||
# 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:
|
||||
type: 'http'
|
||||
inputs:
|
||||
@@ -208,7 +216,9 @@ sinks:
|
||||
method: 'post'
|
||||
request:
|
||||
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:
|
||||
type: 'http'
|
||||
inputs:
|
||||
@@ -218,7 +228,9 @@ sinks:
|
||||
method: 'post'
|
||||
request:
|
||||
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:
|
||||
type: 'http'
|
||||
inputs:
|
||||
@@ -229,4 +241,6 @@ sinks:
|
||||
method: 'post'
|
||||
request:
|
||||
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'
|
||||
|
||||
@@ -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
|
||||
@@ -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");
|
||||
@@ -1,25 +1,18 @@
|
||||
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=http://localhost:3000
|
||||
# Uncoment if you are serving your front on another server than the API (eg. bucket)
|
||||
# FRONT_BASE_URL=http://localhost:3000
|
||||
SERVER_URL=https://$(PRIMARY_DOMAIN)
|
||||
|
||||
# Use openssl rand -base64 32 for each secret
|
||||
ACCESS_TOKEN_SECRET=replace_me_with_a_random_string_access
|
||||
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
|
||||
APP_SECRET=replace_me_with_a_random_string
|
||||
|
||||
STORAGE_TYPE=local
|
||||
|
||||
# STORAGE_S3_REGION=eu-west3
|
||||
# STORAGE_S3_NAME=my-bucket
|
||||
# STORAGE_S3_ENDPOINT=
|
||||
|
||||
MESSAGE_QUEUE_TYPE=pg-boss
|
||||
|
||||
+16
-39
@@ -1,50 +1,27 @@
|
||||
dev-build:
|
||||
@docker compose -f dev/docker-compose.yml down -v
|
||||
@docker compose -f dev/docker-compose.yml build
|
||||
# Makefile for building Twenty CRM docker images.
|
||||
# Set the tag and/or target build platform using make command-line variables assignments.
|
||||
#
|
||||
# Optional make variables:
|
||||
# PLATFORM - defaults to 'linux/amd64'
|
||||
# TAG - defaults to 'latest'
|
||||
#
|
||||
# Example: make
|
||||
# Example: make PLATFORM=linux/aarch64 TAG=my-tag
|
||||
|
||||
dev-up:
|
||||
@docker compose -f dev/docker-compose.yml up -d
|
||||
|
||||
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
|
||||
PLATFORM ?= linux/amd64
|
||||
TAG ?= latest
|
||||
|
||||
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:
|
||||
@docker run -d -p 3000:3000 --name twenty twenty
|
||||
|
||||
prod-postgres-build:
|
||||
@cd ../.. && docker build -f ./packages/twenty-docker/twenty-postgres/Dockerfile --tag twenty-postgres . && cd -
|
||||
@docker run -d -p 3000:3000 --name twenty twenty:$(TAG)
|
||||
|
||||
prod-postgres-run:
|
||||
@docker run -d -p 5432:5432 -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres --name twenty-postgres twenty-postgres
|
||||
@docker run -d -p 5432:5432 -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres --name twenty-postgres twenty-postgres:$(TAG)
|
||||
|
||||
prod-website-build:
|
||||
@cd ../.. && docker build -f ./packages/twenty-docker/twenty-website/Dockerfile --tag twenty-website . && cd -
|
||||
@cd ../.. && docker build -f ./packages/twenty-docker/twenty-website/Dockerfile --platform $(PLATFORM) --tag twenty-website:$(TAG) . && cd -
|
||||
|
||||
prod-website-run:
|
||||
@docker run -d -p 3000:3000 --name twenty-website twenty-website
|
||||
|
||||
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 -
|
||||
@docker run -d -p 3000:3000 --name twenty-website twenty-website:$(TAG)
|
||||
|
||||
@@ -1,72 +1,100 @@
|
||||
version: "3.9"
|
||||
name: twenty
|
||||
|
||||
services:
|
||||
change-vol-ownership:
|
||||
image: ubuntu
|
||||
user: root
|
||||
volumes:
|
||||
- server-local-data:/tmp/server-local-data
|
||||
- docker-data:/tmp/docker-data
|
||||
command: >
|
||||
bash -c "
|
||||
chown -R 1000:1000 /tmp/server-local-data
|
||||
&& chown -R 1000:1000 /tmp/docker-data"
|
||||
|
||||
server:
|
||||
image: twentycrm/twenty:${TAG}
|
||||
image: twentycrm/twenty:${TAG:-latest}
|
||||
volumes:
|
||||
- server-local-data:/app/packages/twenty-server/${STORAGE_LOCAL_PATH:-.local-storage}
|
||||
- docker-data:/app/docker-data
|
||||
- server-local-data:/app/packages/twenty-server/.local-storage
|
||||
environment:
|
||||
PORT: 3000
|
||||
PG_DATABASE_URL: postgres://twenty:twenty@${PG_DATABASE_HOST}/default
|
||||
NODE_PORT: 3000
|
||||
PG_DATABASE_URL: postgres://${PG_DATABASE_USER:-postgres}:${PG_DATABASE_PASSWORD:-postgres}@${PG_DATABASE_HOST:-db}:${PG_DATABASE_PORT:-5432}/default
|
||||
SERVER_URL: ${SERVER_URL}
|
||||
FRONT_BASE_URL: ${FRONT_BASE_URL:-$SERVER_URL}
|
||||
MESSAGE_QUEUE_TYPE: ${MESSAGE_QUEUE_TYPE}
|
||||
REDIS_URL: ${REDIS_URL:-redis://redis:6379}
|
||||
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_S3_REGION: ${STORAGE_S3_REGION}
|
||||
STORAGE_S3_NAME: ${STORAGE_S3_NAME}
|
||||
STORAGE_S3_ENDPOINT: ${STORAGE_S3_ENDPOINT}
|
||||
ACCESS_TOKEN_SECRET: ${ACCESS_TOKEN_SECRET}
|
||||
LOGIN_TOKEN_SECRET: ${LOGIN_TOKEN_SECRET}
|
||||
REFRESH_TOKEN_SECRET: ${REFRESH_TOKEN_SECRET}
|
||||
FILE_TOKEN_SECRET: ${FILE_TOKEN_SECRET}
|
||||
|
||||
APP_SECRET: ${APP_SECRET:-replace_me_with_a_random_string}
|
||||
# MESSAGING_PROVIDER_GMAIL_ENABLED: ${MESSAGING_PROVIDER_GMAIL_ENABLED}
|
||||
# CALENDAR_PROVIDER_GOOGLE_ENABLED: ${CALENDAR_PROVIDER_GOOGLE_ENABLED}
|
||||
# AUTH_GOOGLE_CLIENT_ID: ${AUTH_GOOGLE_CLIENT_ID}
|
||||
# AUTH_GOOGLE_CLIENT_SECRET: ${AUTH_GOOGLE_CLIENT_SECRET}
|
||||
# AUTH_GOOGLE_CALLBACK_URL: ${AUTH_GOOGLE_CALLBACK_URL}
|
||||
# AUTH_GOOGLE_APIS_CALLBACK_URL: ${AUTH_GOOGLE_APIS_CALLBACK_URL}
|
||||
|
||||
# CALENDAR_PROVIDER_MICROSOFT_ENABLED: ${CALENDAR_PROVIDER_MICROSOFT_ENABLED}
|
||||
# MESSAGING_PROVIDER_MICROSOFT_ENABLED: ${MESSAGING_PROVIDER_MICROSOFT_ENABLED}
|
||||
# AUTH_MICROSOFT_ENABLED: ${AUTH_MICROSOFT_ENABLED}
|
||||
# AUTH_MICROSOFT_CLIENT_ID: ${AUTH_MICROSOFT_CLIENT_ID}
|
||||
# AUTH_MICROSOFT_CLIENT_SECRET: ${AUTH_MICROSOFT_CLIENT_SECRET}
|
||||
# AUTH_MICROSOFT_CALLBACK_URL: ${AUTH_MICROSOFT_CALLBACK_URL}
|
||||
# AUTH_MICROSOFT_APIS_CALLBACK_URL: ${AUTH_MICROSOFT_APIS_CALLBACK_URL}
|
||||
|
||||
# EMAIL_FROM_ADDRESS: ${EMAIL_FROM_ADDRESS:-contact@yourdomain.com}
|
||||
# EMAIL_FROM_NAME: ${EMAIL_FROM_NAME:-"John from YourDomain"}
|
||||
# EMAIL_SYSTEM_ADDRESS: ${EMAIL_SYSTEM_ADDRESS:-system@yourdomain.com}
|
||||
# EMAIL_DRIVER: ${EMAIL_DRIVER:-smtp}
|
||||
# EMAIL_SMTP_HOST: ${EMAIL_SMTP_HOST:-smtp.gmail.com}
|
||||
# EMAIL_SMTP_PORT: ${EMAIL_SMTP_PORT:-465}
|
||||
# EMAIL_SMTP_USER: ${EMAIL_SMTP_USER:-}
|
||||
# EMAIL_SMTP_PASSWORD: ${EMAIL_SMTP_PASSWORD:-}
|
||||
|
||||
depends_on:
|
||||
change-vol-ownership:
|
||||
condition: service_completed_successfully
|
||||
db:
|
||||
condition: service_healthy
|
||||
healthcheck:
|
||||
test: curl --fail http://localhost:3000/healthz
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
retries: 20
|
||||
restart: always
|
||||
|
||||
worker:
|
||||
image: twentycrm/twenty:${TAG}
|
||||
command: ["yarn", "worker:prod"]
|
||||
image: twentycrm/twenty:${TAG:-latest}
|
||||
volumes:
|
||||
- server-local-data:/app/packages/twenty-server/.local-storage
|
||||
command: [ "yarn", "worker:prod" ]
|
||||
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}
|
||||
FRONT_BASE_URL: ${FRONT_BASE_URL:-$SERVER_URL}
|
||||
MESSAGE_QUEUE_TYPE: ${MESSAGE_QUEUE_TYPE}
|
||||
|
||||
ENABLE_DB_MIGRATIONS: "false" # it already runs on the server
|
||||
REDIS_URL: ${REDIS_URL:-redis://redis:6379}
|
||||
DISABLE_DB_MIGRATIONS: "true" # it already runs on the server
|
||||
DISABLE_CRON_JOBS_REGISTRATION: "true" # it already runs on the server
|
||||
|
||||
STORAGE_TYPE: ${STORAGE_TYPE}
|
||||
STORAGE_S3_REGION: ${STORAGE_S3_REGION}
|
||||
STORAGE_S3_NAME: ${STORAGE_S3_NAME}
|
||||
STORAGE_S3_ENDPOINT: ${STORAGE_S3_ENDPOINT}
|
||||
ACCESS_TOKEN_SECRET: ${ACCESS_TOKEN_SECRET}
|
||||
LOGIN_TOKEN_SECRET: ${LOGIN_TOKEN_SECRET}
|
||||
REFRESH_TOKEN_SECRET: ${REFRESH_TOKEN_SECRET}
|
||||
FILE_TOKEN_SECRET: ${FILE_TOKEN_SECRET}
|
||||
|
||||
APP_SECRET: ${APP_SECRET:-replace_me_with_a_random_string}
|
||||
# MESSAGING_PROVIDER_GMAIL_ENABLED: ${MESSAGING_PROVIDER_GMAIL_ENABLED}
|
||||
# CALENDAR_PROVIDER_GOOGLE_ENABLED: ${CALENDAR_PROVIDER_GOOGLE_ENABLED}
|
||||
# AUTH_GOOGLE_CLIENT_ID: ${AUTH_GOOGLE_CLIENT_ID}
|
||||
# AUTH_GOOGLE_CLIENT_SECRET: ${AUTH_GOOGLE_CLIENT_SECRET}
|
||||
# AUTH_GOOGLE_CALLBACK_URL: ${AUTH_GOOGLE_CALLBACK_URL}
|
||||
# AUTH_GOOGLE_APIS_CALLBACK_URL: ${AUTH_GOOGLE_APIS_CALLBACK_URL}
|
||||
|
||||
# CALENDAR_PROVIDER_MICROSOFT_ENABLED: ${CALENDAR_PROVIDER_MICROSOFT_ENABLED}
|
||||
# MESSAGING_PROVIDER_MICROSOFT_ENABLED: ${MESSAGING_PROVIDER_MICROSOFT_ENABLED}
|
||||
# AUTH_MICROSOFT_ENABLED: ${AUTH_MICROSOFT_ENABLED}
|
||||
# AUTH_MICROSOFT_CLIENT_ID: ${AUTH_MICROSOFT_CLIENT_ID}
|
||||
# AUTH_MICROSOFT_CLIENT_SECRET: ${AUTH_MICROSOFT_CLIENT_SECRET}
|
||||
# AUTH_MICROSOFT_CALLBACK_URL: ${AUTH_MICROSOFT_CALLBACK_URL}
|
||||
# AUTH_MICROSOFT_APIS_CALLBACK_URL: ${AUTH_MICROSOFT_APIS_CALLBACK_URL}
|
||||
|
||||
# EMAIL_FROM_ADDRESS: ${EMAIL_FROM_ADDRESS:-contact@yourdomain.com}
|
||||
# EMAIL_FROM_NAME: ${EMAIL_FROM_NAME:-"John from YourDomain"}
|
||||
# EMAIL_SYSTEM_ADDRESS: ${EMAIL_SYSTEM_ADDRESS:-system@yourdomain.com}
|
||||
# EMAIL_DRIVER: ${EMAIL_DRIVER:-smtp}
|
||||
# EMAIL_SMTP_HOST: ${EMAIL_SMTP_HOST:-smtp.gmail.com}
|
||||
# EMAIL_SMTP_PORT: ${EMAIL_SMTP_PORT:-465}
|
||||
# EMAIL_SMTP_USER: ${EMAIL_SMTP_USER:-}
|
||||
# EMAIL_SMTP_PASSWORD: ${EMAIL_SMTP_PASSWORD:-}
|
||||
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
@@ -75,19 +103,24 @@ services:
|
||||
restart: always
|
||||
|
||||
db:
|
||||
image: twentycrm/twenty-postgres:${TAG}
|
||||
image: postgres:16
|
||||
volumes:
|
||||
- db-data:/bitnami/postgresql
|
||||
- db-data:/var/lib/postgresql/data
|
||||
environment:
|
||||
POSTGRES_PASSWORD: ${POSTGRES_ADMIN_PASSWORD}
|
||||
POSTGRES_USER: ${PG_DATABASE_USER:-postgres}
|
||||
POSTGRES_PASSWORD: ${PG_DATABASE_PASSWORD:-postgres}
|
||||
healthcheck:
|
||||
test: pg_isready -U twenty -d default
|
||||
test: pg_isready -U ${PG_DATABASE_USER:-postgres} -h localhost -d postgres
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
restart: always
|
||||
|
||||
redis:
|
||||
image: redis
|
||||
restart: always
|
||||
command: [ "--maxmemory-policy", "noeviction" ]
|
||||
|
||||
volumes:
|
||||
docker-data:
|
||||
db-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
|
||||
@@ -1,4 +1,7 @@
|
||||
# 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
|
||||
|
||||
|
||||
@@ -22,33 +22,37 @@ spec:
|
||||
app: twentycrm-db
|
||||
spec:
|
||||
volumes:
|
||||
- name: twentycrm-db-data
|
||||
persistentVolumeClaim:
|
||||
claimName: twentycrm-db-pvc
|
||||
- name: twentycrm-db-data
|
||||
persistentVolumeClaim:
|
||||
claimName: twentycrm-db-pvc
|
||||
containers:
|
||||
- env:
|
||||
- name: POSTGRES_PASSWORD
|
||||
value: "twenty"
|
||||
- name: BITNAMI_DEBUG
|
||||
value: "true"
|
||||
- image: twentycrm/twenty-postgres:latest
|
||||
imagePullPolicy: Always
|
||||
name: twentycrm
|
||||
ports:
|
||||
- containerPort: 5432
|
||||
name: tcp
|
||||
protocol: TCP
|
||||
resources:
|
||||
requests:
|
||||
memory: "256Mi"
|
||||
cpu: "250m"
|
||||
limits:
|
||||
memory: "1024Mi"
|
||||
cpu: "1000m"
|
||||
stdin: true
|
||||
tty: true
|
||||
volumeMounts:
|
||||
- mountPath: /bitnami/postgresql
|
||||
name: twentycrm-db-data
|
||||
- name: twentycrm
|
||||
image: twentycrm/twenty-postgres-spilo:latest
|
||||
imagePullPolicy: Always
|
||||
env:
|
||||
- name: PGUSER_SUPERUSER
|
||||
value: "postgres"
|
||||
- name: PGPASSWORD_SUPERUSER
|
||||
value: "postgres"
|
||||
- name: SPILO_PROVIDER
|
||||
value: "local"
|
||||
- name: ALLOW_NOSSL
|
||||
value: "true"
|
||||
ports:
|
||||
- containerPort: 5432
|
||||
name: tcp
|
||||
protocol: TCP
|
||||
resources:
|
||||
requests:
|
||||
memory: "256Mi"
|
||||
cpu: "250m"
|
||||
limits:
|
||||
memory: "1024Mi"
|
||||
cpu: "1000m"
|
||||
stdin: true
|
||||
tty: true
|
||||
volumeMounts:
|
||||
- mountPath: /home/postgres/pgdata
|
||||
name: twentycrm-db-data
|
||||
dnsPolicy: ClusterFirst
|
||||
restartPolicy: Always
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
app: twentycrm-redis
|
||||
name: twentycrm-redis
|
||||
namespace: twentycrm
|
||||
spec:
|
||||
progressDeadlineSeconds: 600
|
||||
replicas: 1
|
||||
strategy:
|
||||
rollingUpdate:
|
||||
maxSurge: 1
|
||||
maxUnavailable: 1
|
||||
type: RollingUpdate
|
||||
selector:
|
||||
matchLabels:
|
||||
app: twentycrm-redis
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: twentycrm-redis
|
||||
spec:
|
||||
containers:
|
||||
- name: redis
|
||||
image: redis/redis-stack-server:latest
|
||||
imagePullPolicy: Always
|
||||
args: ["--maxmemory-policy", "noeviction"]
|
||||
env:
|
||||
- name: PORT
|
||||
value: "6379"
|
||||
ports:
|
||||
- containerPort: 6379
|
||||
name: redis
|
||||
protocol: TCP
|
||||
resources:
|
||||
requests:
|
||||
memory: "1024Mi"
|
||||
cpu: "250m"
|
||||
limits:
|
||||
memory: "2048Mi"
|
||||
cpu: "500m"
|
||||
|
||||
dnsPolicy: ClusterFirst
|
||||
restartPolicy: Always
|
||||
@@ -22,67 +22,55 @@ spec:
|
||||
app: twentycrm-server
|
||||
spec:
|
||||
volumes:
|
||||
- name: twentycrm-server-data
|
||||
persistentVolumeClaim:
|
||||
claimName: twentycrm-server-pvc
|
||||
- name: twentycrm-server-data
|
||||
persistentVolumeClaim:
|
||||
claimName: twentycrm-server-pvc
|
||||
- name: twentycrm-docker-data
|
||||
persistentVolumeClaim:
|
||||
claimName: twentycrm-docker-data-pvc
|
||||
containers:
|
||||
- env:
|
||||
- name: PORT
|
||||
value: 3000
|
||||
- name: SERVER_URL
|
||||
value: "https://crm.example.com:443"
|
||||
- name: FRONT_BASE_URL
|
||||
value: "https://crm.example.com:443"
|
||||
- name: PG_DATABASE_URL
|
||||
value: "postgres://twenty:twenty@twenty-db.twentycrm.svc.cluster.local/default"
|
||||
- name: ENABLE_DB_MIGRATIONS
|
||||
value: "true"
|
||||
- name: SIGN_IN_PREFILLED
|
||||
value: "true"
|
||||
- name: STORAGE_TYPE
|
||||
value: "local"
|
||||
- name: "MESSAGE_QUEUE_TYPE"
|
||||
value: "pg-boss"
|
||||
- name: ACCESS_TOKEN_SECRET
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: tokens
|
||||
key: accessToken
|
||||
- name: LOGIN_TOKEN_SECRET
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: tokens
|
||||
key: loginToken
|
||||
- name: REFRESH_TOKEN_SECRET
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: tokens
|
||||
key: refreshToken
|
||||
- name: FILE_TOKEN_SECRET
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: tokens
|
||||
key: fileToken
|
||||
- image: twentycrm/twenty:latest
|
||||
imagePullPolicy: Always
|
||||
name: twentycrm
|
||||
ports:
|
||||
- containerPort: 3000
|
||||
name: http-tcp
|
||||
protocol: TCP
|
||||
resources:
|
||||
requests:
|
||||
memory: "256Mi"
|
||||
cpu: "250m"
|
||||
limits:
|
||||
memory: "1024Mi"
|
||||
cpu: "1000m"
|
||||
stdin: true
|
||||
tty: true
|
||||
volumeMounts:
|
||||
- mountPath: /app/docker-data
|
||||
name: twentycrm-server-data
|
||||
- mountPath: /app/.local-storage
|
||||
name: twentycrm-server-data
|
||||
- name: twentycrm
|
||||
image: twentycrm/twenty:latest
|
||||
imagePullPolicy: Always
|
||||
env:
|
||||
- name: NODE_PORT
|
||||
value: 3000
|
||||
- name: SERVER_URL
|
||||
value: "https://crm.example.com:443"
|
||||
- name: "PG_DATABASE_URL"
|
||||
value: "postgres://postgres:postgres@twentycrm-db.twentycrm.svc.cluster.local/default"
|
||||
- name: "REDIS_URL"
|
||||
value: "redis://twentycrm-redis.twentycrm.svc.cluster.local:6379"
|
||||
- name: SIGN_IN_PREFILLED
|
||||
value: "false"
|
||||
- name: STORAGE_TYPE
|
||||
value: "local"
|
||||
- name: "ACCESS_TOKEN_EXPIRES_IN"
|
||||
value: "7d"
|
||||
- name: "LOGIN_TOKEN_EXPIRES_IN"
|
||||
value: "1h"
|
||||
- name: APP_SECRET
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: tokens
|
||||
key: accessToken
|
||||
ports:
|
||||
- containerPort: 3000
|
||||
name: http-tcp
|
||||
protocol: TCP
|
||||
resources:
|
||||
requests:
|
||||
memory: "256Mi"
|
||||
cpu: "250m"
|
||||
limits:
|
||||
memory: "1024Mi"
|
||||
cpu: "1000m"
|
||||
stdin: true
|
||||
tty: true
|
||||
volumeMounts:
|
||||
- mountPath: /app/docker-data
|
||||
name: twentycrm-docker-data
|
||||
- mountPath: /app/packages/twenty-server/.local-storage
|
||||
name: twentycrm-server-data
|
||||
dnsPolicy: ClusterFirst
|
||||
restartPolicy: Always
|
||||
|
||||
@@ -21,58 +21,37 @@ spec:
|
||||
labels:
|
||||
app: twentycrm-worker
|
||||
spec:
|
||||
volumes:
|
||||
- name: twentycrm-worker-data
|
||||
persistentVolumeClaim:
|
||||
claimName: twentycrm-worker-pvc
|
||||
containers:
|
||||
- env:
|
||||
- name: SERVER_URL
|
||||
value: "https://crm.example.com:443"
|
||||
- name: FRONT_BASE_URL
|
||||
value: "https://crm.example.com:443"
|
||||
- name: PG_DATABASE_URL
|
||||
value: "postgres://twenty:twenty@twenty-db.twentycrm.svc.cluster.local/default"
|
||||
- name: ENABLE_DB_MIGRATIONS
|
||||
value: "false" # it already runs on the server
|
||||
- name: STORAGE_TYPE
|
||||
value: "local"
|
||||
- name: "MESSAGE_QUEUE_TYPE"
|
||||
value: "pg-boss"
|
||||
- name: ACCESS_TOKEN_SECRET
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: tokens
|
||||
key: accessToken
|
||||
- name: LOGIN_TOKEN_SECRET
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: tokens
|
||||
key: loginToken
|
||||
- name: REFRESH_TOKEN_SECRET
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: tokens
|
||||
key: refreshToken
|
||||
- name: FILE_TOKEN_SECRET
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
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
|
||||
- name: twentycrm
|
||||
image: twentycrm/twenty:latest
|
||||
imagePullPolicy: Always
|
||||
env:
|
||||
- name: SERVER_URL
|
||||
value: "https://crm.example.com:443"
|
||||
- name: PG_DATABASE_URL
|
||||
value: "postgres://postgres:postgres@twentycrm-db.twentycrm.svc.cluster.local/default"
|
||||
- name: DISABLE_DB_MIGRATIONS
|
||||
value: "false" # it already runs on the server
|
||||
- name: STORAGE_TYPE
|
||||
value: "local"
|
||||
- name: "REDIS_URL"
|
||||
value: "redis://twentycrm-redis.twentycrm.svc.cluster.local:6379"
|
||||
- name: APP_SECRET
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: tokens
|
||||
key: accessToken
|
||||
command:
|
||||
- yarn
|
||||
- worker:prod
|
||||
resources:
|
||||
requests:
|
||||
memory: "1024Mi"
|
||||
cpu: "250m"
|
||||
limits:
|
||||
memory: "2048Mi"
|
||||
cpu: "1000m"
|
||||
stdin: true
|
||||
tty: true
|
||||
dnsPolicy: ClusterFirst
|
||||
restartPolicy: Always
|
||||
|
||||
@@ -4,21 +4,21 @@ metadata:
|
||||
name: twentycrm
|
||||
namespace: twentycrm
|
||||
annotations:
|
||||
nginx.ingress.kubernetes.io/configuration-snippet: |
|
||||
nginx.ingress.kubernetes.io/configuration-snippet: |
|
||||
more_set_headers "X-Forwarded-For $http_x_forwarded_for";
|
||||
nginx.ingress.kubernetes.io/force-ssl-redirect: "false"
|
||||
kubernetes.io/ingress.class: "nginx"
|
||||
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
|
||||
nginx.ingress.kubernetes.io/force-ssl-redirect: "false"
|
||||
kubernetes.io/ingress.class: "nginx"
|
||||
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
|
||||
spec:
|
||||
ingressClassName: nginx
|
||||
rules:
|
||||
- host: crm.example.com
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: twentycrm-server
|
||||
port:
|
||||
name: http-tcp
|
||||
- host: crm.example.com
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: twentycrm-server
|
||||
port:
|
||||
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
|
||||
@@ -6,9 +6,9 @@ metadata:
|
||||
spec:
|
||||
internalTrafficPolicy: Cluster
|
||||
ports:
|
||||
- port: 5432
|
||||
protocol: TCP
|
||||
targetPort: 5432
|
||||
- port: 5432
|
||||
protocol: TCP
|
||||
targetPort: 5432
|
||||
selector:
|
||||
app: twentycrm-db
|
||||
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:
|
||||
internalTrafficPolicy: Cluster
|
||||
ports:
|
||||
- name: http-tcp
|
||||
port: 3000
|
||||
protocol: TCP
|
||||
targetPort: 3000
|
||||
- name: http-tcp
|
||||
port: 3000
|
||||
protocol: TCP
|
||||
targetPort: 3000
|
||||
selector:
|
||||
app: twentycrm-server
|
||||
sessionAffinity: ClientIP
|
||||
|
||||
@@ -15,12 +15,12 @@ output:
|
||||
<!-- BEGIN_TF_DOCS -->
|
||||
# TwentyCRM Terraform Docs
|
||||
|
||||
This file was generated by [terraform-docs](https://terraform-docs.io/), for more information on how to install, configure and use visit their website.
|
||||
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`
|
||||
|
||||
|
||||
{{ .Content }}
|
||||
<!-- END_TF_DOCS -->
|
||||
|
||||
@@ -45,4 +45,4 @@ settings:
|
||||
read-comments: true
|
||||
required: true
|
||||
sensitive: true
|
||||
type: true
|
||||
type: true
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<!-- BEGIN_TF_DOCS -->
|
||||
# TwentyCRM Terraform Docs
|
||||
|
||||
This file was generated by [terraform-docs](https://terraform-docs.io/), for more information on how to install, configure and use visit their website.
|
||||
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`
|
||||
|
||||
@@ -12,30 +12,37 @@ To make configuration changes to how this doc is generated, see `./.terraform-do
|
||||
| Name | Version |
|
||||
|------|---------|
|
||||
| <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
|
||||
|
||||
| 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
|
||||
|
||||
| Name | Type |
|
||||
|------|------|
|
||||
| [kubernetes_deployment.twentycrm_db](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/deployment) | resource |
|
||||
| [kubernetes_deployment.twentycrm_redis](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/deployment) | resource |
|
||||
| [kubernetes_deployment.twentycrm_server](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/deployment) | resource |
|
||||
| [kubernetes_deployment.twentycrm_worker](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/deployment) | resource |
|
||||
| [kubernetes_ingress.twentycrm](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/ingress) | resource |
|
||||
| [kubernetes_namespace.twentycrm](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/namespace) | resource |
|
||||
| [kubernetes_persistent_volume.db](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/persistent_volume) | resource |
|
||||
| [kubernetes_persistent_volume.docker_data](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/persistent_volume) | resource |
|
||||
| [kubernetes_persistent_volume.server](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/persistent_volume) | resource |
|
||||
| [kubernetes_persistent_volume_claim.db](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/persistent_volume_claim) | resource |
|
||||
| [kubernetes_persistent_volume_claim.docker_data](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/persistent_volume_claim) | resource |
|
||||
| [kubernetes_persistent_volume_claim.server](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/persistent_volume_claim) | resource |
|
||||
| [kubernetes_secret.twentycrm_tokens](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/secret) | resource |
|
||||
| [kubernetes_service.twentycrm_db](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/service) | resource |
|
||||
| [kubernetes_service.twentycrm_redis](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/service) | resource |
|
||||
| [kubernetes_service.twentycrm_server](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/service) | resource |
|
||||
| [random_bytes.this](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/bytes) | resource |
|
||||
|
||||
## Inputs
|
||||
|
||||
@@ -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_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_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_path"></a> [twentycrm\_db\_pv\_path](#input\_twentycrm\_db\_pv\_path) | Local path to use to store the physical volume if using local storage on nodes. | `string` | `""` | no |
|
||||
| <a name="input_twentycrm_db_pvc_requests"></a> [twentycrm\_db\_pvc\_requests](#input\_twentycrm\_db\_pvc\_requests) | Storage capacity reservation for database persistent volume claim. | `string` | `"10Gi"` | no |
|
||||
| <a name="input_twentycrm_db_replicas"></a> [twentycrm\_db\_replicas](#input\_twentycrm\_db\_replicas) | Number of replicas for the TwentyCRM database deployment. This defaults to 1. | `number` | `1` | no |
|
||||
| <a name="input_twentycrm_docker_data_mount_path"></a> [twentycrm\_docker\_data\_mount\_path](#input\_twentycrm\_docker\_data\_mount\_path) | TwentyCRM mount path for servers application data. Defaults to '/app/docker-data'. | `string` | `"/app/docker-data"` | no |
|
||||
| <a name="input_twentycrm_docker_data_pv_capacity"></a> [twentycrm\_docker\_data\_pv\_capacity](#input\_twentycrm\_docker\_data\_pv\_capacity) | Storage capacity provisioned for server persistent volume. | `string` | `"10Gi"` | no |
|
||||
| <a name="input_twentycrm_docker_data_pv_path"></a> [twentycrm\_docker\_data\_pv\_path](#input\_twentycrm\_docker\_data\_pv\_path) | Local path to use to store the physical volume if using local storage on nodes. | `string` | `""` | no |
|
||||
| <a name="input_twentycrm_docker_data_pvc_requests"></a> [twentycrm\_docker\_data\_pvc\_requests](#input\_twentycrm\_docker\_data\_pvc\_requests) | Storage capacity reservation for server persistent volume claim. | `string` | `"10Gi"` | no |
|
||||
| <a name="input_twentycrm_namespace"></a> [twentycrm\_namespace](#input\_twentycrm\_namespace) | Namespace for all TwentyCRM resources | `string` | `"twentycrm"` | no |
|
||||
| <a name="input_twentycrm_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_pv_capacity"></a> [twentycrm\_server\_pv\_capacity](#input\_twentycrm\_server\_pv\_capacity) | Storage capacity provisioned for server persistent volume. | `string` | `"10Gi"` | no |
|
||||
| <a name="input_twentycrm_server_pv_path"></a> [twentycrm\_server\_pv\_path](#input\_twentycrm\_server\_pv\_path) | Local path to use to store the physical volume if using local storage on nodes. | `string` | `""` | no |
|
||||
| <a name="input_twentycrm_server_pvc_requests"></a> [twentycrm\_server\_pvc\_requests](#input\_twentycrm\_server\_pvc\_requests) | Storage capacity reservation for server persistent volume claim. | `string` | `"10Gi"` | no |
|
||||
| <a name="input_twentycrm_server_replicas"></a> [twentycrm\_server\_replicas](#input\_twentycrm\_server\_replicas) | Number of replicas for the TwentyCRM server deployment. This defaults to 1. | `number` | `1` | no |
|
||||
| <a name="input_twentycrm_worker_replicas"></a> [twentycrm\_worker\_replicas](#input\_twentycrm\_worker\_replicas) | Number of replicas for the TwentyCRM worker deployment. This defaults to 1. | `number` | `1` | no |
|
||||
<!-- END_TF_DOCS -->
|
||||
<!-- 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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,44 +37,27 @@ resource "kubernetes_deployment" "twentycrm_server" {
|
||||
stdin = true
|
||||
tty = true
|
||||
|
||||
security_context {
|
||||
allow_privilege_escalation = true
|
||||
privileged = true
|
||||
run_as_user = 1000
|
||||
}
|
||||
|
||||
env {
|
||||
name = "PORT"
|
||||
name = "NODE_PORT"
|
||||
value = "3000"
|
||||
}
|
||||
env {
|
||||
name = "DEBUG_MODE"
|
||||
value = false
|
||||
}
|
||||
|
||||
env {
|
||||
name = "SERVER_URL"
|
||||
value = var.twentycrm_app_hostname
|
||||
}
|
||||
|
||||
env {
|
||||
name = "FRONT_BASE_URL"
|
||||
value = var.twentycrm_app_hostname
|
||||
}
|
||||
|
||||
env {
|
||||
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 {
|
||||
name = "ENABLE_DB_MIGRATIONS"
|
||||
value = "true"
|
||||
name = "REDIS_URL"
|
||||
value = "redis://${kubernetes_service.twentycrm_redis.metadata.0.name}.${kubernetes_namespace.twentycrm.metadata.0.name}.svc.cluster.local:6379"
|
||||
}
|
||||
|
||||
env {
|
||||
name = "SIGN_IN_PREFILLED"
|
||||
value = "true"
|
||||
name = "DISABLE_DB_MIGRATIONS"
|
||||
value = "false"
|
||||
}
|
||||
|
||||
env {
|
||||
@@ -82,11 +65,15 @@ resource "kubernetes_deployment" "twentycrm_server" {
|
||||
value = "local"
|
||||
}
|
||||
env {
|
||||
name = "MESSAGE_QUEUE_TYPE"
|
||||
value = "pg-boss"
|
||||
name = "ACCESS_TOKEN_EXPIRES_IN"
|
||||
value = "7d"
|
||||
}
|
||||
env {
|
||||
name = "ACCESS_TOKEN_SECRET"
|
||||
name = "LOGIN_TOKEN_EXPIRES_IN"
|
||||
value = "1h"
|
||||
}
|
||||
env {
|
||||
name = "APP_SECRET"
|
||||
value_from {
|
||||
secret_key_ref {
|
||||
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 {
|
||||
container_port = 3000
|
||||
protocol = "TCP"
|
||||
@@ -145,6 +102,11 @@ resource "kubernetes_deployment" "twentycrm_server" {
|
||||
name = "server-data"
|
||||
mount_path = var.twentycrm_server_data_mount_path
|
||||
}
|
||||
|
||||
volume_mount {
|
||||
name = "docker-data"
|
||||
mount_path = var.twentycrm_docker_data_mount_path
|
||||
}
|
||||
}
|
||||
|
||||
volume {
|
||||
@@ -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"
|
||||
restart_policy = "Always"
|
||||
}
|
||||
@@ -162,6 +132,7 @@ resource "kubernetes_deployment" "twentycrm_server" {
|
||||
}
|
||||
depends_on = [
|
||||
kubernetes_deployment.twentycrm_db,
|
||||
kubernetes_deployment.twentycrm_redis,
|
||||
kubernetes_secret.twentycrm_tokens
|
||||
]
|
||||
}
|
||||
|
||||
@@ -43,32 +43,28 @@ resource "kubernetes_deployment" "twentycrm_worker" {
|
||||
value = var.twentycrm_app_hostname
|
||||
}
|
||||
|
||||
env {
|
||||
name = "FRONT_BASE_URL"
|
||||
value = var.twentycrm_app_hostname
|
||||
}
|
||||
|
||||
env {
|
||||
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 {
|
||||
name = "ENABLE_DB_MIGRATIONS"
|
||||
value = "false" #it already runs on the server
|
||||
name = "REDIS_URL"
|
||||
value = "redis://${kubernetes_service.twentycrm_redis.metadata.0.name}.${kubernetes_namespace.twentycrm.metadata.0.name}.svc.cluster.local:6379"
|
||||
}
|
||||
|
||||
env {
|
||||
name = "DISABLE_DB_MIGRATIONS"
|
||||
value = "true" #it already runs on the server
|
||||
}
|
||||
|
||||
env {
|
||||
name = "STORAGE_TYPE"
|
||||
value = "local"
|
||||
}
|
||||
env {
|
||||
name = "MESSAGE_QUEUE_TYPE"
|
||||
value = "pg-boss"
|
||||
}
|
||||
|
||||
env {
|
||||
name = "ACCESS_TOKEN_SECRET"
|
||||
name = "APP_SECRET"
|
||||
value_from {
|
||||
secret_key_ref {
|
||||
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 {
|
||||
requests = {
|
||||
cpu = "250m"
|
||||
memory = "256Mi"
|
||||
memory = "1024Mi"
|
||||
}
|
||||
limits = {
|
||||
cpu = "1000m"
|
||||
memory = "1024Mi"
|
||||
memory = "2048Mi"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -126,6 +92,8 @@ resource "kubernetes_deployment" "twentycrm_worker" {
|
||||
}
|
||||
depends_on = [
|
||||
kubernetes_deployment.twentycrm_db,
|
||||
kubernetes_secret.twentycrm_tokens
|
||||
kubernetes_deployment.twentycrm_redis,
|
||||
kubernetes_deployment.twentycrm_server,
|
||||
kubernetes_secret.twentycrm_tokens,
|
||||
]
|
||||
}
|
||||
|
||||
@@ -13,7 +13,11 @@ terraform {
|
||||
required_providers {
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -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" {
|
||||
metadata {
|
||||
name = "tokens"
|
||||
@@ -5,11 +20,9 @@ resource "kubernetes_secret" "twentycrm_tokens" {
|
||||
}
|
||||
|
||||
data = {
|
||||
accessToken = var.twentycrm_token_accessToken
|
||||
loginToken = var.twentycrm_token_loginToken
|
||||
refreshToken = var.twentycrm_token_refreshToken
|
||||
fileToken = var.twentycrm_token_fileToken
|
||||
accessToken = random_bytes.this["accessToken"].base64
|
||||
loginToken = random_bytes.this["loginToken"].base64
|
||||
refreshToken = random_bytes.this["refreshToken"].base64
|
||||
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"
|
||||
}
|
||||
}
|
||||
@@ -1,30 +1,6 @@
|
||||
######################
|
||||
# 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" {
|
||||
type = string
|
||||
description = "TwentyCRM password for postgres database."
|
||||
@@ -53,7 +29,7 @@ variable "twentycrm_server_image" {
|
||||
|
||||
variable "twentycrm_db_image" {
|
||||
type = string
|
||||
default = "twentycrm/twenty-postgres:latest"
|
||||
default = "twentycrm/twenty-postgres-spilo: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" {
|
||||
type = string
|
||||
default = "/app/docker-data"
|
||||
description = "TwentyCRM mount path for servers application data. Defaults to '/app/docker-data'."
|
||||
default = "/app/packages/twenty-server/.local-storage"
|
||||
description = "TwentyCRM mount path for servers application data. Defaults to '/app/packages/twenty-server/.local-storage'."
|
||||
}
|
||||
|
||||
variable "twentycrm_db_pv_path" {
|
||||
@@ -122,3 +98,39 @@ variable "twentycrm_namespace" {
|
||||
default = "twentycrm"
|
||||
description = "Namespace for all TwentyCRM resources"
|
||||
}
|
||||
|
||||
variable "twentycrm_redis_replicas" {
|
||||
type = number
|
||||
default = 1
|
||||
description = "Number of replicas for the TwentyCRM Redis deployment. This defaults to 1."
|
||||
}
|
||||
|
||||
variable "twentycrm_redis_image" {
|
||||
type = string
|
||||
default = "redis/redis-stack-server:latest"
|
||||
description = "TwentyCRM image for Redis deployment. This defaults to latest."
|
||||
}
|
||||
|
||||
variable "twentycrm_docker_data_mount_path" {
|
||||
type = string
|
||||
default = "/app/docker-data"
|
||||
description = "TwentyCRM mount path for servers application data. Defaults to '/app/docker-data'."
|
||||
}
|
||||
|
||||
variable "twentycrm_docker_data_pv_path" {
|
||||
type = string
|
||||
default = ""
|
||||
description = "Local path to use to store the physical volume if using local storage on nodes."
|
||||
}
|
||||
|
||||
variable "twentycrm_docker_data_pv_capacity" {
|
||||
type = string
|
||||
default = "100Mi"
|
||||
description = "Storage capacity provisioned for server persistent volume."
|
||||
}
|
||||
|
||||
variable "twentycrm_docker_data_pvc_requests" {
|
||||
type = string
|
||||
default = "100Mi"
|
||||
description = "Storage capacity reservation for server persistent volume claim."
|
||||
}
|
||||
|
||||
@@ -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]
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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:
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
Executable
+167
@@ -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
|
||||
@@ -1,13 +1,12 @@
|
||||
ARG POSTGRES_VERSION=15
|
||||
ARG SPILO_VERSION=3.2-p1
|
||||
ARG PG_GRAPHQL_VERSION=1.5.6
|
||||
ARG WRAPPERS_VERSION=0.2.0
|
||||
|
||||
# Build the mysql_fdw extension
|
||||
FROM debian:bookworm as build-mysql_fdw
|
||||
FROM debian:bookworm AS build-mysql_fdw
|
||||
ARG POSTGRES_VERSION
|
||||
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
RUN apt update && \
|
||||
apt install -y \
|
||||
build-essential \
|
||||
@@ -18,14 +17,14 @@ RUN apt update && \
|
||||
|
||||
# Install mysql_fdw
|
||||
RUN git clone https://github.com/EnterpriseDB/mysql_fdw.git
|
||||
WORKDIR mysql_fdw
|
||||
WORKDIR /mysql_fdw
|
||||
RUN make USE_PGXS=1
|
||||
|
||||
|
||||
# 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 && \
|
||||
apt install -y \
|
||||
build-essential \
|
||||
@@ -38,10 +37,9 @@ WORKDIR /build/openssl
|
||||
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}
|
||||
ARG POSTGRES_VERSION
|
||||
ARG PG_GRAPHQL_VERSION
|
||||
ARG WRAPPERS_VERSION
|
||||
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/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 --from=build-mysql_fdw /mysql_fdw/mysql_fdw.so \
|
||||
/usr/lib/postgresql/${POSTGRES_VERSION}/lib/mysql_fdw.so
|
||||
|
||||
@@ -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"]
|
||||
@@ -1,4 +0,0 @@
|
||||
CREATE DATABASE "default";
|
||||
CREATE DATABASE "test";
|
||||
CREATE USER twenty PASSWORD 'twenty';
|
||||
ALTER ROLE twenty superuser;
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM node:18.17.1-alpine as twenty-website-build
|
||||
FROM node:22-alpine as twenty-website-build
|
||||
|
||||
|
||||
WORKDIR /app
|
||||
@@ -8,14 +8,22 @@ COPY ./yarn.lock .
|
||||
COPY ./.yarnrc.yml .
|
||||
COPY ./.yarn/releases /app/.yarn/releases
|
||||
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
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
@@ -26,4 +34,9 @@ WORKDIR /app/packages/twenty-website
|
||||
LABEL org.opencontainers.image.source=https://github.com/twentyhq/twenty
|
||||
LABEL org.opencontainers.image.description="This image provides a consistent and reproducible environment for the website."
|
||||
|
||||
RUN chown -R 1000 /app
|
||||
|
||||
# Use non root user with uid 1000
|
||||
USER 1000
|
||||
|
||||
CMD ["/bin/sh", "-c", "npx nx start"]
|
||||
@@ -1,5 +1,5 @@
|
||||
# Base image for common dependencies
|
||||
FROM node:18.17.1-alpine as common-deps
|
||||
FROM node:22-alpine as common-deps
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
@@ -7,10 +7,12 @@ WORKDIR /app
|
||||
COPY ./package.json ./yarn.lock ./.yarnrc.yml ./tsconfig.base.json ./nx.json /app/
|
||||
COPY ./.yarn/releases /app/.yarn/releases
|
||||
|
||||
COPY ./.prettierrc /app/
|
||||
COPY ./packages/twenty-emails/package.json /app/packages/twenty-emails/
|
||||
COPY ./packages/twenty-server/package.json /app/packages/twenty-server/
|
||||
COPY ./packages/twenty-server/patches /app/packages/twenty-server/patches
|
||||
COPY ./packages/twenty-ui/package.json /app/packages/twenty-ui/
|
||||
COPY ./packages/twenty-shared/package.json /app/packages/twenty-shared/
|
||||
COPY ./packages/twenty-front/package.json /app/packages/twenty-front/
|
||||
|
||||
# Install all dependencies
|
||||
@@ -22,6 +24,7 @@ FROM common-deps as twenty-server-build
|
||||
|
||||
# Copy sourcecode after installing dependences to accelerate subsequents builds
|
||||
COPY ./packages/twenty-emails /app/packages/twenty-emails
|
||||
COPY ./packages/twenty-shared /app/packages/twenty-shared
|
||||
COPY ./packages/twenty-server /app/packages/twenty-server
|
||||
|
||||
RUN npx nx run twenty-server:build
|
||||
@@ -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 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
|
||||
@@ -41,24 +44,29 @@ ARG REACT_APP_SERVER_BASE_URL
|
||||
|
||||
COPY ./packages/twenty-front /app/packages/twenty-front
|
||||
COPY ./packages/twenty-ui /app/packages/twenty-ui
|
||||
COPY ./packages/twenty-shared /app/packages/twenty-shared
|
||||
RUN npx nx build twenty-front
|
||||
|
||||
|
||||
# Final stage: Run the application
|
||||
FROM node:18.17.1-alpine as twenty
|
||||
FROM node:22-alpine as twenty
|
||||
|
||||
# Used to run healthcheck in docker
|
||||
RUN apk add --no-cache curl jq
|
||||
|
||||
RUN npm install -g tsx
|
||||
|
||||
RUN apk add --no-cache postgresql-client
|
||||
|
||||
COPY ./packages/twenty-docker/twenty/entrypoint.sh /app/entrypoint.sh
|
||||
RUN chmod +x /app/entrypoint.sh
|
||||
|
||||
WORKDIR /app/packages/twenty-server
|
||||
|
||||
ARG REACT_APP_SERVER_BASE_URL
|
||||
ENV REACT_APP_SERVER_BASE_URL $REACT_APP_SERVER_BASE_URL
|
||||
ARG SENTRY_RELEASE
|
||||
ENV SENTRY_RELEASE $SENTRY_RELEASE
|
||||
|
||||
ARG APP_VERSION
|
||||
ENV APP_VERSION $APP_VERSION
|
||||
|
||||
# Copy built applications from previous stages
|
||||
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.description="This image provides a consistent and reproducible environment for the backend and frontend, ensuring it deploys faster and runs the same way regardless of the deployment environment."
|
||||
|
||||
RUN mkdir /app/.local-storage
|
||||
RUN chown -R 1000 /app
|
||||
RUN mkdir -p /app/.local-storage /app/packages/twenty-server/.local-storage && \
|
||||
chown -R 1000:1000 /app
|
||||
|
||||
# Use non root user with uid 1000
|
||||
USER 1000
|
||||
|
||||
@@ -1,17 +1,50 @@
|
||||
#!/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..."
|
||||
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
|
||||
NODE_OPTIONS="--max-old-space-size=1500" npx ts-node ./scripts/setup-db.ts
|
||||
yarn database:migrate:prod
|
||||
# Creating the database if it doesn't exist
|
||||
db_count=$(PGPASSWORD=${PGPASS} psql -h ${PGHOST} -p ${PGPORT} -U ${PGUSER} -d postgres -tAc "SELECT COUNT(*) FROM pg_database WHERE datname = '${PGDATABASE}'")
|
||||
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
|
||||
echo "Successfuly migrated DB!"
|
||||
touch /app/docker-data/db_status
|
||||
fi
|
||||
# Run setup and migration scripts
|
||||
NODE_OPTIONS="--max-old-space-size=1500" tsx ./scripts/setup-db.ts
|
||||
yarn database:migrate:prod
|
||||
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
|
||||
exec "$@"
|
||||
|
||||
@@ -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"
|
||||
);
|
||||
@@ -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(`--------------------------------`);
|
||||
}
|
||||
@@ -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,
|
||||
};
|
||||
Reference in New Issue
Block a user