diff --git a/app/pnpm-workspace.yaml b/app/pnpm-workspace.yaml
new file mode 100644
index 00000000..c4ec45c0
--- /dev/null
+++ b/app/pnpm-workspace.yaml
@@ -0,0 +1,4 @@
+packages:
+ - .
+allowBuilds:
+ esbuild: false
diff --git a/app/src/components/Navigation.tsx b/app/src/components/Navigation.tsx
index 47639224..adba7dd7 100644
--- a/app/src/components/Navigation.tsx
+++ b/app/src/components/Navigation.tsx
@@ -13,7 +13,9 @@ const Navigation = () => {
"https://api.github.com/repos/dokploy/dokploy"
);
const data = await response.json();
- setGithubStars(data.stargazers_count);
+ setGithubStars(
+ Number.isFinite(data.stargazers_count) ? data.stargazers_count : 0
+ );
} catch (error) {
console.error("Error fetching GitHub stars:", error);
}
diff --git a/blueprints/agent-zero/agent-zero.svg b/blueprints/agent-zero/agent-zero.svg
new file mode 100644
index 00000000..1d2aea94
--- /dev/null
+++ b/blueprints/agent-zero/agent-zero.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/blueprints/agent-zero/docker-compose.yml b/blueprints/agent-zero/docker-compose.yml
new file mode 100644
index 00000000..fceed3cf
--- /dev/null
+++ b/blueprints/agent-zero/docker-compose.yml
@@ -0,0 +1,14 @@
+version: "3.8"
+services:
+ agent-zero:
+ image: agent0ai/agent-zero:v1.9
+ restart: unless-stopped
+ expose:
+ - "80"
+ environment:
+ - AUTH_LOGIN=${AUTH_LOGIN}
+ - AUTH_PASSWORD=${AUTH_PASSWORD}
+ volumes:
+ - agent-zero-data:/a0/usr
+volumes:
+ agent-zero-data:
\ No newline at end of file
diff --git a/blueprints/agent-zero/template.toml b/blueprints/agent-zero/template.toml
new file mode 100644
index 00000000..bb84517b
--- /dev/null
+++ b/blueprints/agent-zero/template.toml
@@ -0,0 +1,16 @@
+[variables]
+main_domain = "${domain}"
+auth_login = "${username}"
+auth_password = "${password:32}"
+
+[config]
+env = [
+ "AUTH_LOGIN=${auth_login}",
+ "AUTH_PASSWORD=${auth_password}",
+]
+mounts = []
+
+[[config.domains]]
+serviceName = "agent-zero"
+port = 80
+host = "${main_domain}"
\ No newline at end of file
diff --git a/blueprints/appwrite/docker-compose.yml b/blueprints/appwrite/docker-compose.yml
index cb622284..2da23f52 100644
--- a/blueprints/appwrite/docker-compose.yml
+++ b/blueprints/appwrite/docker-compose.yml
@@ -8,12 +8,34 @@ x-logging: &x-logging
max-size: "10m"
services:
appwrite:
- image: appwrite/appwrite:1.8.0
+ image: appwrite/appwrite:1.9.5
<<: *x-logging
restart: unless-stopped
labels:
- traefik.enable=true
- traefik.constraint-label-stack=appwrite
+ - 'traefik.http.routers.appwrite-sites-wildcard.rule=HostRegexp(`^.+\.${_APP_DOMAIN_SITES}$$`)'
+ - traefik.http.routers.appwrite-sites-wildcard.entrypoints=web
+ - traefik.http.routers.appwrite-sites-wildcard.service=appwrite-wildcard
+ - 'traefik.http.routers.appwrite-sites-wildcard-secure.rule=HostRegexp(`^.+\.${_APP_DOMAIN_SITES}$$`)'
+ - traefik.http.routers.appwrite-sites-wildcard-secure.entrypoints=websecure
+ - traefik.http.routers.appwrite-sites-wildcard-secure.tls=true
+ - traefik.http.routers.appwrite-sites-wildcard-secure.service=appwrite-wildcard
+ - 'traefik.http.routers.appwrite-functions-wildcard.rule=HostRegexp(`^.+\.${_APP_DOMAIN_FUNCTIONS}$$`)'
+ - traefik.http.routers.appwrite-functions-wildcard.entrypoints=web
+ - traefik.http.routers.appwrite-functions-wildcard.service=appwrite-wildcard
+ - 'traefik.http.routers.appwrite-functions-wildcard-secure.rule=HostRegexp(`^.+\.${_APP_DOMAIN_FUNCTIONS}$$`)'
+ - traefik.http.routers.appwrite-functions-wildcard-secure.entrypoints=websecure
+ - traefik.http.routers.appwrite-functions-wildcard-secure.tls=true
+ - traefik.http.routers.appwrite-functions-wildcard-secure.service=appwrite-wildcard
+ - traefik.http.services.appwrite-wildcard.loadbalancer.server.port=80
+ healthcheck:
+ test:
+ - CMD
+ - doctor
+ interval: 5s
+ timeout: 5s
+ retries: 12
volumes:
- appwrite-uploads:/storage/uploads:rw
- appwrite-imports:/storage/imports:rw
@@ -24,21 +46,25 @@ services:
- appwrite-sites:/storage/sites:rw
- appwrite-builds:/storage/builds:rw
depends_on:
- - mariadb
- redis
- # - clamav
+ - ${_APP_DB_HOST:-mongodb}
environment:
- _APP_ENV
+ - _APP_EDITION
- _APP_WORKER_PER_CORE
+ - _APP_POOL_ADAPTER
- _APP_LOCALE
+ - _APP_COMPRESSION_ENABLED
- _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_CONSOLE_SCHEMA
- _APP_SYSTEM_EMAIL_NAME
- _APP_SYSTEM_EMAIL_ADDRESS
+ - _APP_SYSTEM_TEAM_EMAIL
- _APP_EMAIL_SECURITY
- _APP_SYSTEM_RESPONSE_FORMAT
- _APP_OPTIONS_ABUSE
@@ -47,6 +73,8 @@ services:
- _APP_OPTIONS_ROUTER_FORCE_HTTPS
- _APP_OPENSSL_KEY_V1
- _APP_DOMAIN
+ - _APP_CONSOLE_DOMAIN
+ - _APP_CONSOLE_TRUSTED_PROJECTS
- _APP_DOMAIN_TARGET_CNAME
- _APP_DOMAIN_TARGET_AAAA
- _APP_DOMAIN_TARGET_A
@@ -57,11 +85,18 @@ services:
- _APP_REDIS_PORT
- _APP_REDIS_USER
- _APP_REDIS_PASS
+ - _APP_DB_ADAPTER
- _APP_DB_HOST
- _APP_DB_PORT
- _APP_DB_SCHEMA
- _APP_DB_USER
- _APP_DB_PASS
+ - _APP_DB_ADAPTER_VECTORSDB
+ - _APP_DB_HOST_VECTORSDB
+ - _APP_DB_PORT_VECTORSDB
+ - _APP_DB_SCHEMA_VECTORSDB
+ - _APP_DB_USER_VECTORSDB
+ - _APP_DB_PASS_VECTORSDB
- _APP_SMTP_HOST
- _APP_SMTP_PORT
- _APP_SMTP_SECURE
@@ -108,8 +143,6 @@ services:
- _APP_EXECUTOR_HOST
- _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
@@ -119,6 +152,7 @@ services:
- _APP_MAINTENANCE_RETENTION_SCHEDULES
- _APP_SMS_PROVIDER
- _APP_SMS_FROM
+ - _APP_GRAPHQL_INTROSPECTION
- _APP_GRAPHQL_MAX_BATCH_SIZE
- _APP_GRAPHQL_MAX_COMPLEXITY
- _APP_GRAPHQL_MAX_DEPTH
@@ -131,16 +165,26 @@ services:
- _APP_MIGRATIONS_FIREBASE_CLIENT_ID
- _APP_MIGRATIONS_FIREBASE_CLIENT_SECRET
- _APP_ASSISTANT_OPENAI_API_KEY
+ - _APP_CONSOLE_COUNTRIES_DENYLIST
+ - _APP_EXPERIMENT_LOGGING_PROVIDER
+ - _APP_EXPERIMENT_LOGGING_CONFIG
+ - _APP_DATABASE_SHARED_TABLES
+ - _APP_DATABASE_SHARED_NAMESPACE
+ - _APP_FUNCTIONS_CREATION_ABUSE_LIMIT
+ - _APP_CUSTOM_DOMAIN_DENY_LIST
+ - _APP_TRUSTED_HEADERS
+ - _APP_MIGRATION_HOST
+
appwrite-console:
<<: *x-logging
- image: appwrite/console:7.4.7
+ image: appwrite/console:8.7.5
restart: unless-stopped
labels:
- "traefik.enable=true"
- "traefik.constraint-label-stack=appwrite"
appwrite-realtime:
- image: appwrite/appwrite:1.8.0
+ image: appwrite/appwrite:1.9.5
entrypoint: realtime
<<: *x-logging
restart: unless-stopped
@@ -148,7 +192,7 @@ services:
- "traefik.enable=true"
- "traefik.constraint-label-stack=appwrite"
depends_on:
- - mariadb
+ - ${_APP_DB_HOST:-mongodb}
- redis
environment:
- _APP_ENV
@@ -160,51 +204,69 @@ services:
- _APP_REDIS_PORT
- _APP_REDIS_USER
- _APP_REDIS_PASS
+ - _APP_DB_ADAPTER
- _APP_DB_HOST
- _APP_DB_PORT
- _APP_DB_SCHEMA
- _APP_DB_USER
- _APP_DB_PASS
+ - _APP_DB_ADAPTER_VECTORSDB
+ - _APP_DB_HOST_VECTORSDB
+ - _APP_DB_PORT_VECTORSDB
+ - _APP_DB_SCHEMA_VECTORSDB
+ - _APP_DB_USER_VECTORSDB
+ - _APP_DB_PASS_VECTORSDB
- _APP_USAGE_STATS
- _APP_LOGGING_CONFIG
+ - _APP_LOGGING_CONFIG_REALTIME
+ - _APP_DATABASE_SHARED_TABLES
+ - _APP_POOL_ADAPTER=swoole
appwrite-worker-audits:
- image: appwrite/appwrite:1.8.0
+ image: appwrite/appwrite:1.9.5
entrypoint: worker-audits
<<: *x-logging
restart: unless-stopped
depends_on:
- redis
- - mariadb
+ - ${_APP_DB_HOST:-mongodb}
environment:
- _APP_ENV
+ - _APP_WORKERS_NUM=1
+ - _APP_WORKER_MAX_COROUTINES=1
- _APP_WORKER_PER_CORE
+ - _APP_POOL_ADAPTER
- _APP_OPENSSL_KEY_V1
- _APP_REDIS_HOST
- _APP_REDIS_PORT
- _APP_REDIS_USER
- _APP_REDIS_PASS
+ - _APP_DB_ADAPTER
- _APP_DB_HOST
- _APP_DB_PORT
- _APP_DB_SCHEMA
- _APP_DB_USER
- _APP_DB_PASS
- _APP_LOGGING_CONFIG
+ - _APP_DATABASE_SHARED_TABLES
appwrite-worker-webhooks:
- image: appwrite/appwrite:1.8.0
+ image: appwrite/appwrite:1.9.5
entrypoint: worker-webhooks
<<: *x-logging
restart: unless-stopped
depends_on:
- redis
- - mariadb
+ - ${_APP_DB_HOST:-mongodb}
environment:
- _APP_ENV
+ - _APP_WORKERS_NUM=1
+ - _APP_WORKER_MAX_COROUTINES=8
- _APP_WORKER_PER_CORE
+ - _APP_POOL_ADAPTER
- _APP_OPENSSL_KEY_V1
- _APP_EMAIL_SECURITY
- - _APP_SYSTEM_SECURITY_EMAIL_ADDRESS
+ - _APP_DB_ADAPTER
- _APP_DB_HOST
- _APP_DB_PORT
- _APP_DB_SCHEMA
@@ -215,15 +277,17 @@ services:
- _APP_REDIS_USER
- _APP_REDIS_PASS
- _APP_LOGGING_CONFIG
+ - _APP_WEBHOOK_MAX_FAILED_ATTEMPTS
+ - _APP_DATABASE_SHARED_TABLES
appwrite-worker-deletes:
- image: appwrite/appwrite:1.8.0
+ image: appwrite/appwrite:1.9.5
entrypoint: worker-deletes
<<: *x-logging
restart: unless-stopped
depends_on:
- redis
- - mariadb
+ - ${_APP_DB_HOST:-mongodb}
volumes:
- appwrite-uploads:/storage/uploads:rw
- appwrite-cache:/storage/cache:rw
@@ -233,12 +297,16 @@ services:
- appwrite-certificates:/storage/certificates:rw
environment:
- _APP_ENV
+ - _APP_WORKERS_NUM=1
+ - _APP_WORKER_MAX_COROUTINES=8
- _APP_WORKER_PER_CORE
+ - _APP_POOL_ADAPTER
- _APP_OPENSSL_KEY_V1
- _APP_REDIS_HOST
- _APP_REDIS_PORT
- _APP_REDIS_USER
- _APP_REDIS_PASS
+ - _APP_DB_ADAPTER
- _APP_DB_HOST
- _APP_DB_PORT
- _APP_DB_SCHEMA
@@ -269,52 +337,64 @@ services:
- _APP_LOGGING_CONFIG
- _APP_EXECUTOR_SECRET
- _APP_EXECUTOR_HOST
- - _APP_MAINTENANCE_RETENTION_ABUSE
+ - _APP_DATABASE_SHARED_TABLES
+ - _APP_EMAIL_CERTIFICATES
- _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.8.0
+ image: appwrite/appwrite:1.9.5
entrypoint: worker-databases
<<: *x-logging
restart: unless-stopped
depends_on:
- redis
- - mariadb
+ - ${_APP_DB_HOST:-mongodb}
environment:
- _APP_ENV
+ - _APP_WORKERS_NUM=1
+ - _APP_WORKER_MAX_COROUTINES=1
- _APP_WORKER_PER_CORE
+ - _APP_POOL_ADAPTER
- _APP_OPENSSL_KEY_V1
- _APP_REDIS_HOST
- _APP_REDIS_PORT
- _APP_REDIS_USER
- _APP_REDIS_PASS
+ - _APP_DB_ADAPTER
- _APP_DB_HOST
- _APP_DB_PORT
- _APP_DB_SCHEMA
- _APP_DB_USER
- _APP_DB_PASS
+ - _APP_DB_ADAPTER_VECTORSDB
+ - _APP_DB_HOST_VECTORSDB
+ - _APP_DB_PORT_VECTORSDB
+ - _APP_DB_SCHEMA_VECTORSDB
+ - _APP_DB_USER_VECTORSDB
+ - _APP_DB_PASS_VECTORSDB
- _APP_LOGGING_CONFIG
+ - _APP_QUEUE_NAME
+ - _APP_DATABASE_SHARED_TABLES
appwrite-worker-builds:
- image: appwrite/appwrite:1.8.0
+ image: appwrite/appwrite:1.9.5
entrypoint: worker-builds
<<: *x-logging
restart: unless-stopped
depends_on:
- redis
- - mariadb
+ - ${_APP_DB_HOST:-mongodb}
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_WORKERS_NUM=1
+ - _APP_WORKER_MAX_COROUTINES=8
- _APP_WORKER_PER_CORE
+ - _APP_POOL_ADAPTER
- _APP_OPENSSL_KEY_V1
- _APP_EXECUTOR_SECRET
- _APP_EXECUTOR_HOST
@@ -322,6 +402,7 @@ services:
- _APP_REDIS_PORT
- _APP_REDIS_USER
- _APP_REDIS_PASS
+ - _APP_DB_ADAPTER
- _APP_DB_HOST
- _APP_DB_PORT
- _APP_DB_SCHEMA
@@ -336,10 +417,13 @@ services:
- _APP_COMPUTE_BUILD_TIMEOUT
- _APP_COMPUTE_CPUS
- _APP_COMPUTE_MEMORY
+ - _APP_OPEN_RUNTIMES_NFT
- _APP_COMPUTE_SIZE_LIMIT
- _APP_OPTIONS_FORCE_HTTPS
- _APP_OPTIONS_ROUTER_FORCE_HTTPS
- _APP_DOMAIN
+ - _APP_CONSOLE_DOMAIN
+ - _APP_CONSOLE_TRUSTED_PROJECTS
- _APP_STORAGE_DEVICE
- _APP_STORAGE_S3_ACCESS_KEY
- _APP_STORAGE_S3_SECRET
@@ -362,22 +446,85 @@ services:
- _APP_STORAGE_WASABI_SECRET
- _APP_STORAGE_WASABI_REGION
- _APP_STORAGE_WASABI_BUCKET
+ - _APP_DATABASE_SHARED_TABLES
- _APP_DOMAIN_SITES
+ extra_hosts:
+ - host.docker.internal:host-gateway
+
+ appwrite-worker-screenshots:
+ image: appwrite/appwrite:1.9.5
+ entrypoint: worker-screenshots
+ <<: *x-logging
+ restart: unless-stopped
+ depends_on:
+ - redis
+ - ${_APP_DB_HOST:-mongodb}
+ volumes:
+ - appwrite-uploads:/storage/uploads:rw
+ environment:
+ - _APP_BROWSER_HOST
+ - _APP_WORKER_SCREENSHOTS_ROUTER
+ - _APP_OPTIONS_FORCE_HTTPS
+ - _APP_ENV
+ - _APP_WORKERS_NUM=1
+ - _APP_WORKER_MAX_COROUTINES=8
+ - _APP_WORKER_PER_CORE
+ - _APP_POOL_ADAPTER
+ - _APP_LOGGING_CONFIG
+ - _APP_OPENSSL_KEY_V1
+ - _APP_REDIS_HOST
+ - _APP_REDIS_PORT
+ - _APP_REDIS_USER
+ - _APP_REDIS_PASS
+ - _APP_DB_ADAPTER
+ - _APP_DB_HOST
+ - _APP_DB_PORT
+ - _APP_DB_SCHEMA
+ - _APP_DB_USER
+ - _APP_DB_PASS
+ - _APP_DATABASE_SHARED_TABLES
+ - _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
+ - _APP_STORAGE_DO_SPACES_BUCKET
+ - _APP_STORAGE_BACKBLAZE_ACCESS_KEY
+ - _APP_STORAGE_BACKBLAZE_SECRET
+ - _APP_STORAGE_BACKBLAZE_REGION
+ - _APP_STORAGE_BACKBLAZE_BUCKET
+ - _APP_STORAGE_LINODE_ACCESS_KEY
+ - _APP_STORAGE_LINODE_SECRET
+ - _APP_STORAGE_LINODE_REGION
+ - _APP_STORAGE_LINODE_BUCKET
+ - _APP_STORAGE_WASABI_ACCESS_KEY
+ - _APP_STORAGE_WASABI_SECRET
+ - _APP_STORAGE_WASABI_REGION
+ - _APP_STORAGE_WASABI_BUCKET
+ extra_hosts:
+ - host.docker.internal:host-gateway
appwrite-worker-certificates:
- image: appwrite/appwrite:1.8.0
+ image: appwrite/appwrite:1.9.5
entrypoint: worker-certificates
<<: *x-logging
restart: unless-stopped
depends_on:
- redis
- - mariadb
+ - ${_APP_DB_HOST:-mongodb}
volumes:
- appwrite-config:/storage/config:rw
- appwrite-certificates:/storage/certificates:rw
environment:
- _APP_ENV
+ - _APP_WORKERS_NUM=1
+ - _APP_WORKER_MAX_COROUTINES=8
- _APP_WORKER_PER_CORE
+ - _APP_POOL_ADAPTER
- _APP_OPENSSL_KEY_V1
- _APP_DOMAIN
- _APP_DOMAIN_TARGET_CNAME
@@ -386,30 +533,64 @@ services:
- _APP_DOMAIN_TARGET_CAA
- _APP_DNS
- _APP_DOMAIN_FUNCTIONS
+ - _APP_DOMAIN_SITES
- _APP_EMAIL_CERTIFICATES
- _APP_REDIS_HOST
- _APP_REDIS_PORT
- _APP_REDIS_USER
- _APP_REDIS_PASS
+ - _APP_DB_ADAPTER
- _APP_DB_HOST
- _APP_DB_PORT
- _APP_DB_SCHEMA
- _APP_DB_USER
- _APP_DB_PASS
- _APP_LOGGING_CONFIG
+ - _APP_DATABASE_SHARED_TABLES
- appwrite-worker-functions:
- image: appwrite/appwrite:1.8.0
- entrypoint: worker-functions
+ appwrite-worker-executions:
+ image: appwrite/appwrite:1.9.5
+ entrypoint: worker-executions
<<: *x-logging
restart: unless-stopped
depends_on:
- redis
- - mariadb
+ - ${_APP_DB_HOST:-mongodb}
+ environment:
+ - _APP_ENV
+ - _APP_WORKERS_NUM=1
+ - _APP_WORKER_MAX_COROUTINES=8
+ - _APP_WORKER_PER_CORE
+ - _APP_POOL_ADAPTER
+ - _APP_OPENSSL_KEY_V1
+ - _APP_REDIS_HOST
+ - _APP_REDIS_PORT
+ - _APP_REDIS_USER
+ - _APP_REDIS_PASS
+ - _APP_DB_ADAPTER
+ - _APP_DB_HOST
+ - _APP_DB_PORT
+ - _APP_DB_SCHEMA
+ - _APP_DB_USER
+ - _APP_DB_PASS
+ - _APP_LOGGING_CONFIG
+ - _APP_DATABASE_SHARED_TABLES
+
+ appwrite-worker-functions:
+ image: appwrite/appwrite:1.9.5
+ entrypoint: worker-functions
+ <<: *x-logging
+ restart: unless-stopped
+ depends_on:
+ - ${_APP_DB_HOST:-mongodb}
+ - redis
- openruntimes-executor
environment:
- _APP_ENV
+ - _APP_WORKERS_NUM=1
+ - _APP_WORKER_MAX_COROUTINES=8
- _APP_WORKER_PER_CORE
+ - _APP_POOL_ADAPTER
- _APP_OPENSSL_KEY_V1
- _APP_DOMAIN
- _APP_OPTIONS_FORCE_HTTPS
@@ -417,6 +598,7 @@ services:
- _APP_REDIS_PORT
- _APP_REDIS_USER
- _APP_REDIS_PASS
+ - _APP_DB_ADAPTER
- _APP_DB_HOST
- _APP_DB_PORT
- _APP_DB_SCHEMA
@@ -433,9 +615,11 @@ services:
- _APP_DOCKER_HUB_USERNAME
- _APP_DOCKER_HUB_PASSWORD
- _APP_LOGGING_CONFIG
+ - _APP_LOGGING_PROVIDER
+ - _APP_DATABASE_SHARED_TABLES
appwrite-worker-mails:
- image: appwrite/appwrite:1.8.0
+ image: appwrite/appwrite:1.9.5
entrypoint: worker-mails
<<: *x-logging
restart: unless-stopped
@@ -443,19 +627,23 @@ services:
- redis
environment:
- _APP_ENV
+ - _APP_WORKERS_NUM=1
+ - _APP_WORKER_MAX_COROUTINES=1
- _APP_WORKER_PER_CORE
+ - _APP_POOL_ADAPTER
- _APP_OPENSSL_KEY_V1
- _APP_SYSTEM_EMAIL_NAME
- _APP_SYSTEM_EMAIL_ADDRESS
+ - _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
- - _APP_REDIS_HOST
- - _APP_REDIS_PORT
- - _APP_REDIS_USER
- - _APP_REDIS_PASS
+ - _APP_DB_ADAPTER
- _APP_SMTP_HOST
- _APP_SMTP_PORT
- _APP_SMTP_SECURE
@@ -464,9 +652,10 @@ services:
- _APP_LOGGING_CONFIG
- _APP_DOMAIN
- _APP_OPTIONS_FORCE_HTTPS
+ - _APP_DATABASE_SHARED_TABLES
appwrite-worker-messaging:
- image: appwrite/appwrite:1.8.0
+ image: appwrite/appwrite:1.9.5
entrypoint: worker-messaging
<<: *x-logging
restart: unless-stopped
@@ -476,12 +665,16 @@ services:
- redis
environment:
- _APP_ENV
+ - _APP_WORKERS_NUM=1
+ - _APP_WORKER_MAX_COROUTINES=1
- _APP_WORKER_PER_CORE
+ - _APP_POOL_ADAPTER
- _APP_OPENSSL_KEY_V1
- _APP_REDIS_HOST
- _APP_REDIS_PORT
- _APP_REDIS_USER
- _APP_REDIS_PASS
+ - _APP_DB_ADAPTER
- _APP_DB_HOST
- _APP_DB_PORT
- _APP_DB_SCHEMA
@@ -490,6 +683,7 @@ services:
- _APP_LOGGING_CONFIG
- _APP_SMS_FROM
- _APP_SMS_PROVIDER
+ - _APP_SMS_PROJECTS_DENY_LIST
- _APP_STORAGE_DEVICE
- _APP_STORAGE_S3_ACCESS_KEY
- _APP_STORAGE_S3_SECRET
@@ -512,19 +706,24 @@ services:
- _APP_STORAGE_WASABI_SECRET
- _APP_STORAGE_WASABI_REGION
- _APP_STORAGE_WASABI_BUCKET
+ - _APP_DATABASE_SHARED_TABLES
appwrite-worker-migrations:
- image: appwrite/appwrite:1.8.0
+ image: appwrite/appwrite:1.9.5
entrypoint: worker-migrations
<<: *x-logging
restart: unless-stopped
volumes:
- appwrite-imports:/storage/imports:rw
+ - appwrite-uploads:/storage/uploads:rw
depends_on:
- - mariadb
+ - ${_APP_DB_HOST:-mongodb}
environment:
- _APP_ENV
+ - _APP_WORKERS_NUM=1
+ - _APP_WORKER_MAX_COROUTINES=1
- _APP_WORKER_PER_CORE
+ - _APP_POOL_ADAPTER
- _APP_OPENSSL_KEY_V1
- _APP_DOMAIN
- _APP_DOMAIN_TARGET_CNAME
@@ -537,6 +736,7 @@ services:
- _APP_REDIS_PORT
- _APP_REDIS_USER
- _APP_REDIS_PASS
+ - _APP_DB_ADAPTER
- _APP_DB_HOST
- _APP_DB_PORT
- _APP_DB_SCHEMA
@@ -545,17 +745,22 @@ services:
- _APP_LOGGING_CONFIG
- _APP_MIGRATIONS_FIREBASE_CLIENT_ID
- _APP_MIGRATIONS_FIREBASE_CLIENT_SECRET
+ - _APP_DATABASE_SHARED_TABLES
+ - _APP_OPTIONS_FORCE_HTTPS
+ - _APP_MIGRATION_HOST
appwrite-task-maintenance:
- image: appwrite/appwrite:1.8.0
+ image: appwrite/appwrite:1.9.5
entrypoint: maintenance
<<: *x-logging
restart: unless-stopped
depends_on:
+ - ${_APP_DB_HOST:-mongodb}
- redis
environment:
- _APP_ENV
- _APP_WORKER_PER_CORE
+ - _APP_POOL_ADAPTER
- _APP_DOMAIN
- _APP_DOMAIN_TARGET_CNAME
- _APP_DOMAIN_TARGET_AAAA
@@ -568,6 +773,7 @@ services:
- _APP_REDIS_PORT
- _APP_REDIS_USER
- _APP_REDIS_PASS
+ - _APP_DB_ADAPTER
- _APP_DB_HOST
- _APP_DB_PORT
- _APP_DB_SCHEMA
@@ -581,19 +787,58 @@ services:
- _APP_MAINTENANCE_RETENTION_AUDIT_CONSOLE
- _APP_MAINTENANCE_RETENTION_USAGE_HOURLY
- _APP_MAINTENANCE_RETENTION_SCHEDULES
+ - _APP_MAINTENANCE_START_TIME
+ - _APP_DATABASE_SHARED_TABLES
+
+ appwrite-task-interval:
+ image: appwrite/appwrite:1.9.5
+ entrypoint: interval
+ <<: *x-logging
+ restart: unless-stopped
+ depends_on:
+ - ${_APP_DB_HOST:-mongodb}
+ - redis
+ environment:
+ - _APP_ENV
+ - _APP_WORKER_PER_CORE
+ - _APP_POOL_ADAPTER
+ - _APP_DOMAIN
+ - _APP_DOMAIN_TARGET_CNAME
+ - _APP_DOMAIN_TARGET_AAAA
+ - _APP_DOMAIN_TARGET_A
+ - _APP_DOMAIN_TARGET_CAA
+ - _APP_DNS
+ - _APP_DOMAIN_FUNCTIONS
+ - _APP_DOMAIN_SITES
+ - _APP_OPENSSL_KEY_V1
+ - _APP_REDIS_HOST
+ - _APP_REDIS_PORT
+ - _APP_REDIS_USER
+ - _APP_REDIS_PASS
+ - _APP_DB_ADAPTER
+ - _APP_DB_HOST
+ - _APP_DB_PORT
+ - _APP_DB_SCHEMA
+ - _APP_DB_USER
+ - _APP_DB_PASS
+ - _APP_DATABASE_SHARED_TABLES
+ - _APP_INTERVAL_DOMAIN_VERIFICATION
+ - _APP_INTERVAL_CLEANUP_STALE_EXECUTIONS
appwrite-task-stats-resources:
- image: appwrite/appwrite:1.8.0
+ image: appwrite/appwrite:1.9.5
entrypoint: stats-resources
<<: *x-logging
restart: unless-stopped
depends_on:
- redis
- - mariadb
+ - ${_APP_DB_HOST:-mongodb}
environment:
- _APP_ENV
- _APP_WORKER_PER_CORE
+ - _APP_POOL_ADAPTER
- _APP_OPENSSL_KEY_V1
+ - _APP_DB_ADAPTER
- _APP_DB_HOST
- _APP_DB_PORT
- _APP_DB_SCHEMA
@@ -609,42 +854,21 @@ services:
- _APP_STATS_RESOURCES_INTERVAL
appwrite-worker-stats-resources:
- image: appwrite/appwrite:1.8.0
+ image: appwrite/appwrite:1.9.5
entrypoint: worker-stats-resources
<<: *x-logging
restart: unless-stopped
depends_on:
- redis
- - mariadb
- environment:
- - _APP_ENV
- - _APP_WORKER_PER_CORE
- - _APP_OPENSSL_KEY_V1
- - _APP_DB_HOST
- - _APP_DB_PORT
- - _APP_DB_SCHEMA
- - _APP_DB_USER
- - _APP_DB_PASS
- - _APP_REDIS_HOST
- - _APP_REDIS_PORT
- - _APP_REDIS_USER
- - _APP_REDIS_PASS
- - _APP_USAGE_STATS
- - _APP_LOGGING_CONFIG
- - _APP_STATS_RESOURCES_INTERVAL
-
- appwrite-worker-stats-usage:
- image: appwrite/appwrite:1.8.0
- entrypoint: worker-stats-usage
- <<: *x-logging
- restart: unless-stopped
- depends_on:
- - redis
- - mariadb
+ - ${_APP_DB_HOST:-mongodb}
environment:
- _APP_ENV
+ - _APP_WORKERS_NUM=1
+ - _APP_WORKER_MAX_COROUTINES=1
- _APP_WORKER_PER_CORE
+ - _APP_POOL_ADAPTER
- _APP_OPENSSL_KEY_V1
+ - _APP_DB_ADAPTER
- _APP_DB_HOST
- _APP_DB_PORT
- _APP_DB_SCHEMA
@@ -657,91 +881,145 @@ services:
- _APP_USAGE_STATS
- _APP_LOGGING_CONFIG
- _APP_USAGE_AGGREGATION_INTERVAL
+ - _APP_DATABASE_SHARED_TABLES
+
+ appwrite-worker-stats-usage:
+ image: appwrite/appwrite:1.9.5
+ entrypoint: worker-stats-usage
+ <<: *x-logging
+ restart: unless-stopped
+ depends_on:
+ - redis
+ - ${_APP_DB_HOST:-mongodb}
+ environment:
+ - _APP_ENV
+ - _APP_WORKERS_NUM=1
+ - _APP_WORKER_MAX_COROUTINES=1
+ - _APP_WORKER_PER_CORE
+ - _APP_POOL_ADAPTER
+ - _APP_OPENSSL_KEY_V1
+ - _APP_DB_ADAPTER
+ - _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_USAGE_AGGREGATION_INTERVAL
+ - _APP_DATABASE_SHARED_TABLES
appwrite-task-scheduler-functions:
- image: appwrite/appwrite:1.8.0
+ image: appwrite/appwrite:1.9.5
entrypoint: schedule-functions
<<: *x-logging
restart: unless-stopped
depends_on:
- - mariadb
+ - ${_APP_DB_HOST:-mongodb}
- redis
environment:
- _APP_ENV
- _APP_WORKER_PER_CORE
+ - _APP_POOL_ADAPTER
- _APP_OPENSSL_KEY_V1
+ - _APP_OPTIONS_FORCE_HTTPS
+ - _APP_DOMAIN
+ - _APP_CONSOLE_DOMAIN
+ - _APP_DOMAIN_FUNCTIONS
+ - _APP_DOMAIN_SITES
+ - _APP_MIGRATION_HOST
+ - _APP_CONSOLE_SCHEMA
- _APP_REDIS_HOST
- _APP_REDIS_PORT
- _APP_REDIS_USER
- _APP_REDIS_PASS
+ - _APP_DB_ADAPTER
- _APP_DB_HOST
- _APP_DB_PORT
- _APP_DB_SCHEMA
- _APP_DB_USER
- _APP_DB_PASS
+ - _APP_DATABASE_SHARED_TABLES
appwrite-task-scheduler-executions:
- image: appwrite/appwrite:1.8.0
+ image: appwrite/appwrite:1.9.5
entrypoint: schedule-executions
<<: *x-logging
restart: unless-stopped
depends_on:
- - mariadb
+ - ${_APP_DB_HOST:-mongodb}
- redis
environment:
- _APP_ENV
- _APP_WORKER_PER_CORE
+ - _APP_POOL_ADAPTER
- _APP_OPENSSL_KEY_V1
+ - _APP_OPTIONS_FORCE_HTTPS
+ - _APP_DOMAIN
+ - _APP_CONSOLE_DOMAIN
+ - _APP_DOMAIN_FUNCTIONS
+ - _APP_DOMAIN_SITES
+ - _APP_MIGRATION_HOST
+ - _APP_CONSOLE_SCHEMA
- _APP_REDIS_HOST
- _APP_REDIS_PORT
- _APP_REDIS_USER
- _APP_REDIS_PASS
+ - _APP_DB_ADAPTER
- _APP_DB_HOST
- _APP_DB_PORT
- _APP_DB_SCHEMA
- _APP_DB_USER
- _APP_DB_PASS
+ - _APP_DATABASE_SHARED_TABLES
appwrite-task-scheduler-messages:
- image: appwrite/appwrite:1.8.0
+ image: appwrite/appwrite:1.9.5
entrypoint: schedule-messages
<<: *x-logging
restart: unless-stopped
depends_on:
- - mariadb
+ - ${_APP_DB_HOST:-mongodb}
- redis
environment:
- _APP_ENV
- _APP_WORKER_PER_CORE
+ - _APP_POOL_ADAPTER
- _APP_OPENSSL_KEY_V1
- _APP_REDIS_HOST
- _APP_REDIS_PORT
- _APP_REDIS_USER
- _APP_REDIS_PASS
+ - _APP_DB_ADAPTER
- _APP_DB_HOST
- _APP_DB_PORT
- _APP_DB_SCHEMA
- _APP_DB_USER
- _APP_DB_PASS
+ - _APP_DATABASE_SHARED_TABLES
appwrite-assistant:
- image: appwrite/assistant:0.8.3
+ image: appwrite/assistant:0.8.4
<<: *x-logging
restart: unless-stopped
environment:
- _APP_ASSISTANT_OPENAI_API_KEY
appwrite-browser:
- image: appwrite/browser:0.2.4
+ image: appwrite/browser:0.3.2
<<: *x-logging
restart: unless-stopped
openruntimes-executor:
- hostname: exc1
+ hostname: openruntimes-executor
<<: *x-logging
restart: unless-stopped
stop_signal: SIGINT
- image: openruntimes/executor:0.7.22
+ image: openruntimes/executor:0.25.1
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- appwrite-builds:/storage/builds:rw
@@ -751,7 +1029,10 @@ services:
# 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_COMPUTE_INACTIVE_THRESHOLD
+ - OPR_EXECUTOR_CONNECTION_STORAGE=local://localhost
+ - OPR_EXECUTOR_CONNECTION_BUILD_CACHE_STORAGE=
+ - OPR_EXECUTOR_IMAGES=$_APP_EXECUTOR_IMAGES
+ - OPR_EXECUTOR_INACTIVE_THRESHOLD=$_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
@@ -760,6 +1041,7 @@ services:
- OPR_EXECUTOR_RUNTIMES=$_APP_FUNCTIONS_RUNTIMES,$_APP_SITES_RUNTIMES
- OPR_EXECUTOR_SECRET=$_APP_EXECUTOR_SECRET
- OPR_EXECUTOR_RUNTIME_VERSIONS=v5
+ - OPEN_RUNTIMES_NFT=$_APP_OPEN_RUNTIMES_NFT
- 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
@@ -783,6 +1065,55 @@ services:
- OPR_EXECUTOR_STORAGE_WASABI_SECRET=$_APP_STORAGE_WASABI_SECRET
- OPR_EXECUTOR_STORAGE_WASABI_REGION=$_APP_STORAGE_WASABI_REGION
- OPR_EXECUTOR_STORAGE_WASABI_BUCKET=$_APP_STORAGE_WASABI_BUCKET
+ healthcheck:
+ test:
+ - CMD-SHELL
+ - 'curl -fsS -H "Authorization: Bearer $$OPR_EXECUTOR_SECRET" http://localhost/v1/health >/dev/null'
+ interval: 5s
+ timeout: 3s
+ retries: 20
+ start_period: 5s
+
+ mongodb:
+ image: mongo:8.2.5
+ <<: *x-logging
+ restart: unless-stopped
+ volumes:
+ - appwrite-mongodb:/data/db
+ - appwrite-mongodb-keyfile:/data/keyfile
+ - ../files/mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js:ro
+ - ../files/mongo-entrypoint.sh:/mongo-entrypoint.sh:ro
+ environment:
+ - MONGO_INITDB_ROOT_USERNAME=root
+ - MONGO_INITDB_ROOT_PASSWORD=${_APP_DB_ROOT_PASS}
+ - MONGO_INITDB_DATABASE=${_APP_DB_SCHEMA}
+ - MONGO_INITDB_USERNAME=${_APP_DB_USER}
+ - MONGO_INITDB_PASSWORD=${_APP_DB_PASS}
+ entrypoint:
+ - /bin/bash
+ - /mongo-entrypoint.sh
+ healthcheck:
+ test: |
+ bash -c "
+ mongosh -u root -p \"$$MONGO_INITDB_ROOT_PASSWORD\" --authenticationDatabase admin --quiet --eval \"
+ try {
+ const hello = db.adminCommand({hello: 1});
+ if (hello.isWritablePrimary) {
+ quit(0);
+ }
+ } catch (e) {}
+
+ try {
+ rs.initiate({_id: 'rs0', members: [{_id: 0, host: 'mongodb:27017'}]});
+ } catch (e) {}
+
+ quit(1);
+ \" 2>/dev/null
+ "
+ interval: 10s
+ timeout: 10s
+ retries: 10
+ start_period: 30s
mariadb:
image: mariadb:10.11 # fix issues when upgrading using: mysql_upgrade -u root -p
@@ -799,7 +1130,7 @@ services:
command: "mysqld --innodb-flush-method=fsync"
redis:
- image: redis:7.2.4-alpine
+ image: redis:7.4.7-alpine
<<: *x-logging
restart: unless-stopped
command: >
@@ -818,6 +1149,8 @@ services:
volumes:
appwrite-mariadb:
+ appwrite-mongodb:
+ appwrite-mongodb-keyfile:
appwrite-redis:
appwrite-cache:
appwrite-uploads:
diff --git a/blueprints/appwrite/template.toml b/blueprints/appwrite/template.toml
index cca2d43d..54d3a8bc 100644
--- a/blueprints/appwrite/template.toml
+++ b/blueprints/appwrite/template.toml
@@ -10,58 +10,69 @@ executor_secret = "${password:32}"
[config]
env = [
"_APP_ENV=production",
+ "_APP_EDITION=self-hosted",
"_APP_LOCALE=en",
+ "_APP_POOL_ADAPTER=stack",
+ "_APP_WORKER_PER_CORE=6",
"_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=${openssl_key}",
"_APP_DOMAIN=${main_domain}",
+ "_APP_CONSOLE_DOMAIN=${main_domain}",
+ "_APP_CONSOLE_TRUSTED_PROJECTS=",
"_APP_CUSTOM_DOMAIN_DENY_LIST=example.com,test.com,app.example.com",
"_APP_DOMAIN_FUNCTIONS=${functions_domain}",
"_APP_DOMAIN_SITES=${sites_domain}",
- "_APP_DOMAIN_TARGET=localhost",
"_APP_DOMAIN_TARGET_CNAME=localhost",
"_APP_DOMAIN_TARGET_AAAA=::1",
"_APP_DOMAIN_TARGET_A=127.0.0.1",
"_APP_DOMAIN_TARGET_CAA=",
"_APP_DNS=8.8.8.8",
+ "_APP_TRUSTED_HEADERS=x-forwarded-for",
"_APP_CONSOLE_WHITELIST_ROOT=enabled",
"_APP_CONSOLE_WHITELIST_EMAILS=",
"_APP_CONSOLE_WHITELIST_IPS=",
"_APP_CONSOLE_HOSTNAMES=",
+ "_APP_CONSOLE_SCHEMA=appwriteio",
+ "_APP_CONSOLE_SESSION_ALERTS=disabled",
+ "_APP_CONSOLE_COUNTRIES_DENYLIST=",
"_APP_SYSTEM_EMAIL_NAME=Appwrite",
"_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=",
"_APP_EMAIL_CERTIFICATES=",
- "_APP_USAGE_STATS=enabled",
- "_APP_LOGGING_PROVIDER=",
- "_APP_LOGGING_CONFIG=",
- "_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_USAGE_STATS=enabled",
+ "_APP_USAGE_AGGREGATION_INTERVAL=30",
+ "_APP_STATS_RESOURCES_INTERVAL=30",
+ "_APP_LOGGING_PROVIDER=",
+ "_APP_LOGGING_CONFIG=",
+ "_APP_LOGGING_CONFIG_REALTIME=",
+ "_APP_EXPERIMENT_LOGGING_PROVIDER=",
+ "_APP_EXPERIMENT_LOGGING_CONFIG=",
"_APP_REDIS_HOST=redis",
"_APP_REDIS_PORT=6379",
"_APP_REDIS_USER=",
"_APP_REDIS_PASS=",
- "_APP_DB_HOST=mariadb",
- "_APP_DB_PORT=3306",
+ "_APP_DB_ADAPTER=mongodb",
+ "_APP_DB_HOST=mongodb",
+ "_APP_DB_PORT=27017",
"_APP_DB_SCHEMA=appwrite",
"_APP_DB_USER=user",
"_APP_DB_PASS=${db_user_pw}",
"_APP_DB_ROOT_PASS=${db_root_pw}",
- "_APP_INFLUXDB_HOST=influxdb",
- "_APP_INFLUXDB_PORT=8086",
- "_APP_STATSD_HOST=telegraf",
- "_APP_STATSD_PORT=8125",
+ "_APP_DATABASE_SHARED_TABLES=",
+ "_APP_DATABASE_SHARED_NAMESPACE=",
+ "_APP_DB_ADAPTER_VECTORSDB=",
+ "_APP_DB_HOST_VECTORSDB=",
+ "_APP_DB_PORT_VECTORSDB=",
+ "_APP_DB_SCHEMA_VECTORSDB=",
+ "_APP_DB_USER_VECTORSDB=",
+ "_APP_DB_PASS_VECTORSDB=",
"_APP_SMTP_HOST=",
"_APP_SMTP_PORT=",
"_APP_SMTP_SECURE=",
@@ -69,6 +80,7 @@ env = [
"_APP_SMTP_PASSWORD=",
"_APP_SMS_PROVIDER=",
"_APP_SMS_FROM=",
+ "_APP_SMS_PROJECTS_DENY_LIST=",
"_APP_STORAGE_LIMIT=30000000",
"_APP_STORAGE_PREVIEW_LIMIT=20000000",
"_APP_STORAGE_ANTIVIRUS=disabled",
@@ -96,45 +108,27 @@ env = [
"_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=${executor_secret}",
- "_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=dokploy-network",
+ "_APP_COMPUTE_MAINTENANCE_INTERVAL=3600",
"_APP_COMPUTE_RUNTIMES_NETWORK=dokploy-network",
+ "_APP_FUNCTIONS_TIMEOUT=900",
+ "_APP_FUNCTIONS_CREATION_ABUSE_LIMIT=5000",
+ "_APP_FUNCTIONS_RUNTIMES=node-22,python-3.12,php-8.3,ruby-3.3,dart-3.5,go-1.23,rust-1.83,bun-1.1,deno-1.46,java-21.0,dotnet-8.0",
+ "_APP_SITES_TIMEOUT=900",
+ "_APP_SITES_RUNTIMES=static-1,node-22",
+ "_APP_EXECUTOR_SECRET=${executor_secret}",
+ "_APP_EXECUTOR_HOST=http://openruntimes-executor/v1",
+ "_APP_EXECUTOR_IMAGES=openruntimes/node:v5-22,openruntimes/python:v5-3.12,openruntimes/php:v5-8.3,openruntimes/static:v5-1",
+ "_APP_OPEN_RUNTIMES_NFT=enabled",
+ "_APP_BROWSER_HOST=http://appwrite-browser:3000/v1",
+ "_APP_WORKER_SCREENSHOTS_ROUTER=http://appwrite",
"_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=",
- "_APP_VCS_GITHUB_CLIENT_ID=",
- "_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",
@@ -143,14 +137,67 @@ env = [
"_APP_MAINTENANCE_RETENTION_ABUSE=86400",
"_APP_MAINTENANCE_RETENTION_USAGE_HOURLY=8640000",
"_APP_MAINTENANCE_RETENTION_SCHEDULES=86400",
+ "_APP_INTERVAL_DOMAIN_VERIFICATION=120",
+ "_APP_INTERVAL_CLEANUP_STALE_EXECUTIONS=300",
+ "_APP_GRAPHQL_INTROSPECTION=enabled",
"_APP_GRAPHQL_MAX_BATCH_SIZE=10",
"_APP_GRAPHQL_MAX_COMPLEXITY=250",
- "_APP_GRAPHQL_MAX_DEPTH=3",
+ "_APP_GRAPHQL_MAX_DEPTH=4",
+ "_APP_WEBHOOK_MAX_FAILED_ATTEMPTS=10",
+ "_APP_VCS_GITHUB_APP_NAME=",
+ "_APP_VCS_GITHUB_PRIVATE_KEY=",
+ "_APP_VCS_GITHUB_APP_ID=",
+ "_APP_VCS_GITHUB_CLIENT_ID=",
+ "_APP_VCS_GITHUB_CLIENT_SECRET=",
+ "_APP_VCS_GITHUB_WEBHOOK_SECRET=",
+ "_APP_MIGRATION_HOST=appwrite",
"_APP_MIGRATIONS_FIREBASE_CLIENT_ID=",
"_APP_MIGRATIONS_FIREBASE_CLIENT_SECRET=",
"_APP_ASSISTANT_OPENAI_API_KEY=",
]
-mounts = []
+
+[[config.mounts]]
+filePath = "mongo-init.js"
+content = """// mongo-init.js
+
+// Switch to the admin database
+const adminDb = db.getSiblingDB('admin');
+
+// Get username and password from environment variables
+const username = process.env.MONGO_INITDB_USERNAME;
+const password = process.env.MONGO_INITDB_PASSWORD;
+const database = process.env.MONGO_INITDB_DATABASE;
+
+// Create the user
+adminDb.createUser({
+ user: username,
+ pwd: password,
+ roles: [
+ { role: 'readWrite', db: database }
+ ]
+});
+"""
+
+[[config.mounts]]
+filePath = "mongo-entrypoint.sh"
+content = """#!/bin/bash
+set -e
+
+# Fix keyfile permissions if mounted from volume
+KEYFILE_PATH="/data/keyfile/mongo-keyfile"
+
+if [ ! -f "$KEYFILE_PATH" ]; then
+ echo "Generating random MongoDB keyfile..."
+ mkdir -p /data/keyfile
+ openssl rand -base64 756 > "$KEYFILE_PATH"
+fi
+
+chmod 400 "$KEYFILE_PATH"
+chown mongodb:mongodb "$KEYFILE_PATH" 2>/dev/null || chown 999:999 "$KEYFILE_PATH"
+
+# Use MongoDB's standard entrypoint with our command
+exec docker-entrypoint.sh mongod --replSet rs0 --bind_ip_all --auth --keyFile "$KEYFILE_PATH"
+"""
[[config.domains]]
serviceName = "appwrite"
diff --git a/blueprints/arche/arche.svg b/blueprints/arche/arche.svg
new file mode 100644
index 00000000..06ae9720
--- /dev/null
+++ b/blueprints/arche/arche.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/blueprints/arche/docker-compose.yml b/blueprints/arche/docker-compose.yml
new file mode 100644
index 00000000..cbefbe7e
--- /dev/null
+++ b/blueprints/arche/docker-compose.yml
@@ -0,0 +1,102 @@
+version: "3.8"
+
+# Arche — AI workspace platform that spawns per-user OpenCode containers
+# via a Docker socket proxy.
+#
+# PRE-REQUISITES (run once on the VPS before deploying):
+# mkdir -p /opt/arche/kb-content /opt/arche/kb-config /opt/arche/users
+#
+# Optional (only needed to seed the Knowledge Base):
+# git init --bare --initial-branch=main /opt/arche/kb-content
+# git init --bare --initial-branch=main /opt/arche/kb-config
+#
+# POST-DEPLOY (set in Dokploy → Environment, then redeploy):
+# 1. Deploy this template once. Dokploy auto-creates a network for the
+# compose stack.
+# 2. SSH into the host and find the network name:
+# docker network ls --format '{{.Name}}' | grep arche
+# It looks like `_default` or similar.
+# 3. Add the env var OPENCODE_NETWORK= and redeploy.
+# Without it, spawned user workspaces will fail to start.
+#
+# IMAGE ARCHITECTURE:
+# Default tags target linux/amd64. For ARM64 hosts (Apple Silicon,
+# Ampere, Graviton), override both images to the `-arm64` variants in
+# Dokploy → Environment:
+# ARCHE_WEB_IMAGE=ghcr.io/peaberry-studio/arche/web:latest-arm64
+# ARCHE_WORKSPACE_IMAGE=ghcr.io/peaberry-studio/arche/workspace:latest-arm64
+
+services:
+ web:
+ image: ${ARCHE_WEB_IMAGE:-ghcr.io/peaberry-studio/arche/web:latest}
+ restart: unless-stopped
+ depends_on:
+ postgres:
+ condition: service_healthy
+ docker-socket-proxy:
+ condition: service_started
+ environment:
+ ARCHE_DOMAIN: ${ARCHE_DOMAIN}
+ DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD}@postgres:5432/arche?schema=public
+
+ ARCHE_SESSION_PEPPER: ${ARCHE_SESSION_PEPPER}
+ ARCHE_ENCRYPTION_KEY: ${ARCHE_ENCRYPTION_KEY}
+ ARCHE_INTERNAL_TOKEN: ${ARCHE_INTERNAL_TOKEN}
+ ARCHE_GATEWAY_TOKEN_SECRET: ${ARCHE_GATEWAY_TOKEN_SECRET}
+ ARCHE_CONNECTOR_OAUTH_STATE_SECRET: ${ARCHE_CONNECTOR_OAUTH_STATE_SECRET}
+
+ ARCHE_GATEWAY_TOKEN_TTL_SECONDS: "86400"
+ ARCHE_GATEWAY_BASE_URL: http://web:3000
+ ARCHE_PUBLIC_BASE_URL: https://${ARCHE_DOMAIN}
+ ARCHE_SESSION_TTL_DAYS: "7"
+ ARCHE_COOKIE_SECURE: "true"
+
+ ARCHE_SEED_ADMIN_EMAIL: ${ARCHE_SEED_ADMIN_EMAIL}
+ ARCHE_SEED_ADMIN_PASSWORD: ${ARCHE_SEED_ADMIN_PASSWORD}
+ ARCHE_SEED_ADMIN_SLUG: ${ARCHE_SEED_ADMIN_SLUG:-admin}
+
+ CONTAINER_PROXY_HOST: docker-socket-proxy
+ CONTAINER_PROXY_PORT: "2375"
+ OPENCODE_IMAGE: ${ARCHE_WORKSPACE_IMAGE:-ghcr.io/peaberry-studio/arche/workspace:latest}
+ OPENCODE_NETWORK: ${OPENCODE_NETWORK}
+
+ KB_CONTENT_HOST_PATH: /opt/arche/kb-content
+ KB_CONFIG_HOST_PATH: /opt/arche/kb-config
+ ARCHE_USERS_PATH: /opt/arche/users
+ expose:
+ - "3000"
+ volumes:
+ - /opt/arche/kb-content:/kb-content
+ - /opt/arche/kb-config:/kb-config
+ - /opt/arche/users:/opt/arche/users
+
+ postgres:
+ image: postgres:16
+ restart: unless-stopped
+ environment:
+ POSTGRES_DB: arche
+ POSTGRES_USER: postgres
+ POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
+ volumes:
+ - postgres_data:/var/lib/postgresql/data
+ healthcheck:
+ test: ["CMD-SHELL", "pg_isready -U postgres"]
+ interval: 10s
+ timeout: 5s
+ retries: 5
+
+ docker-socket-proxy:
+ image: ghcr.io/tecnativa/docker-socket-proxy:master
+ restart: unless-stopped
+ environment:
+ CONTAINERS: 1
+ NETWORKS: 1
+ IMAGES: 1
+ INFO: 1
+ POST: 1
+ VOLUMES: 1
+ volumes:
+ - /var/run/docker.sock:/var/run/docker.sock:ro
+
+volumes:
+ postgres_data:
diff --git a/blueprints/arche/template.toml b/blueprints/arche/template.toml
new file mode 100644
index 00000000..5772c7b3
--- /dev/null
+++ b/blueprints/arche/template.toml
@@ -0,0 +1,33 @@
+[variables]
+main_domain = "${domain}"
+postgres_password = "${password:32}"
+session_pepper = "${base64:32}"
+encryption_key = "${base64:32}"
+internal_token = "${base64:32}"
+gateway_token_secret = "${base64:32}"
+connector_oauth_state_secret = "${base64:32}"
+seed_admin_email = "${email}"
+seed_admin_password = "${password:16}"
+
+[config]
+env = [
+ "ARCHE_DOMAIN=${main_domain}",
+ "POSTGRES_PASSWORD=${postgres_password}",
+ "ARCHE_SESSION_PEPPER=${session_pepper}",
+ "ARCHE_ENCRYPTION_KEY=${encryption_key}",
+ "ARCHE_INTERNAL_TOKEN=${internal_token}",
+ "ARCHE_GATEWAY_TOKEN_SECRET=${gateway_token_secret}",
+ "ARCHE_CONNECTOR_OAUTH_STATE_SECRET=${connector_oauth_state_secret}",
+ "ARCHE_SEED_ADMIN_EMAIL=${seed_admin_email}",
+ "ARCHE_SEED_ADMIN_PASSWORD=${seed_admin_password}",
+ "ARCHE_SEED_ADMIN_SLUG=admin",
+ "ARCHE_WEB_IMAGE=ghcr.io/peaberry-studio/arche/web:latest",
+ "ARCHE_WORKSPACE_IMAGE=ghcr.io/peaberry-studio/arche/workspace:latest",
+ "OPENCODE_NETWORK=",
+]
+mounts = []
+
+[[config.domains]]
+serviceName = "web"
+port = 3000
+host = "${main_domain}"
diff --git a/blueprints/autobase/docker-compose.yml b/blueprints/autobase/docker-compose.yml
index 13b23d57..7582c9c6 100644
--- a/blueprints/autobase/docker-compose.yml
+++ b/blueprints/autobase/docker-compose.yml
@@ -1,6 +1,6 @@
services:
autobase-console:
- image: autobase/console:2.5.2
+ image: autobase/console:2.7.2
restart: unless-stopped
ports:
- "80"
@@ -10,8 +10,10 @@ services:
- PG_CONSOLE_AUTHORIZATION_TOKEN=${PG_CONSOLE_AUTHORIZATION_TOKEN}
volumes:
- console_postgres:/var/lib/postgresql
+ - dbdesk_studio_data:/opt/dbdesk-studio
- /var/run/docker.sock:/var/run/docker.sock
- /tmp/ansible:/tmp/ansible
volumes:
console_postgres:
+ dbdesk_studio_data:
diff --git a/blueprints/billmora/billmora.svg b/blueprints/billmora/billmora.svg
new file mode 100644
index 00000000..e9daa0b3
--- /dev/null
+++ b/blueprints/billmora/billmora.svg
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/blueprints/billmora/docker-compose.yml b/blueprints/billmora/docker-compose.yml
new file mode 100644
index 00000000..870629e1
--- /dev/null
+++ b/blueprints/billmora/docker-compose.yml
@@ -0,0 +1,130 @@
+version: "3.8"
+
+services:
+ billmora-app:
+ image: ghcr.io/billmora/billmora:latest
+ restart: always
+ environment:
+ - APP_NAME=${APP_NAME}
+ - APP_ENV=${APP_ENV}
+ - APP_KEY=${APP_KEY}
+ - APP_URL=${APP_URL}
+ - DB_CONNECTION=${DB_CONNECTION}
+ - DB_HOST=${DB_HOST}
+ - DB_PORT=${DB_PORT}
+ - DB_DATABASE=${DB_DATABASE}
+ - DB_USERNAME=${DB_USERNAME}
+ - DB_PASSWORD=${DB_PASSWORD}
+ - REDIS_HOST=${REDIS_HOST}
+ - REDIS_PASSWORD=${REDIS_PASSWORD}
+ - REDIS_PORT=${REDIS_PORT}
+ - SESSION_DRIVER=${SESSION_DRIVER}
+ - CACHE_STORE=${CACHE_STORE}
+ - QUEUE_CONNECTION=${QUEUE_CONNECTION}
+ - AUTORUN_ENABLED=true
+ - AUTORUN_LARAVEL_MIGRATION=true
+ - AUTORUN_LARAVEL_MIGRATION_FORCE=true
+ - AUTORUN_LARAVEL_MIGRATION_SEED=true
+ - AUTORUN_LARAVEL_STORAGE_LINK=true
+ volumes:
+ - billmora-storage:/var/www/html/storage
+ depends_on:
+ billmora-db:
+ condition: service_healthy
+ billmora-redis:
+ condition: service_healthy
+
+ billmora-worker:
+ image: ghcr.io/billmora/billmora:latest
+ restart: always
+ command: ["php", "artisan", "queue:work", "--sleep=3", "--tries=3", "--max-time=3600"]
+ environment:
+ - APP_NAME=${APP_NAME}
+ - APP_ENV=${APP_ENV}
+ - APP_KEY=${APP_KEY}
+ - APP_URL=${APP_URL}
+ - DB_CONNECTION=${DB_CONNECTION}
+ - DB_HOST=${DB_HOST}
+ - DB_PORT=${DB_PORT}
+ - DB_DATABASE=${DB_DATABASE}
+ - DB_USERNAME=${DB_USERNAME}
+ - DB_PASSWORD=${DB_PASSWORD}
+ - REDIS_HOST=${REDIS_HOST}
+ - REDIS_PASSWORD=${REDIS_PASSWORD}
+ - REDIS_PORT=${REDIS_PORT}
+ - SESSION_DRIVER=${SESSION_DRIVER}
+ - CACHE_STORE=${CACHE_STORE}
+ - QUEUE_CONNECTION=${QUEUE_CONNECTION}
+ - AUTORUN_ENABLED=false
+ volumes:
+ - billmora-storage:/var/www/html/storage
+ depends_on:
+ billmora-db:
+ condition: service_healthy
+ billmora-redis:
+ condition: service_healthy
+
+ billmora-scheduler:
+ image: ghcr.io/billmora/billmora:latest
+ restart: always
+ command: ["/bin/sh", "-c", "while true; do php artisan schedule:run >> /dev/null 2>&1; sleep 60; done"]
+ environment:
+ - APP_NAME=${APP_NAME}
+ - APP_ENV=${APP_ENV}
+ - APP_KEY=${APP_KEY}
+ - APP_URL=${APP_URL}
+ - DB_CONNECTION=${DB_CONNECTION}
+ - DB_HOST=${DB_HOST}
+ - DB_PORT=${DB_PORT}
+ - DB_DATABASE=${DB_DATABASE}
+ - DB_USERNAME=${DB_USERNAME}
+ - DB_PASSWORD=${DB_PASSWORD}
+ - REDIS_HOST=${REDIS_HOST}
+ - REDIS_PASSWORD=${REDIS_PASSWORD}
+ - REDIS_PORT=${REDIS_PORT}
+ - SESSION_DRIVER=${SESSION_DRIVER}
+ - CACHE_STORE=${CACHE_STORE}
+ - QUEUE_CONNECTION=${QUEUE_CONNECTION}
+ - AUTORUN_ENABLED=false
+ volumes:
+ - billmora-storage:/var/www/html/storage
+ depends_on:
+ billmora-db:
+ condition: service_healthy
+ billmora-redis:
+ condition: service_healthy
+
+ billmora-db:
+ image: mariadb:11
+ restart: always
+ environment:
+ - MARIADB_DATABASE=${DB_DATABASE}
+ - MARIADB_USER=${DB_USERNAME}
+ - MARIADB_PASSWORD=${DB_PASSWORD}
+ - MARIADB_ROOT_PASSWORD=${DB_ROOT_PASSWORD}
+ volumes:
+ - billmora-db-data:/var/lib/mysql
+ healthcheck:
+ test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
+ interval: 10s
+ timeout: 5s
+ retries: 5
+ start_period: 30s
+
+ billmora-redis:
+ image: redis:7-alpine
+ restart: always
+ command: redis-server --requirepass ${REDIS_PASSWORD}
+ volumes:
+ - billmora-redis-data:/data
+ healthcheck:
+ test: ["CMD", "redis-cli", "--no-auth-warning", "-a", "${REDIS_PASSWORD}", "ping"]
+ interval: 10s
+ timeout: 3s
+ retries: 5
+ start_period: 10s
+
+volumes:
+ billmora-storage:
+ billmora-db-data:
+ billmora-redis-data:
diff --git a/blueprints/billmora/template.toml b/blueprints/billmora/template.toml
new file mode 100644
index 00000000..40a37e29
--- /dev/null
+++ b/blueprints/billmora/template.toml
@@ -0,0 +1,31 @@
+[variables]
+APP_KEY = "base64:${base64:32}"
+APP_URL = "https://${domain}"
+DB_PASSWORD = "${password:16}"
+DB_ROOT_PASSWORD = "${password:16}"
+REDIS_PASSWORD = "${password:16}"
+
+[config]
+[[config.domains]]
+serviceName = "billmora-app"
+port = 8080
+host = "${domain}"
+
+[config.env]
+APP_NAME = "Billmora"
+APP_ENV = "production"
+APP_KEY = "${APP_KEY}"
+APP_URL = "${APP_URL}"
+DB_CONNECTION = "mariadb"
+DB_HOST = "billmora-db"
+DB_PORT = "3306"
+DB_DATABASE = "billmora"
+DB_USERNAME = "billmora"
+DB_PASSWORD = "${DB_PASSWORD}"
+DB_ROOT_PASSWORD = "${DB_ROOT_PASSWORD}"
+REDIS_HOST = "billmora-redis"
+REDIS_PASSWORD = "${REDIS_PASSWORD}"
+REDIS_PORT = "6379"
+SESSION_DRIVER = "redis"
+CACHE_STORE = "redis"
+QUEUE_CONNECTION = "redis"
diff --git a/blueprints/crawlab-master/crawlab.jpeg b/blueprints/crawlab-master/crawlab.jpeg
new file mode 100644
index 00000000..1aef3cb9
Binary files /dev/null and b/blueprints/crawlab-master/crawlab.jpeg differ
diff --git a/blueprints/crawlab-master/docker-compose.yml b/blueprints/crawlab-master/docker-compose.yml
new file mode 100644
index 00000000..8b4f58af
--- /dev/null
+++ b/blueprints/crawlab-master/docker-compose.yml
@@ -0,0 +1,41 @@
+version: "3.8"
+services:
+ crawlab-master:
+ image: crawlabteam/crawlab:latest
+ restart: unless-stopped
+ environment:
+ - CRAWLAB_NODE_MASTER=Y
+ - CRAWLAB_MONGO_HOST=mongo
+ - CRAWLAB_MONGO_PORT=27017
+ - CRAWLAB_MONGO_DB=crawlab
+ - CRAWLAB_MONGO_USERNAME=${MONGO_USERNAME}
+ - CRAWLAB_MONGO_PASSWORD=${MONGO_PASSWORD}
+ - CRAWLAB_MONGO_AUTHSOURCE=admin
+ volumes:
+ - crawlab-master-data:/root/.crawlab
+ - crawlab-app-data:/data
+ - crawlab-logs:/var/log/crawlab
+ expose:
+ - "8080"
+ - "9666"
+ depends_on:
+ - mongo
+ deploy:
+ resources:
+ limits:
+ cpus: "${CPU_LIMIT:-0.8}" # 0.8 will limit to 80% of CPU if one core. If 2 cores, you need to put 0.8*2=1.6
+
+ mongo:
+ image: mongo:4.2
+ restart: unless-stopped
+ environment:
+ - MONGO_INITDB_ROOT_USERNAME=${MONGO_USERNAME}
+ - MONGO_INITDB_ROOT_PASSWORD=${MONGO_PASSWORD}
+ volumes:
+ - mongo-data:/data/db
+
+volumes:
+ crawlab-master-data:
+ crawlab-app-data:
+ crawlab-logs:
+ mongo-data:
diff --git a/blueprints/crawlab-master/template.toml b/blueprints/crawlab-master/template.toml
new file mode 100644
index 00000000..e1bf5524
--- /dev/null
+++ b/blueprints/crawlab-master/template.toml
@@ -0,0 +1,12 @@
+[variables]
+MONGO_USERNAME = "crawlab"
+MONGO_PASSWORD = "${password:24}"
+CPU_LIMIT = "0.8"
+
+[config]
+env = ["MONGO_USERNAME=${MONGO_USERNAME}", "MONGO_PASSWORD=${MONGO_PASSWORD}", "CPU_LIMIT=${CPU_LIMIT}"]
+
+[[config.domains]]
+serviceName = "crawlab-master"
+port = 8080
+host = "${domain}"
diff --git a/blueprints/crawlab-worker/crawlab.jpeg b/blueprints/crawlab-worker/crawlab.jpeg
new file mode 100644
index 00000000..1aef3cb9
Binary files /dev/null and b/blueprints/crawlab-worker/crawlab.jpeg differ
diff --git a/blueprints/crawlab-worker/docker-compose.yml b/blueprints/crawlab-worker/docker-compose.yml
new file mode 100644
index 00000000..7f147afa
--- /dev/null
+++ b/blueprints/crawlab-worker/docker-compose.yml
@@ -0,0 +1,20 @@
+version: "3.8"
+services:
+ crawlab-worker:
+ image: crawlabteam/crawlab:latest
+ restart: unless-stopped
+ environment:
+ - CRAWLAB_NODE_MASTER=N
+ - CRAWLAB_GRPC_ADDRESS=${MASTER_GRPC_ADDRESS}
+ - CRAWLAB_FS_FILER_URL=${MASTER_FILER_URL}
+ volumes:
+ - crawlab-worker-data:/root/.crawlab
+ - crawlab-worker-app:/data
+ deploy:
+ resources:
+ limits:
+ cpus: "${CPU_LIMIT:-0.8}" # 0.8 will limit to 80% of CPU if one core. If 2 cores, you need to put 0.8*2=1.6
+
+volumes:
+ crawlab-worker-data:
+ crawlab-worker-app:
diff --git a/blueprints/crawlab-worker/template.toml b/blueprints/crawlab-worker/template.toml
new file mode 100644
index 00000000..ba9e53d1
--- /dev/null
+++ b/blueprints/crawlab-worker/template.toml
@@ -0,0 +1,7 @@
+[variables]
+MASTER_GRPC_ADDRESS = ":9666"
+MASTER_FILER_URL = "http://:8080/api/filer"
+CPU_LIMIT = "0.8"
+
+[config]
+env = ["MASTER_GRPC_ADDRESS=${MASTER_GRPC_ADDRESS}", "MASTER_FILER_URL=${MASTER_FILER_URL}", "CPU_LIMIT=${CPU_LIMIT}"]
diff --git a/blueprints/cut/cut.svg b/blueprints/cut/cut.svg
new file mode 100644
index 00000000..c0604eac
--- /dev/null
+++ b/blueprints/cut/cut.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/blueprints/cut/docker-compose.yml b/blueprints/cut/docker-compose.yml
new file mode 100644
index 00000000..b31578d1
--- /dev/null
+++ b/blueprints/cut/docker-compose.yml
@@ -0,0 +1,37 @@
+services:
+ cut:
+ image: ghcr.io/mendylanda/cut:latest
+ restart: unless-stopped
+ depends_on:
+ redis:
+ condition: service_healthy
+ environment:
+ # Injected by Dokploy from template.toml (generated strong password).
+ - ADMIN_PASSWORD=${ADMIN_PASSWORD}
+ # Bundled Redis below, private to the project network.
+ - REDIS_URL=redis://redis:6379
+ # Expose the container port only; Dokploy maps the domain to it.
+ ports:
+ - 3000
+ healthcheck:
+ test: ["CMD", "wget", "-qO-", "http://127.0.0.1:3000/"]
+ interval: 10s
+ timeout: 5s
+ retries: 10
+
+ redis:
+ image: redis:7-alpine
+ restart: unless-stopped
+ # appendonly = durable across restarts; noeviction because this is Cut's
+ # primary datastore, not a cache (don't drop links under memory pressure).
+ command: redis-server --appendonly yes --maxmemory-policy noeviction
+ volumes:
+ - redis-data:/data
+ healthcheck:
+ test: ["CMD", "redis-cli", "ping"]
+ interval: 5s
+ timeout: 3s
+ retries: 10
+
+volumes:
+ redis-data:
diff --git a/blueprints/cut/template.toml b/blueprints/cut/template.toml
new file mode 100644
index 00000000..83de686c
--- /dev/null
+++ b/blueprints/cut/template.toml
@@ -0,0 +1,14 @@
+[variables]
+main_domain = "${domain}"
+admin_password = "${password:24}"
+
+[config]
+env = [
+ "ADMIN_PASSWORD=${admin_password}",
+]
+mounts = []
+
+[[config.domains]]
+serviceName = "cut"
+port = 3000
+host = "${main_domain}"
diff --git a/blueprints/discourse/docker-compose.yml b/blueprints/discourse/docker-compose.yml
index caafab5b..d0353e8a 100644
--- a/blueprints/discourse/docker-compose.yml
+++ b/blueprints/discourse/docker-compose.yml
@@ -1,29 +1,24 @@
-version: '3.7'
-
services:
discourse-db:
- image: docker.io/bitnami/postgresql:17
-
+ image: pgvector/pgvector:pg16
volumes:
- - discourse-postgresql-data:/bitnami/postgresql
+ - discourse-postgresql-data:/var/lib/postgresql/data
environment:
- POSTGRESQL_USERNAME: bn_discourse
- POSTGRESQL_PASSWORD: ${POSTGRES_PASSWORD}
- POSTGRESQL_DATABASE: bitnami_discourse
+ POSTGRES_USER: discourse
+ POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
+ POSTGRES_DB: discourse
healthcheck:
- test: ["CMD-SHELL", "pg_isready -U bn_discourse -d bitnami_discourse"]
+ test: ["CMD-SHELL", "pg_isready -U discourse -d discourse"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
discourse-redis:
- image: docker.io/bitnami/redis:7.4
-
+ image: redis:7-alpine
volumes:
- - discourse-redis-data:/bitnami/redis
- environment:
- REDIS_PASSWORD: ${REDIS_PASSWORD}
+ - discourse-redis-data:/data
+ command: redis-server --requirepass ${REDIS_PASSWORD}
healthcheck:
test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"]
interval: 10s
@@ -32,59 +27,38 @@ services:
restart: unless-stopped
discourse-app:
- image: docker.io/bitnamilegacy/discourse:3.5.0
-
+ image: discourse/discourse:2026.1.4
volumes:
- - discourse-data:/bitnami/discourse
+ - discourse-data:/shared
depends_on:
discourse-db:
condition: service_healthy
discourse-redis:
condition: service_healthy
environment:
- DISCOURSE_HOST: ${DISCOURSE_HOST}
- DISCOURSE_DATABASE_HOST: discourse-db
- DISCOURSE_DATABASE_PORT_NUMBER: 5432
- DISCOURSE_DATABASE_USER: bn_discourse
- DISCOURSE_DATABASE_PASSWORD: ${POSTGRES_PASSWORD}
- DISCOURSE_DATABASE_NAME: bitnami_discourse
+ DISCOURSE_HOSTNAME: ${DISCOURSE_HOST}
+ DISCOURSE_DB_HOST: discourse-db
+ DISCOURSE_DB_PORT: 5432
+ DISCOURSE_DB_USERNAME: discourse
+ DISCOURSE_DB_PASSWORD: ${POSTGRES_PASSWORD}
+ DISCOURSE_DB_NAME: discourse
DISCOURSE_REDIS_HOST: discourse-redis
- DISCOURSE_REDIS_PORT_NUMBER: 6379
+ DISCOURSE_REDIS_PORT: 6379
DISCOURSE_REDIS_PASSWORD: ${REDIS_PASSWORD}
- # Optional: Configure SMTP for email delivery
- # DISCOURSE_SMTP_HOST: ${SMTP_HOST}
+ DISCOURSE_DEVELOPER_EMAILS: ${DISCOURSE_ADMIN_EMAIL}
+ # Required for email delivery - Discourse will not function correctly without SMTP
+ # DISCOURSE_SMTP_ADDRESS: ${SMTP_HOST}
# DISCOURSE_SMTP_PORT: ${SMTP_PORT}
- # DISCOURSE_SMTP_USER: ${SMTP_USER}
- # DISCOURSE_SMTP_PASSWORD: ${SMTP_PASSWORD}
- restart: unless-stopped
-
- discourse-sidekiq:
- image: docker.io/bitnamilegacy/discourse:3.5.0
-
- volumes:
- - discourse-sidekiq-data:/bitnami/discourse
- depends_on:
- - discourse-app
- command: /opt/bitnami/scripts/discourse-sidekiq/run.sh
- environment:
- DISCOURSE_HOST: ${DISCOURSE_HOST}
- DISCOURSE_DATABASE_HOST: discourse-db
- DISCOURSE_DATABASE_PORT_NUMBER: 5432
- DISCOURSE_DATABASE_USER: bn_discourse
- DISCOURSE_DATABASE_PASSWORD: ${POSTGRES_PASSWORD}
- DISCOURSE_DATABASE_NAME: bitnami_discourse
- DISCOURSE_REDIS_HOST: discourse-redis
- DISCOURSE_REDIS_PORT_NUMBER: 6379
- DISCOURSE_REDIS_PASSWORD: ${REDIS_PASSWORD}
- # Optional: Configure SMTP for email delivery
- # DISCOURSE_SMTP_HOST: ${SMTP_HOST}
- # DISCOURSE_SMTP_PORT: ${SMTP_PORT}
- # DISCOURSE_SMTP_USER: ${SMTP_USER}
+ # DISCOURSE_SMTP_USER_NAME: ${SMTP_USER}
# DISCOURSE_SMTP_PASSWORD: ${SMTP_PASSWORD}
+ # DISCOURSE_SMTP_ENABLE_START_TLS: "true"
+ # DISCOURSE_NOTIFICATION_EMAIL: [email protected]
+ # DISCOURSE_DEVELOPER_EMAILS: [email protected]
+ ports:
+ - 80
restart: unless-stopped
volumes:
discourse-postgresql-data:
discourse-redis-data:
discourse-data:
- discourse-sidekiq-data:
\ No newline at end of file
diff --git a/blueprints/discourse/template.toml b/blueprints/discourse/template.toml
index c02aa2c7..10358839 100644
--- a/blueprints/discourse/template.toml
+++ b/blueprints/discourse/template.toml
@@ -1,11 +1,13 @@
[variables]
main_domain = "${domain}"
+admin_email = "${email}"
postgres_password = "${password}"
redis_password = "${password}"
[config]
env = [
"DISCOURSE_HOST=${main_domain}",
+ "DISCOURSE_ADMIN_EMAIL=${admin_email}",
"POSTGRES_PASSWORD=${postgres_password}",
"REDIS_PASSWORD=${redis_password}",
]
@@ -13,5 +15,5 @@ mounts = []
[[config.domains]]
serviceName = "discourse-app"
-port = 3_000
-host = "${main_domain}"
+port = 80
+host = "${main_domain}"
\ No newline at end of file
diff --git a/blueprints/fider/docker-compose.yml b/blueprints/fider/docker-compose.yml
new file mode 100644
index 00000000..1c42adaf
--- /dev/null
+++ b/blueprints/fider/docker-compose.yml
@@ -0,0 +1,37 @@
+version: "3.8"
+
+services:
+ db:
+ image: postgres:17
+ restart: unless-stopped
+ volumes:
+ - fiderPostgresData:/var/lib/postgresql/data
+ environment:
+ POSTGRES_USER: ${POSTGRES_USER}
+ POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
+ POSTGRES_DB: ${POSTGRES_DB}
+
+ fider:
+ image: getfider/fider:0.21.1
+ restart: unless-stopped
+ depends_on:
+ - db
+ - mailhog
+ environment:
+ BASE_URL: ${BASE_URL}
+ DATABASE_URL: ${DATABASE_URL}
+ JWT_SECRET: ${JWT_SECRET}
+ EMAIL: ${EMAIL}
+ EMAIL_NOREPLY: ${EMAIL_NOREPLY}
+ EMAIL_SMTP_HOST: ${EMAIL_SMTP_HOST}
+ EMAIL_SMTP_PORT: ${EMAIL_SMTP_PORT}
+ EMAIL_SMTP_USERNAME: ${EMAIL_SMTP_USERNAME}
+ EMAIL_SMTP_PASSWORD: ${EMAIL_SMTP_PASSWORD}
+ EMAIL_SMTP_ENABLE_STARTTLS: ${EMAIL_SMTP_ENABLE_STARTTLS}
+
+ mailhog:
+ image: mailhog/mailhog:v1.0.1
+ restart: unless-stopped
+
+volumes:
+ fiderPostgresData:
diff --git a/blueprints/fider/fider.svg b/blueprints/fider/fider.svg
new file mode 100644
index 00000000..e3b6b12c
--- /dev/null
+++ b/blueprints/fider/fider.svg
@@ -0,0 +1,9 @@
+
+ Fider
+ Fider template logo
+
+
+
+
+
+
\ No newline at end of file
diff --git a/blueprints/fider/template.toml b/blueprints/fider/template.toml
new file mode 100644
index 00000000..c409461a
--- /dev/null
+++ b/blueprints/fider/template.toml
@@ -0,0 +1,27 @@
+[variables]
+main_domain = "${domain}"
+postgres_password = "${password:32}"
+jwt_secret = "${password:64}"
+
+[config]
+env = [
+ "POSTGRES_USER=fider",
+ "POSTGRES_PASSWORD=${postgres_password}",
+ "POSTGRES_DB=fider",
+ "BASE_URL=https://${main_domain}",
+ "DATABASE_URL=postgres://fider:${postgres_password}@db:5432/fider?sslmode=disable",
+ "JWT_SECRET=${jwt_secret}",
+ "EMAIL_NOREPLY=noreply@${main_domain}",
+ "EMAIL=smtp",
+ "EMAIL_SMTP_HOST=mailhog",
+ "EMAIL_SMTP_PORT=1025",
+ "EMAIL_SMTP_USERNAME=",
+ "EMAIL_SMTP_PASSWORD=",
+ "EMAIL_SMTP_ENABLE_STARTTLS=true",
+]
+mounts = []
+
+[[config.domains]]
+serviceName = "fider"
+port = 3000
+host = "${main_domain}"
diff --git a/blueprints/geoserver/docker-compose.yml b/blueprints/geoserver/docker-compose.yml
new file mode 100644
index 00000000..fdd4fc97
--- /dev/null
+++ b/blueprints/geoserver/docker-compose.yml
@@ -0,0 +1,27 @@
+services:
+ geoserver:
+ image: kartoza/geoserver:2.24.1
+ depends_on:
+ - db
+ environment:
+ - GEOSERVER_ADMIN_USER=${GEOSERVER_ADMIN_USER}
+ - GEOSERVER_ADMIN_PASSWORD=${GEOSERVER_ADMIN_PASSWORD}
+ - INITIAL_MEMORY=${INITIAL_MEMORY}
+ - MAXIMUM_MEMORY=${MAXIMUM_MEMORY}
+ volumes:
+ - geoserver-data:/opt/geoserver/data_dir
+ restart: unless-stopped
+
+ db:
+ image: postgis/postgis:17-3.4
+ environment:
+ - POSTGRES_USER=${POSTGRES_USER}
+ - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
+ - POSTGRES_DB=${POSTGRES_DB}
+ volumes:
+ - postgis-data:/var/lib/postgresql/data
+ restart: unless-stopped
+
+volumes:
+ geoserver-data:
+ postgis-data:
diff --git a/blueprints/geoserver/logo.png b/blueprints/geoserver/logo.png
new file mode 100644
index 00000000..14ae15a6
Binary files /dev/null and b/blueprints/geoserver/logo.png differ
diff --git a/blueprints/geoserver/logo.svg b/blueprints/geoserver/logo.svg
new file mode 100644
index 00000000..e2f02fee
--- /dev/null
+++ b/blueprints/geoserver/logo.svg
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/blueprints/geoserver/template.toml b/blueprints/geoserver/template.toml
new file mode 100644
index 00000000..a975cc8e
--- /dev/null
+++ b/blueprints/geoserver/template.toml
@@ -0,0 +1,18 @@
+[info]
+name = "GeoServer & PostGIS"
+description = "An open-source server for sharing geospatial data, paired with a PostGIS database. Template created and maintained by OpenGeoCity Tanzania (info@ogctz.org). For further assistance contact +255759968919 or visit https://opengeocity.org or github: https://github.com/ShabaniMagawila or linkedin: https://www.linkedin.com/in/shabani-magawila/"
+version = "2.24.1"
+
+[variables]
+GEOSERVER_ADMIN_USER = "admin"
+GEOSERVER_ADMIN_PASSWORD = "geoserver_secure"
+INITIAL_MEMORY = "2G"
+MAXIMUM_MEMORY = "4G"
+POSTGRES_USER = "postgres"
+POSTGRES_PASSWORD = "postgres_secure"
+POSTGRES_DB = "gis"
+
+[config]
+[[config.domains]]
+serviceName = "geoserver"
+port = 8080
\ No newline at end of file
diff --git a/blueprints/glitchtip/docker-compose.yml b/blueprints/glitchtip/docker-compose.yml
index f47742f0..8a483a61 100644
--- a/blueprints/glitchtip/docker-compose.yml
+++ b/blueprints/glitchtip/docker-compose.yml
@@ -1,55 +1,52 @@
+version: "3.8"
+
x-environment: &default-environment
DATABASE_URL: postgres://postgres:postgres@postgres:5432/postgres
+ VALKEY_URL: redis://valkey:6379
SECRET_KEY: ${SECRET_KEY}
PORT: ${GLITCHTIP_PORT}
EMAIL_URL: consolemail://
- GLITCHTIP_DOMAIN: http://${GLITCHTIP_HOST}
- DEFAULT_FROM_EMAIL: email@glitchtip.com
- CELERY_WORKER_AUTOSCALE: "1,3"
- CELERY_WORKER_MAX_TASKS_PER_CHILD: "10000"
+ GLITCHTIP_DOMAIN: ${GLITCHTIP_DOMAIN}
+ DEFAULT_FROM_EMAIL: ${DEFAULT_FROM_EMAIL}
x-depends_on: &default-depends_on
- postgres
- - redis
+ - valkey
services:
postgres:
- image: postgres:16
+ image: postgres:18
environment:
POSTGRES_HOST_AUTH_METHOD: "trust"
restart: unless-stopped
volumes:
- pg-data:/var/lib/postgresql/data
-
- redis:
- image: redis
+ valkey:
+ image: valkey/valkey:9
restart: unless-stopped
-
web:
- image: glitchtip/glitchtip:v4.0
+ image: glitchtip/glitchtip:6.1.0
depends_on: *default-depends_on
- ports:
+ expose:
- ${GLITCHTIP_PORT}
environment: *default-environment
restart: unless-stopped
volumes:
- uploads:/code/uploads
worker:
- image: glitchtip/glitchtip:v4.0
- command: ./bin/run-celery-with-beat.sh
+ image: glitchtip/glitchtip:6.1.0
+ command: ./bin/run-worker.sh
depends_on: *default-depends_on
environment: *default-environment
restart: unless-stopped
volumes:
- uploads:/code/uploads
-
migrate:
- image: glitchtip/glitchtip:v4.0
+ image: glitchtip/glitchtip:6.1.0
depends_on: *default-depends_on
- command: "./manage.py migrate"
+ command: ./bin/run-migrate.sh
environment: *default-environment
-
volumes:
pg-data:
uploads:
diff --git a/blueprints/glitchtip/template.toml b/blueprints/glitchtip/template.toml
index c5b7a46c..af90c5ff 100644
--- a/blueprints/glitchtip/template.toml
+++ b/blueprints/glitchtip/template.toml
@@ -4,7 +4,8 @@ secret_key = "${base64:32}"
[config]
env = [
- "GLITCHTIP_HOST=${main_domain}",
+ "DEFAULT_FROM_EMAIL=${email}",
+ "GLITCHTIP_DOMAIN=https://${main_domain}",
"GLITCHTIP_PORT=8000",
"SECRET_KEY=${secret_key}",
]
@@ -12,5 +13,5 @@ mounts = []
[[config.domains]]
serviceName = "web"
-port = 8_000
+port = 8000
host = "${main_domain}"
diff --git a/blueprints/hedgedoc/docker-compose.yml b/blueprints/hedgedoc/docker-compose.yml
new file mode 100644
index 00000000..8ee2e567
--- /dev/null
+++ b/blueprints/hedgedoc/docker-compose.yml
@@ -0,0 +1,37 @@
+version: "3.8"
+
+services:
+ hedgedoc:
+ image: quay.io/hedgedoc/hedgedoc:1.10.8
+ restart: unless-stopped
+ depends_on:
+ database:
+ condition: service_healthy
+ environment:
+ - CMD_DB_URL=${CMD_DB_URL}
+ - CMD_DOMAIN=${CMD_DOMAIN}
+ - CMD_PROTOCOL_USESSL=${CMD_PROTOCOL_USESSL}
+ - CMD_URL_ADDPORT=${CMD_URL_ADDPORT}
+ volumes:
+ - hedgedoc_uploads:/hedgedoc/public/uploads
+ expose:
+ - "3000"
+
+ database:
+ image: postgres:17.7-alpine
+ restart: unless-stopped
+ environment:
+ - POSTGRES_USER=hedgedoc
+ - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
+ - POSTGRES_DB=hedgedoc
+ volumes:
+ - hedgedoc_database:/var/lib/postgresql/data
+ healthcheck:
+ test: ["CMD-SHELL", "pg_isready -U hedgedoc -d hedgedoc"]
+ interval: 10s
+ timeout: 5s
+ retries: 5
+
+volumes:
+ hedgedoc_uploads:
+ hedgedoc_database:
diff --git a/blueprints/hedgedoc/hedgedoc.svg b/blueprints/hedgedoc/hedgedoc.svg
new file mode 100644
index 00000000..0d236216
--- /dev/null
+++ b/blueprints/hedgedoc/hedgedoc.svg
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/blueprints/hedgedoc/template.toml b/blueprints/hedgedoc/template.toml
new file mode 100644
index 00000000..8e82e9d5
--- /dev/null
+++ b/blueprints/hedgedoc/template.toml
@@ -0,0 +1,16 @@
+[variables]
+main_domain = "${domain}"
+database_password = "${password:32}"
+
+[config]
+[[config.domains]]
+serviceName = "hedgedoc"
+port = 3000
+host = "${main_domain}"
+
+[config.env]
+POSTGRES_PASSWORD = "${database_password}"
+CMD_DB_URL = "postgres://hedgedoc:${database_password}@database:5432/hedgedoc"
+CMD_DOMAIN = "${main_domain}"
+CMD_PROTOCOL_USESSL = "true"
+CMD_URL_ADDPORT = "false"
diff --git a/blueprints/hi-events/docker-compose.yml b/blueprints/hi-events/docker-compose.yml
index 3c2291b9..dd3d7269 100644
--- a/blueprints/hi-events/docker-compose.yml
+++ b/blueprints/hi-events/docker-compose.yml
@@ -1,6 +1,6 @@
services:
all-in-one:
- image: daveearley/hi.events-all-in-one:v0.8.0-beta.1
+ image: daveearley/hi.events-all-in-one:v1.9.0-beta
restart: always
environment:
- VITE_FRONTEND_URL=https://${DOMAIN}
@@ -20,6 +20,8 @@ services:
- MAIL_MAILER
- MAIL_HOST
- MAIL_PORT
+ - MAIL_USERNAME
+ - MAIL_PASSWORD
- MAIL_FROM_ADDRESS
- MAIL_FROM_NAME
depends_on:
diff --git a/blueprints/hi-events/template.toml b/blueprints/hi-events/template.toml
index 4fea86ce..a8c2c3d3 100644
--- a/blueprints/hi-events/template.toml
+++ b/blueprints/hi-events/template.toml
@@ -16,6 +16,8 @@ env = [
"MAIL_MAILER=",
"MAIL_HOST=",
"MAIL_PORT=",
+ "MAIL_USERNAME=",
+ "MAIL_PASSWORD=",
"MAIL_FROM_ADDRESS=",
"MAIL_FROM_NAME=",
]
diff --git a/blueprints/homepage/docker-compose.yml b/blueprints/homepage/docker-compose.yml
new file mode 100644
index 00000000..2a6d48b9
--- /dev/null
+++ b/blueprints/homepage/docker-compose.yml
@@ -0,0 +1,9 @@
+version: "3.8"
+services:
+ homepage:
+ image: ghcr.io/gethomepage/homepage:v1.13.1
+ restart: unless-stopped
+ expose:
+ - 3000
+ volumes:
+ - ../files/homepage-config:/app/config
diff --git a/blueprints/homepage/homepage.png b/blueprints/homepage/homepage.png
new file mode 100644
index 00000000..0a11f3dc
Binary files /dev/null and b/blueprints/homepage/homepage.png differ
diff --git a/blueprints/homepage/template.toml b/blueprints/homepage/template.toml
new file mode 100644
index 00000000..2f4dfa15
--- /dev/null
+++ b/blueprints/homepage/template.toml
@@ -0,0 +1,13 @@
+[variables]
+main_domain = "${domain}"
+
+[config]
+[[config.domains]]
+serviceName = "homepage"
+port = 3000
+host = "${main_domain}"
+
+[config.env]
+HOMEPAGE_ALLOWED_HOSTS = "${main_domain}"
+PUID = "1000"
+PGID = "1000"
diff --git a/blueprints/imgproxy/docker-compose.yml b/blueprints/imgproxy/docker-compose.yml
index e9bc86a1..b71ccf49 100644
--- a/blueprints/imgproxy/docker-compose.yml
+++ b/blueprints/imgproxy/docker-compose.yml
@@ -3,6 +3,8 @@ services:
imgproxy:
image: darthsim/imgproxy:v3.30.1
restart: unless-stopped
+ expose:
+ - 8080
environment:
IMGPROXY_KEY: ${IMGPROXY_KEY}
IMGPROXY_SALT: ${IMGPROXY_SALT}
diff --git a/blueprints/immich/docker-compose.yml b/blueprints/immich/docker-compose.yml
index 8f12d6d1..f385b329 100644
--- a/blueprints/immich/docker-compose.yml
+++ b/blueprints/immich/docker-compose.yml
@@ -28,7 +28,7 @@ services:
REDIS_DBINDEX: ${REDIS_DBINDEX}
# Server Configuration
TZ: ${TZ}
- restart: always
+ restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:2283/server-info/ping"]
interval: 30s
@@ -44,7 +44,7 @@ services:
REDIS_HOSTNAME: ${REDIS_HOSTNAME}
REDIS_PORT: ${REDIS_PORT}
REDIS_DBINDEX: ${REDIS_DBINDEX}
- restart: always
+ restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3003/ping"]
interval: 30s
@@ -61,7 +61,7 @@ services:
interval: 10s
timeout: 5s
retries: 5
- restart: always
+ restart: unless-stopped
immich-database:
image: tensorchord/pgvecto-rs:pg14-v0.3.0
@@ -94,10 +94,10 @@ services:
'-c',
'wal_compression=on',
]
- restart: always
+ restart: unless-stopped
volumes:
immich-model-cache:
immich-postgres:
immich-library:
- immich-redis-data:
+ immich-redis-data:
diff --git a/blueprints/joomla/docker-compose.yml b/blueprints/joomla/docker-compose.yml
new file mode 100644
index 00000000..e83a420b
--- /dev/null
+++ b/blueprints/joomla/docker-compose.yml
@@ -0,0 +1,44 @@
+version: "3.8"
+
+services:
+ joomla:
+ image: joomla:6.1.0-apache
+ restart: unless-stopped
+ depends_on:
+ joomla-db:
+ condition: service_healthy
+ expose:
+ - "80"
+ environment:
+ JOOMLA_DB_HOST: joomla-db
+ JOOMLA_DB_USER: ${JOOMLA_DB_USER}
+ JOOMLA_DB_PASSWORD: ${JOOMLA_DB_PASSWORD}
+ JOOMLA_DB_NAME: ${JOOMLA_DB_NAME}
+ JOOMLA_SITE_NAME: ${JOOMLA_SITE_NAME}
+ JOOMLA_ADMIN_USER: ${JOOMLA_ADMIN_USER}
+ JOOMLA_ADMIN_USERNAME: ${JOOMLA_ADMIN_USERNAME}
+ JOOMLA_ADMIN_PASSWORD: ${JOOMLA_ADMIN_PASSWORD}
+ JOOMLA_ADMIN_EMAIL: ${JOOMLA_ADMIN_EMAIL}
+ volumes:
+ - joomla-data:/var/www/html
+
+ joomla-db:
+ image: mariadb:11.4
+ restart: unless-stopped
+ environment:
+ MARIADB_DATABASE: ${JOOMLA_DB_NAME}
+ MARIADB_USER: ${JOOMLA_DB_USER}
+ MARIADB_PASSWORD: ${JOOMLA_DB_PASSWORD}
+ MARIADB_RANDOM_ROOT_PASSWORD: "1"
+ volumes:
+ - joomla-db:/var/lib/mysql
+ healthcheck:
+ test: ["CMD-SHELL", "healthcheck.sh --connect --innodb_initialized"]
+ interval: 10s
+ timeout: 5s
+ retries: 5
+ start_period: 30s
+
+volumes:
+ joomla-data:
+ joomla-db:
diff --git a/blueprints/joomla/joomla.svg b/blueprints/joomla/joomla.svg
new file mode 100644
index 00000000..27239ba8
--- /dev/null
+++ b/blueprints/joomla/joomla.svg
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/blueprints/joomla/template.toml b/blueprints/joomla/template.toml
new file mode 100644
index 00000000..4f360d66
--- /dev/null
+++ b/blueprints/joomla/template.toml
@@ -0,0 +1,51 @@
+[variables]
+main_domain = "${domain}"
+site_name = "Joomla"
+admin_name = "Joomla Administrator"
+admin_username = "${username}"
+admin_password = "${password:24}"
+admin_email = "${email}"
+db_user = "joomla"
+db_password = "${password:32}"
+db_name = "joomla"
+
+[[config.domains]]
+serviceName = "joomla"
+port = 80
+host = "${main_domain}"
+path = "/"
+
+[[config.mounts]]
+filePath = "README.md"
+content = """# Joomla
+
+This template deploys Joomla CMS with MariaDB using the official Joomla Apache image.
+
+## Access
+
+- URL: `http://${main_domain}`
+- Administrator username: the configured `admin_username` value
+- Administrator password: the generated `admin_password` value
+- Administrator email: the configured `admin_email` value
+
+The template uses Joomla's auto-deployment environment variables so the site and administrator account are initialized on first start.
+
+## Storage
+
+The template creates persistent volumes for:
+
+- Joomla application files at `/var/www/html`
+- MariaDB data at `/var/lib/mysql`
+
+Back up both volumes together before upgrades or migrations.
+"""
+
+[config.env]
+JOOMLA_SITE_NAME = "${site_name}"
+JOOMLA_ADMIN_USER = "${admin_name}"
+JOOMLA_ADMIN_USERNAME = "${admin_username}"
+JOOMLA_ADMIN_PASSWORD = "${admin_password}"
+JOOMLA_ADMIN_EMAIL = "${admin_email}"
+JOOMLA_DB_USER = "${db_user}"
+JOOMLA_DB_PASSWORD = "${db_password}"
+JOOMLA_DB_NAME = "${db_name}"
diff --git a/blueprints/langflow/docker-compose.yml b/blueprints/langflow/docker-compose.yml
index a9628286..70495a7a 100644
--- a/blueprints/langflow/docker-compose.yml
+++ b/blueprints/langflow/docker-compose.yml
@@ -1,31 +1,44 @@
-version: "3.8"
-
services:
langflow:
- image: langflowai/langflow:v1.1.1
+ image: langflowai/langflow:latest
+ user: root
+ restart: always
+ pull_policy: always
ports:
- 7860
depends_on:
- postgres-langflow
environment:
- LANGFLOW_DATABASE_URL=postgresql://${DB_USERNAME}:${DB_PASSWORD}@postgres-langflow:5432/langflow
- # This variable defines where the logs, file storage, monitor data and secret keys are stored.
+ - LANGFLOW_CONFIG_DIR=/app/config
+ - LANGFLOW_SUPERUSER=email@domain.com
+ - LANGFLOW_SUPERUSER_PASSWORD=changepassword
+ - LANGFLOW_SECRET_KEY=PP_G4Gwm1lOkyG8r8N0LrdlpWXZ7Tyq5CVyfBquuj6g=
+ - DO_NOT_TRACK=True
+ - LANGFLOW_AUTO_SAVING=True
+ - LANGFLOW_AUTO_LOGIN=False
+ - LANGFLOW_NEW_USER_IS_ACTIVE=False
+ - LANGFLOW_ENABLE_SUPERUSER_CLI=False
volumes:
- - langflow-data:/app/langflow
-
-
+ - app-data:/app/langflow
+ - app-config:/app/config
+
postgres-langflow:
image: postgres:16
+ restart: always
+ healthcheck:
+ test: ["CMD-SHELL", "pg_isready -U ${DB_USERNAME} -d langflow"]
+ interval: 3s
+ timeout: 3s
+ retries: 10
environment:
POSTGRES_USER: ${DB_USERNAME}
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_DB: langflow
- ports:
- - 5432
volumes:
- - langflow-postgres:/var/lib/postgresql/data
-
+ - postgres-data:/var/lib/postgresql/data
volumes:
- langflow-postgres:
- langflow-data:
\ No newline at end of file
+ postgres-data:
+ app-data:
+ app-config:
diff --git a/blueprints/libredb-studio/docker-compose.yml b/blueprints/libredb-studio/docker-compose.yml
new file mode 100644
index 00000000..00b88766
--- /dev/null
+++ b/blueprints/libredb-studio/docker-compose.yml
@@ -0,0 +1,17 @@
+version: "3.8"
+services:
+ libredb-studio:
+ image: ghcr.io/libredb/libredb-studio:0.9.27
+ restart: unless-stopped
+ environment:
+ - ADMIN_EMAIL=admin@libredb.org
+ - ADMIN_PASSWORD=${ADMIN_PASSWORD}
+ - USER_EMAIL=user@libredb.org
+ - USER_PASSWORD=${USER_PASSWORD}
+ - JWT_SECRET=${JWT_SECRET}
+ - STORAGE_PROVIDER=sqlite
+ - STORAGE_SQLITE_PATH=/app/data/libredb-storage.db
+ volumes:
+ - libredb-data:/app/data
+volumes:
+ libredb-data:
diff --git a/blueprints/libredb-studio/libredb-studio.svg b/blueprints/libredb-studio/libredb-studio.svg
new file mode 100644
index 00000000..c36a98eb
--- /dev/null
+++ b/blueprints/libredb-studio/libredb-studio.svg
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/blueprints/libredb-studio/template.toml b/blueprints/libredb-studio/template.toml
new file mode 100644
index 00000000..9d30084d
--- /dev/null
+++ b/blueprints/libredb-studio/template.toml
@@ -0,0 +1,18 @@
+[variables]
+admin_password = "${password:32}"
+user_password = "${password:32}"
+jwt_secret = "${password:64}"
+
+[config]
+[[config.domains]]
+serviceName = "libredb-studio"
+port = 3000
+
+[[config.env]]
+ADMIN_PASSWORD = "${admin_password}"
+
+[[config.env]]
+USER_PASSWORD = "${user_password}"
+
+[[config.env]]
+JWT_SECRET = "${jwt_secret}"
diff --git a/blueprints/librespeed/docker-compose.yml b/blueprints/librespeed/docker-compose.yml
new file mode 100644
index 00000000..2f7e8bc1
--- /dev/null
+++ b/blueprints/librespeed/docker-compose.yml
@@ -0,0 +1,20 @@
+version: "3.8"
+
+services:
+ librespeed:
+ image: lscr.io/linuxserver/librespeed:latest
+ restart: unless-stopped
+ expose:
+ - 80
+ volumes:
+ - librespeed-config:/config
+ environment:
+ - PUID=1000
+ - PGID=1000
+ - TZ=${TZ}
+ - PASSWORD=${PASSWORD}
+ - CUSTOM_RESULTS=${CUSTOM_RESULTS}
+ - DB_TYPE=sqlite
+
+volumes:
+ librespeed-config:
diff --git a/blueprints/librespeed/librespeed.svg b/blueprints/librespeed/librespeed.svg
new file mode 100644
index 00000000..c76c99ec
--- /dev/null
+++ b/blueprints/librespeed/librespeed.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/blueprints/librespeed/template.toml b/blueprints/librespeed/template.toml
new file mode 100644
index 00000000..b8ed3e13
--- /dev/null
+++ b/blueprints/librespeed/template.toml
@@ -0,0 +1,14 @@
+[variables]
+main_domain = "${domain}"
+password = "${password:32}"
+
+[config]
+[[config.domains]]
+serviceName = "librespeed"
+port = 80
+host = "${main_domain}"
+
+[config.env]
+PASSWORD = "${password}"
+TZ = "UTC"
+CUSTOM_RESULTS = "false"
diff --git a/blueprints/limesurvey/docker-compose.yml b/blueprints/limesurvey/docker-compose.yml
new file mode 100644
index 00000000..936e5199
--- /dev/null
+++ b/blueprints/limesurvey/docker-compose.yml
@@ -0,0 +1,40 @@
+version: "3.8"
+
+services:
+ db:
+ image: mariadb:10.11
+ restart: always
+ volumes:
+ - db_data:/var/lib/mysql
+ environment:
+ - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
+ - MYSQL_DATABASE=limesurvey
+ - MYSQL_USER=limesurvey
+ - MYSQL_PASSWORD=${MYSQL_PASSWORD}
+
+ limesurvey:
+ image: martialblog/limesurvey:latest
+ restart: always
+ volumes:
+ - limesurvey_upload:/var/www/html/upload
+ environment:
+ - ADMIN_EMAIL=${ADMIN_EMAIL}
+ - ADMIN_NAME=Admin
+ - ADMIN_USER=admin
+ - ADMIN_PASSWORD=${ADMIN_PASSWORD}
+ - DB_HOST=db
+ - DB_MYSQL_ENGINE=InnoDB
+ - DB_NAME=limesurvey
+ - DB_PASSWORD=${MYSQL_PASSWORD}
+ - DB_USERNAME=limesurvey
+ - DEBUG=0
+ - DEBUG_SQL=0
+ - PUBLIC_URL=${PUBLIC_URL}
+ - SHOW_SCRIPT_NAME=false
+ - URL_FORMAT=path
+ depends_on:
+ - db
+
+volumes:
+ db_data:
+ limesurvey_upload:
diff --git a/blueprints/limesurvey/limesurvey.svg b/blueprints/limesurvey/limesurvey.svg
new file mode 100644
index 00000000..9ee4c0c6
--- /dev/null
+++ b/blueprints/limesurvey/limesurvey.svg
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/blueprints/limesurvey/template.toml b/blueprints/limesurvey/template.toml
new file mode 100644
index 00000000..07623f50
--- /dev/null
+++ b/blueprints/limesurvey/template.toml
@@ -0,0 +1,19 @@
+[variables]
+main_domain = "${domain}"
+mysql_root_password = "${password:32}"
+mysql_user_password = "${password:32}"
+admin_email = "${email}"
+admin_password = "${password:32}"
+
+[config]
+[[config.domains]]
+serviceName = "limesurvey"
+port = 8080
+host = "${main_domain}"
+
+[config.env]
+PUBLIC_URL = "http://${main_domain}"
+ADMIN_EMAIL = "${admin_email}"
+ADMIN_PASSWORD = "${admin_password}"
+MYSQL_PASSWORD = "${mysql_user_password}"
+MYSQL_ROOT_PASSWORD = "${mysql_root_password}"
diff --git a/blueprints/lubelogger/docker-compose.yml b/blueprints/lubelogger/docker-compose.yml
new file mode 100644
index 00000000..535b8e55
--- /dev/null
+++ b/blueprints/lubelogger/docker-compose.yml
@@ -0,0 +1,20 @@
+version: "3.8"
+
+services:
+ lubelogger:
+ image: ghcr.io/hargata/lubelogger:v1.6.5
+ restart: unless-stopped
+ environment:
+ - LC_ALL=${LUBELOGGER_LOCALE}
+ - LANG=${LUBELOGGER_LOCALE}
+ - LUBELOGGER_DOMAIN=${LUBELOGGER_DOMAIN}
+ - EnableAuth=${LUBELOGGER_ENABLE_AUTH}
+ volumes:
+ - lubelogger-data:/App/data
+ - lubelogger-keys:/root/.aspnet/DataProtection-Keys
+ expose:
+ - 8080
+
+volumes:
+ lubelogger-data: {}
+ lubelogger-keys: {}
diff --git a/blueprints/lubelogger/lubelogger.png b/blueprints/lubelogger/lubelogger.png
new file mode 100644
index 00000000..b3713e80
Binary files /dev/null and b/blueprints/lubelogger/lubelogger.png differ
diff --git a/blueprints/lubelogger/template.toml b/blueprints/lubelogger/template.toml
new file mode 100644
index 00000000..4ff28963
--- /dev/null
+++ b/blueprints/lubelogger/template.toml
@@ -0,0 +1,18 @@
+[variables]
+main_domain = "${domain}"
+lubelogger_locale = "en_US.UTF-8"
+lubelogger_enable_auth = "false"
+lubelogger_domain = "https://${main_domain}"
+
+[config]
+mounts = []
+
+[[config.domains]]
+serviceName = "lubelogger"
+port = 8080
+host = "${main_domain}"
+
+[config.env]
+LUBELOGGER_LOCALE = "${lubelogger_locale}"
+LUBELOGGER_ENABLE_AUTH = "${lubelogger_enable_auth}"
+LUBELOGGER_DOMAIN = "${lubelogger_domain}"
diff --git a/blueprints/marketing-dashboard/docker-compose.yml b/blueprints/marketing-dashboard/docker-compose.yml
new file mode 100644
index 00000000..637849e7
--- /dev/null
+++ b/blueprints/marketing-dashboard/docker-compose.yml
@@ -0,0 +1,47 @@
+services:
+ marketing-dashboard:
+ image: ghcr.io/abel-yelin/marketing-dashboard:latest
+ restart: unless-stopped
+ depends_on:
+ postgres:
+ condition: service_healthy
+ environment:
+ DATABASE_URL: ${DATABASE_URL}
+ DIRECT_URL: ${DIRECT_URL}
+ MARKETING_APP_URL: ${MARKETING_APP_URL}
+ MARKETING_COLLECTOR_UPSTREAM_URL: ${MARKETING_COLLECTOR_UPSTREAM_URL}
+ MARKETING_SESSION_TIMEOUT_MINUTES: ${MARKETING_SESSION_TIMEOUT_MINUTES}
+ MARKETING_PROXY_TIMEOUT_MS: ${MARKETING_PROXY_TIMEOUT_MS}
+ MARKETING_INGEST_MAX_BODY_BYTES: ${MARKETING_INGEST_MAX_BODY_BYTES}
+ MARKETING_INGEST_IP_RATE_LIMIT: ${MARKETING_INGEST_IP_RATE_LIMIT}
+ MARKETING_INGEST_CLIENT_RATE_LIMIT: ${MARKETING_INGEST_CLIENT_RATE_LIMIT}
+ MARKETING_INGEST_RATE_LIMIT_WINDOW_MS: ${MARKETING_INGEST_RATE_LIMIT_WINDOW_MS}
+ MARKETING_ENABLE_PILOT_API: ${MARKETING_ENABLE_PILOT_API}
+ MARKETING_DASHBOARD_ADMIN_USER: ${MARKETING_DASHBOARD_ADMIN_USER}
+ MARKETING_DASHBOARD_ADMIN_PASSWORD: ${MARKETING_DASHBOARD_ADMIN_PASSWORD}
+ ports:
+ - 3000
+ healthcheck:
+ test: ["CMD-SHELL", "curl -fsS http://localhost:3000/api/health > /dev/null || exit 1"]
+ interval: 15s
+ timeout: 5s
+ retries: 10
+ start_period: 30s
+
+ postgres:
+ image: postgres:16
+ restart: unless-stopped
+ environment:
+ POSTGRES_DB: ${POSTGRES_DB}
+ POSTGRES_USER: ${POSTGRES_USER}
+ POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
+ volumes:
+ - marketing-dashboard-postgres:/var/lib/postgresql/data
+ healthcheck:
+ test: ["CMD-SHELL", "pg_isready -U \"$${POSTGRES_USER}\" -d \"$${POSTGRES_DB}\""]
+ interval: 10s
+ timeout: 5s
+ retries: 10
+
+volumes:
+ marketing-dashboard-postgres:
diff --git a/blueprints/marketing-dashboard/logo.svg b/blueprints/marketing-dashboard/logo.svg
new file mode 100644
index 00000000..07a4ae88
--- /dev/null
+++ b/blueprints/marketing-dashboard/logo.svg
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/blueprints/marketing-dashboard/template.toml b/blueprints/marketing-dashboard/template.toml
new file mode 100644
index 00000000..531874ea
--- /dev/null
+++ b/blueprints/marketing-dashboard/template.toml
@@ -0,0 +1,30 @@
+[variables]
+main_domain = "${domain}"
+postgres_password = "${password:32}"
+admin_password = "${password:32}"
+
+[config]
+mounts = []
+
+[[config.domains]]
+serviceName = "marketing-dashboard"
+port = 3000
+host = "${main_domain}"
+
+[config.env]
+POSTGRES_DB = "marketing_dashboard"
+POSTGRES_USER = "marketing_dashboard"
+POSTGRES_PASSWORD = "${postgres_password}"
+DATABASE_URL = "postgresql://marketing_dashboard:${postgres_password}@postgres:5432/marketing_dashboard?schema=public"
+DIRECT_URL = "postgresql://marketing_dashboard:${postgres_password}@postgres:5432/marketing_dashboard?schema=public"
+MARKETING_APP_URL = "https://${main_domain}"
+MARKETING_COLLECTOR_UPSTREAM_URL = "https://${main_domain}/api/ingest/browser"
+MARKETING_SESSION_TIMEOUT_MINUTES = "30"
+MARKETING_PROXY_TIMEOUT_MS = "4000"
+MARKETING_INGEST_MAX_BODY_BYTES = "65536"
+MARKETING_INGEST_IP_RATE_LIMIT = "300"
+MARKETING_INGEST_CLIENT_RATE_LIMIT = "1200"
+MARKETING_INGEST_RATE_LIMIT_WINDOW_MS = "60000"
+MARKETING_ENABLE_PILOT_API = "false"
+MARKETING_DASHBOARD_ADMIN_USER = "admin"
+MARKETING_DASHBOARD_ADMIN_PASSWORD = "${admin_password}"
diff --git a/blueprints/maxio/docker-compose.yml b/blueprints/maxio/docker-compose.yml
new file mode 100644
index 00000000..51a826b2
--- /dev/null
+++ b/blueprints/maxio/docker-compose.yml
@@ -0,0 +1,15 @@
+version: "3.8"
+
+services:
+ maxio:
+ image: ghcr.io/coollabsio/maxio:0.2.1
+ expose:
+ - 9000
+ volumes:
+ - maxio-data:/data
+ environment:
+ - MAXIO_ACCESS_KEY=${MAXIO_ACCESS_KEY}
+ - MAXIO_SECRET_KEY=${MAXIO_SECRET_KEY}
+ restart: unless-stopped
+volumes:
+ maxio-data:
diff --git a/blueprints/maxio/maxio.svg b/blueprints/maxio/maxio.svg
new file mode 100644
index 00000000..0121fc4a
--- /dev/null
+++ b/blueprints/maxio/maxio.svg
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/blueprints/maxio/template.toml b/blueprints/maxio/template.toml
new file mode 100644
index 00000000..42e1087d
--- /dev/null
+++ b/blueprints/maxio/template.toml
@@ -0,0 +1,10 @@
+[[config.domains]]
+serviceName = "maxio"
+port = 9000
+host = "${domain}"
+
+[config]
+env = [
+ "MAXIO_ACCESS_KEY=${password:20}",
+ "MAXIO_SECRET_KEY=${password:20}",
+]
diff --git a/blueprints/mediafetch/docker-compose.yml b/blueprints/mediafetch/docker-compose.yml
index f0c690cd..17ba6176 100644
--- a/blueprints/mediafetch/docker-compose.yml
+++ b/blueprints/mediafetch/docker-compose.yml
@@ -1,7 +1,7 @@
version: "3.8"
services:
mediafetch:
- image: lukedunsmoto/mediafetch:latest
+ image: lukedunsmoto/mediafetch:1.3.5
restart: unless-stopped
expose:
- "3002"
@@ -11,8 +11,11 @@ services:
- PORT=3002
- BASIC_AUTH_USER=${BASIC_AUTH_USER}
- BASIC_AUTH_PASS=${BASIC_AUTH_PASS}
- - PUBLIC_BASE_URL=https://${DOMAIN}
- - OUTPUT_DIR=/data/downloads
+ - PUBLIC_BASE_URL=${PUBLIC_BASE_URL}
+ - OUTPUT_DIR=${OUTPUT_DIR}
+ - MAX_CONCURRENT_JOBS=${MAX_CONCURRENT_JOBS}
+ - JOB_TIMEOUT_MS=${JOB_TIMEOUT_MS}
+ - VERSION_CHECK_TTL_MS=${VERSION_CHECK_TTL_MS}
volumes:
mediafetch_data:
\ No newline at end of file
diff --git a/blueprints/mediafetch/template.toml b/blueprints/mediafetch/template.toml
index 07672d4e..791bd07f 100644
--- a/blueprints/mediafetch/template.toml
+++ b/blueprints/mediafetch/template.toml
@@ -1,13 +1,21 @@
[variables]
+main_domain = "${domain}"
+PORT="3002"
+PUBLIC_BASE_URL="https://${main_domain}"
+OUTPUT_DIR="/data/downloads"
BASIC_AUTH_USER = "admin"
-BASIC_AUTH_PASS = "${password:12}"
+BASIC_AUTH_PASS = "changeme"
+MAX_CONCURRENT_JOBS="2"
+JOB_TIMEOUT_MS="600000"
+VERSION_CHECK_TTL_MS="21600000"
[config]
+
[[config.domains]]
name = "Domain"
-variable = "DOMAIN"
serviceName = "mediafetch"
-port = 3002
+port = "3002"
+host = "${main_domain}"
[[config.mounts]]
name = "Downloads"
diff --git a/blueprints/miniflux/docker-compose.yml b/blueprints/miniflux/docker-compose.yml
new file mode 100644
index 00000000..874021ac
--- /dev/null
+++ b/blueprints/miniflux/docker-compose.yml
@@ -0,0 +1,45 @@
+version: "3.8"
+
+services:
+ miniflux:
+ image: miniflux/miniflux:2.2.19
+ restart: unless-stopped
+ depends_on:
+ db:
+ condition: service_healthy
+ environment:
+ DATABASE_URL: user=miniflux password=${POSTGRES_PASSWORD} dbname=miniflux host=db sslmode=disable
+ RUN_MIGRATIONS: "1"
+ CREATE_ADMIN: "1"
+ ADMIN_USERNAME: ${ADMIN_USERNAME}
+ ADMIN_PASSWORD: ${ADMIN_PASSWORD}
+ BASE_URL: https://${MINIFLUX_DOMAIN}
+ expose:
+ - "8080"
+ healthcheck:
+ test: ["CMD", "/usr/bin/miniflux", "-healthcheck", "auto"]
+ interval: 30s
+ timeout: 10s
+ retries: 3
+ start_period: 30s
+
+ db:
+ image: postgres:18-alpine
+ restart: unless-stopped
+ environment:
+ POSTGRES_USER: miniflux
+ POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
+ POSTGRES_DB: miniflux
+ expose:
+ - "5432"
+ volumes:
+ - miniflux-db:/var/lib/postgresql
+ healthcheck:
+ test: ["CMD-SHELL", "pg_isready -U miniflux -d miniflux"]
+ interval: 10s
+ timeout: 5s
+ retries: 5
+ start_period: 30s
+
+volumes:
+ miniflux-db:
diff --git a/blueprints/miniflux/miniflux.svg b/blueprints/miniflux/miniflux.svg
new file mode 100644
index 00000000..3537ce7e
--- /dev/null
+++ b/blueprints/miniflux/miniflux.svg
@@ -0,0 +1 @@
+
diff --git a/blueprints/miniflux/template.toml b/blueprints/miniflux/template.toml
new file mode 100644
index 00000000..d6f553f7
--- /dev/null
+++ b/blueprints/miniflux/template.toml
@@ -0,0 +1,17 @@
+[variables]
+main_domain = "${domain}"
+postgres_password = "${password:32}"
+admin_username = "admin"
+admin_password = "${password:32}"
+
+[config]
+[[config.domains]]
+serviceName = "miniflux"
+port = 8080
+host = "${main_domain}"
+
+[config.env]
+MINIFLUX_DOMAIN = "${main_domain}"
+POSTGRES_PASSWORD = "${postgres_password}"
+ADMIN_USERNAME = "${admin_username}"
+ADMIN_PASSWORD = "${admin_password}"
diff --git a/blueprints/nextcloud-aio/docker-compose.yml b/blueprints/nextcloud-aio/docker-compose.yml
index 9cec8542..7550c252 100644
--- a/blueprints/nextcloud-aio/docker-compose.yml
+++ b/blueprints/nextcloud-aio/docker-compose.yml
@@ -14,6 +14,21 @@ services:
- nextcloud_db
- nextcloud_redis
+ nextcloud_cron:
+ image: nextcloud:stable
+ restart: always
+ volumes:
+ - nextcloud_data:/var/www/html
+ environment:
+ - MYSQL_HOST=nextcloud_db
+ - MYSQL_DATABASE=nextcloud
+ - MYSQL_USER=nextcloud
+ - MYSQL_PASSWORD=${MYSQL_PASSWORD}
+ entrypoint: /cron.sh
+ depends_on:
+ - nextcloud_db
+ - nextcloud_redis
+
nextcloud_db:
image: mariadb:10.11
restart: always
@@ -31,4 +46,4 @@ services:
volumes:
nextcloud_data:
- nextcloud_db_data:
\ No newline at end of file
+ nextcloud_db_data:
diff --git a/blueprints/omniroute/docker-compose.yml b/blueprints/omniroute/docker-compose.yml
new file mode 100644
index 00000000..552c8f26
--- /dev/null
+++ b/blueprints/omniroute/docker-compose.yml
@@ -0,0 +1,40 @@
+services:
+ omniroute:
+ image: diegosouzapw/omniroute:3.8.17
+ restart: unless-stopped
+
+ expose:
+ - "20128"
+ - "20129"
+
+ volumes:
+ - omniroute-prod-data:/app/data
+
+ environment:
+ - NODE_ENV=production
+ - PORT=${PORT:-20128}
+ - DASHBOARD_PORT=${DASHBOARD_PORT:-${PORT:-20128}}
+ - API_PORT=${API_PORT:-20129}
+ - API_HOST=${API_HOST:-0.0.0.0}
+ - HOSTNAME=0.0.0.0
+ - DATA_DIR=/app/data
+ - PATH=/home/node/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
+
+ redis:
+ image: redis:8.6.2-alpine
+ restart: unless-stopped
+ volumes:
+ - redis-prod-data:/data
+ command: redis-server --save 60 1 --loglevel warning
+ healthcheck:
+ test: [ "CMD", "redis-cli", "ping" ]
+ interval: 10s
+ timeout: 5s
+ retries: 3
+
+volumes:
+ omniroute-prod-data:
+
+ redis-prod-data:
+
+
diff --git a/blueprints/omniroute/omniroute.png b/blueprints/omniroute/omniroute.png
new file mode 100644
index 00000000..4d4a0d14
Binary files /dev/null and b/blueprints/omniroute/omniroute.png differ
diff --git a/blueprints/omniroute/template.toml b/blueprints/omniroute/template.toml
new file mode 100644
index 00000000..ae4a61e0
--- /dev/null
+++ b/blueprints/omniroute/template.toml
@@ -0,0 +1,31 @@
+[variables]
+main_domain = "${domain}"
+
+[config]
+[[config.domains]]
+serviceName = "omniroute"
+port = 20128
+host = "${main_domain}"
+
+[config.env]
+JWT_SECRET = "${base64:64}"
+API_KEY_SECRET = "${base64:64}"
+INITIAL_PASSWORD = "${base64:64}"
+STORAGE_ENCRYPTION_KEY = "${base64:64}"
+STORAGE_ENCRYPTION_KEY_VERSION = "v1"
+DISABLE_SQLITE_AUTO_BACKUP = false
+PORT = 20128
+API_PORT = 20129
+OMNIROUTE_USE_TURBOPACK = 1
+NODE_ENV = "production"
+MACHINE_ID_SALT = "endpoint-proxy-salt"
+AUTH_COOKIE_SECURE = false
+REQUIRE_API_KEY = false
+ALLOW_API_KEY_REVEAL = false
+BASE_URL = "http://localhost:20128"
+CLOUD_URL = ""
+NEXT_PUBLIC_BASE_URL = "http://localhost:20128"
+ENABLE_SOCKS5_PROXY = true
+NEXT_PUBLIC_ENABLE_SOCKS5_PROXY = true
+PROVIDER_LIMITS_SYNC_INTERVAL_MINUTES = 70
+APP_LOG_TO_FILE = true
diff --git a/blueprints/openobserve/docker-compose.yml b/blueprints/openobserve/docker-compose.yml
new file mode 100644
index 00000000..442ec844
--- /dev/null
+++ b/blueprints/openobserve/docker-compose.yml
@@ -0,0 +1,18 @@
+version: "3.8"
+
+services:
+ openobserve:
+ image: public.ecr.aws/zinclabs/openobserve:v0.70.0
+ restart: unless-stopped
+ environment:
+ ZO_ROOT_USER_EMAIL: ${ZO_ROOT_USER_EMAIL}
+ ZO_ROOT_USER_PASSWORD: ${ZO_ROOT_USER_PASSWORD}
+ ZO_DATA_DIR: ${ZO_DATA_DIR}
+ expose:
+ - 5080
+ - 5081
+ volumes:
+ - data:${ZO_DATA_DIR}
+
+volumes:
+ data:
diff --git a/blueprints/openobserve/openobserve.svg b/blueprints/openobserve/openobserve.svg
new file mode 100644
index 00000000..e189fa50
--- /dev/null
+++ b/blueprints/openobserve/openobserve.svg
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/blueprints/openobserve/template.toml b/blueprints/openobserve/template.toml
new file mode 100644
index 00000000..58a7b09a
--- /dev/null
+++ b/blueprints/openobserve/template.toml
@@ -0,0 +1,17 @@
+[variables]
+main_domain = "${domain}"
+root_email = "${email}"
+root_password = "${password:32}"
+
+[config]
+env = [
+ "ZO_ROOT_USER_EMAIL=${root_email}",
+ "ZO_ROOT_USER_PASSWORD=${root_password}",
+ "ZO_DATA_DIR=/data",
+]
+mounts = []
+
+[[config.domains]]
+serviceName = "openobserve"
+port = 5080
+host = "${main_domain}"
diff --git a/blueprints/opensourcepos/docker-compose.yml b/blueprints/opensourcepos/docker-compose.yml
new file mode 100644
index 00000000..95d58960
--- /dev/null
+++ b/blueprints/opensourcepos/docker-compose.yml
@@ -0,0 +1,45 @@
+version: "3.8"
+
+services:
+ opensourcepos:
+ image: jekkos/opensourcepos:master
+ restart: unless-stopped
+ depends_on:
+ opensourcepos-db:
+ condition: service_healthy
+ expose:
+ - "80"
+ environment:
+ CI_ENVIRONMENT: production
+ ALLOWED_HOSTNAMES: ${ALLOWED_HOSTNAMES}
+ FORCE_HTTPS: ${FORCE_HTTPS}
+ PHP_TIMEZONE: ${PHP_TIMEZONE}
+ MYSQL_USERNAME: ${MYSQL_USER}
+ MYSQL_PASSWORD: ${MYSQL_PASSWORD}
+ MYSQL_DB_NAME: ${MYSQL_DATABASE}
+ MYSQL_HOST_NAME: opensourcepos-db
+ volumes:
+ - opensourcepos-uploads:/app/public/uploads
+ - opensourcepos-logs:/app/writable/logs
+
+ opensourcepos-db:
+ image: mariadb:10.11
+ restart: unless-stopped
+ environment:
+ MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
+ MYSQL_DATABASE: ${MYSQL_DATABASE}
+ MYSQL_USER: ${MYSQL_USER}
+ MYSQL_PASSWORD: ${MYSQL_PASSWORD}
+ volumes:
+ - opensourcepos-db:/var/lib/mysql
+ healthcheck:
+ test: ["CMD-SHELL", "healthcheck.sh --connect --innodb_initialized"]
+ interval: 10s
+ timeout: 5s
+ retries: 5
+ start_period: 30s
+
+volumes:
+ opensourcepos-db:
+ opensourcepos-uploads:
+ opensourcepos-logs:
diff --git a/blueprints/opensourcepos/opensourcepos.svg b/blueprints/opensourcepos/opensourcepos.svg
new file mode 100644
index 00000000..d63b2009
--- /dev/null
+++ b/blueprints/opensourcepos/opensourcepos.svg
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/blueprints/opensourcepos/template.toml b/blueprints/opensourcepos/template.toml
new file mode 100644
index 00000000..d925ad0c
--- /dev/null
+++ b/blueprints/opensourcepos/template.toml
@@ -0,0 +1,51 @@
+[variables]
+main_domain = "${domain}"
+mysql_root_password = "${password:32}"
+mysql_password = "${password:32}"
+php_timezone = "UTC"
+force_https = "false"
+allowed_hostnames = "${main_domain}"
+
+[[config.domains]]
+serviceName = "opensourcepos"
+port = 80
+host = "${main_domain}"
+path = "/"
+
+[[config.mounts]]
+filePath = "README.md"
+content = """# OpenSourcePOS
+
+This template deploys Open Source Point of Sale with MariaDB using the upstream Docker image and persistent storage for uploads, logs, and database data.
+
+## Access
+
+- URL: `http://${main_domain}`
+- Default application user: `admin`
+- Default application password: `pointofsale`
+
+Change the default application password immediately after the first login.
+
+## Hostnames and HTTPS
+
+OpenSourcePOS validates incoming host headers in production. The `allowed_hostnames` variable defaults to `${main_domain}` and can be set to a comma-separated list such as `pos.example.com,www.pos.example.com`.
+
+The template defaults `force_https` to `false` because Dokploy terminates TLS outside the container. Set it to `true` only when your deployment always reaches OpenSourcePOS through HTTPS and the reverse proxy sends the expected headers.
+
+## Storage
+
+The template creates persistent volumes for:
+
+- MariaDB data
+- uploaded files
+- application logs
+"""
+
+[config.env]
+MYSQL_ROOT_PASSWORD = "${mysql_root_password}"
+MYSQL_DATABASE = "ospos"
+MYSQL_USER = "admin"
+MYSQL_PASSWORD = "${mysql_password}"
+PHP_TIMEZONE = "${php_timezone}"
+FORCE_HTTPS = "${force_https}"
+ALLOWED_HOSTNAMES = "${allowed_hostnames}"
diff --git a/blueprints/outline/docker-compose.yml b/blueprints/outline/docker-compose.yml
index aaf98ac0..9f726040 100644
--- a/blueprints/outline/docker-compose.yml
+++ b/blueprints/outline/docker-compose.yml
@@ -12,18 +12,36 @@ services:
NODE_ENV: production
URL: ${URL}
FORCE_HTTPS: 'false'
+ PROXY_HEADERS_TRUSTED: 'true'
SECRET_KEY: ${SECRET_KEY}
UTILS_SECRET: ${UTILS_SECRET}
DATABASE_URL: postgres://outline:${POSTGRES_PASSWORD}@postgres:5432/outline
PGSSLMODE: disable
REDIS_URL: redis://redis:6379
+ FILE_STORAGE: local
+ FILE_STORAGE_LOCAL_ROOT_DIR: /var/lib/outline/data
OIDC_CLIENT_ID: outline
OIDC_CLIENT_SECRET: ${CLIENT_SECRET}
OIDC_AUTH_URI: ${DEX_URL}/auth
OIDC_TOKEN_URI: ${DEX_URL}/token
OIDC_USERINFO_URI: ${DEX_URL}/userinfo
+ OIDC_USERNAME_CLAIM: preferred_username
+ OIDC_DISPLAY_NAME: OpenID Connect
+ OIDC_SCOPES: openid profile email
+ volumes:
+ - outline_data-test-outline-khufpx:/var/lib/outline/data
dex:
+ image: nginx:1.27-alpine
+ restart: always
+ depends_on:
+ - dex-server
+ volumes:
+ - ../files/etc/nginx/conf.d/default.conf:/etc/nginx/conf.d/default.conf
+ ports:
+ - 5556
+
+ dex-server:
image: ghcr.io/dexidp/dex:v2.37.0
restart: always
volumes:
@@ -32,8 +50,6 @@ services:
- dex
- serve
- /etc/dex/config.yaml
- ports:
- - 5556
postgres:
image: postgres:15
@@ -53,5 +69,6 @@ services:
- redis_data-test-outline-khufpx:/data
volumes:
+ outline_data-test-outline-khufpx:
postgres_data-test-outline-khufpx:
- redis_data-test-outline-khufpx:
\ No newline at end of file
+ redis_data-test-outline-khufpx:
diff --git a/blueprints/outline/template.toml b/blueprints/outline/template.toml
index e4f86738..a38a16e0 100644
--- a/blueprints/outline/template.toml
+++ b/blueprints/outline/template.toml
@@ -1,6 +1,6 @@
[variables]
main_domain = "${domain}"
-dex_domain = "${domain}"
+dex_domain = "dex-${domain}"
secret_key = "${hash:64}"
utils_secret = "${base64:32}"
client_secret = "${base64:32}"
@@ -17,8 +17,8 @@ port = 5_556
host = "${dex_domain}"
[config.env]
-URL = "http://${main_domain}"
-DEX_URL = "http://${dex_domain}"
+URL = "https://${main_domain}"
+DEX_URL = "https://${dex_domain}"
DOMAIN_NAME = "${main_domain}"
POSTGRES_PASSWORD = "${postgres_password}"
SECRET_KEY = "${secret_key}"
@@ -28,7 +28,7 @@ CLIENT_SECRET = "${client_secret}"
[[config.mounts]]
filePath = "/etc/dex/config.yaml"
content = """
-issuer: http://${dex_domain}
+issuer: https://${dex_domain}
web:
http: 0.0.0.0:5556
@@ -60,7 +60,28 @@ oauth2:
staticClients:
- id: "outline"
redirectURIs:
- - http://${main_domain}/auth/oidc.callback
+ - https://${main_domain}/auth/oidc.callback
name: "Outline"
secret: "${client_secret}"
"""
+
+[[config.mounts]]
+filePath = "/etc/nginx/conf.d/default.conf"
+content = """
+server {
+ listen 5556;
+
+ location = / {
+ add_header Content-Type text/plain;
+ return 200 "Dex ready\n";
+ }
+
+ location / {
+ proxy_pass http://dex-server:5556;
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ }
+}
+"""
diff --git a/blueprints/paperclip/README.md b/blueprints/paperclip/README.md
new file mode 100644
index 00000000..2ccae853
--- /dev/null
+++ b/blueprints/paperclip/README.md
@@ -0,0 +1,15 @@
+# Paperclip
+
+Paperclip is an open-source control plane for managing teams of AI agents, goals, budgets, tickets, and recurring work.
+
+This Dokploy template includes:
+
+- Paperclip web/API service using the official GHCR image
+- PostgreSQL 17 database with health check
+- Generated `BETTER_AUTH_SECRET`
+- Generated database password
+- Persistent `/paperclip` storage for instance data
+- Public URL configured from the Dokploy domain
+- Dokploy domain routing to Paperclip on port 3100
+
+After deployment, check the Paperclip container logs for first-run setup or invite information.
\ No newline at end of file
diff --git a/blueprints/paperclip/docker-compose.yml b/blueprints/paperclip/docker-compose.yml
new file mode 100644
index 00000000..5c1ce7bf
--- /dev/null
+++ b/blueprints/paperclip/docker-compose.yml
@@ -0,0 +1,44 @@
+version: "3.8"
+
+services:
+ postgres:
+ image: postgres:17-alpine
+ restart: unless-stopped
+ environment:
+ POSTGRES_USER: paperclip
+ POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
+ POSTGRES_DB: paperclip
+ healthcheck:
+ test: ["CMD-SHELL", "pg_isready -U paperclip -d paperclip"]
+ interval: 10s
+ timeout: 5s
+ retries: 10
+ volumes:
+ - postgres-data:/var/lib/postgresql/data
+
+ paperclip:
+ image: ghcr.io/paperclipai/paperclip:latest
+ restart: unless-stopped
+ depends_on:
+ postgres:
+ condition: service_healthy
+ environment:
+ HOST: 0.0.0.0
+ PORT: "3100"
+ SERVE_UI: "true"
+ DATABASE_URL: ${DATABASE_URL}
+ BETTER_AUTH_SECRET: ${BETTER_AUTH_SECRET}
+ PAPERCLIP_HOME: /paperclip
+ PAPERCLIP_INSTANCE_ID: default
+ PAPERCLIP_CONFIG: /paperclip/instances/default/config.json
+ PAPERCLIP_DEPLOYMENT_MODE: ${PAPERCLIP_DEPLOYMENT_MODE}
+ PAPERCLIP_DEPLOYMENT_EXPOSURE: ${PAPERCLIP_DEPLOYMENT_EXPOSURE}
+ PAPERCLIP_PUBLIC_URL: ${PAPERCLIP_PUBLIC_URL}
+ expose:
+ - "3100"
+ volumes:
+ - paperclip-data:/paperclip
+
+volumes:
+ postgres-data: {}
+ paperclip-data: {}
\ No newline at end of file
diff --git a/blueprints/paperclip/logo.svg b/blueprints/paperclip/logo.svg
new file mode 100644
index 00000000..44a8f649
--- /dev/null
+++ b/blueprints/paperclip/logo.svg
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/blueprints/paperclip/template.toml b/blueprints/paperclip/template.toml
new file mode 100644
index 00000000..6a79e07c
--- /dev/null
+++ b/blueprints/paperclip/template.toml
@@ -0,0 +1,20 @@
+[variables]
+main_domain = "${domain}"
+postgres_password = "${password:32}"
+better_auth_secret = "${password:64}"
+
+[config]
+env = [
+ "POSTGRES_PASSWORD=${postgres_password}",
+ "DATABASE_URL=postgres://paperclip:${postgres_password}@postgres:5432/paperclip",
+ "BETTER_AUTH_SECRET=${better_auth_secret}",
+ "PAPERCLIP_DEPLOYMENT_MODE=authenticated",
+ "PAPERCLIP_DEPLOYMENT_EXPOSURE=private",
+ "PAPERCLIP_PUBLIC_URL=https://${main_domain}"
+]
+mounts = []
+
+[[config.domains]]
+serviceName = "paperclip"
+port = 3100
+host = "${main_domain}"
\ No newline at end of file
diff --git a/blueprints/plane/docker-compose.yml b/blueprints/plane/docker-compose.yml
index 9502c010..a79f83d6 100644
--- a/blueprints/plane/docker-compose.yml
+++ b/blueprints/plane/docker-compose.yml
@@ -2,8 +2,8 @@ version: "3.8"
services:
web:
- image: makeplane/plane-frontend:${APP_RELEASE:-v0.27.1}
- command: node web/server.js web
+ image: makeplane/plane-frontend:${APP_RELEASE:-v1.2.3}
+ restart: always
depends_on:
- api
- worker
@@ -11,8 +11,8 @@ services:
- .env
space:
- image: makeplane/plane-space:${APP_RELEASE:-v0.27.1}
- command: node space/server.js space
+ image: makeplane/plane-space:${APP_RELEASE:-v1.2.3}
+ restart: always
depends_on:
- api
- worker
@@ -21,8 +21,8 @@ services:
- .env
admin:
- image: makeplane/plane-admin:${APP_RELEASE:-v0.27.1}
- command: node admin/server.js admin
+ image: makeplane/plane-admin:${APP_RELEASE:-v1.2.3}
+ restart: always
depends_on:
- api
- web
@@ -30,8 +30,8 @@ services:
- .env
live:
- image: makeplane/plane-live:${APP_RELEASE:-v0.27.1}
- command: node live/dist/server.js live
+ image: makeplane/plane-live:${APP_RELEASE:-v1.2.3}
+ restart: always
depends_on:
- api
- web
@@ -39,7 +39,8 @@ services:
- .env
api:
- image: makeplane/plane-backend:${APP_RELEASE:-v0.27.1}
+ image: makeplane/plane-backend:${APP_RELEASE:-v1.2.3}
+ restart: always
command: ./bin/docker-entrypoint-api.sh
volumes:
- logs_api:/code/plane/logs
@@ -51,7 +52,8 @@ services:
- .env
worker:
- image: makeplane/plane-backend:${APP_RELEASE:-v0.27.1}
+ image: makeplane/plane-backend:${APP_RELEASE:-v1.2.3}
+ restart: always
command: ./bin/docker-entrypoint-worker.sh
volumes:
- logs_worker:/code/plane/logs
@@ -64,7 +66,8 @@ services:
- .env
beat-worker:
- image: makeplane/plane-backend:${APP_RELEASE:-v0.27.1}
+ image: makeplane/plane-backend:${APP_RELEASE:-v1.2.3}
+ restart: always
command: ./bin/docker-entrypoint-beat.sh
volumes:
- logs_beat-worker:/code/plane/logs
@@ -77,7 +80,8 @@ services:
- .env
migrator:
- image: makeplane/plane-backend:${APP_RELEASE:-v0.27.1}
+ image: makeplane/plane-backend:${APP_RELEASE:-v1.2.3}
+ restart: on-failure
command: ./bin/docker-entrypoint-migrator.sh
volumes:
- logs_migrator:/code/plane/logs
@@ -88,7 +92,8 @@ services:
- .env
plane-db:
- image: postgres:17-alpine
+ image: postgres:15.7-alpine
+ restart: always
command: postgres -c 'max_connections=1000'
volumes:
- pgdata:/var/lib/postgresql/data
@@ -96,33 +101,39 @@ services:
- .env
plane-redis:
- image: valkey/valkey:7.2.5-alpine
+ image: valkey/valkey:7.2.11-alpine
+ restart: always
volumes:
- redisdata:/data
- env_file:
- - .env
plane-mq:
image: rabbitmq:3.13.6-management-alpine
+ restart: always
volumes:
- rabbitmq_data:/var/lib/rabbitmq
env_file:
- .env
- plane-minio:
- image: minio/minio:latest
- command: server /export --console-address ":9090"
+ plane-storage:
+ image: rustfs/rustfs:1.0.0-alpha.90
+ restart: always
volumes:
- - uploads:/export
+ - uploads:/data
env_file:
- .env
proxy:
- image: makeplane/plane-proxy:${APP_RELEASE:-v0.27.1}
+ image: makeplane/plane-proxy:${APP_RELEASE:-v1.2.3}
+ restart: always
depends_on:
- web
- api
- space
+ - admin
+ - live
+ volumes:
+ - proxy_config:/config
+ - proxy_data:/data
env_file:
- .env
@@ -135,3 +146,5 @@ volumes:
logs_beat-worker:
logs_migrator:
rabbitmq_data:
+ proxy_config:
+ proxy_data:
diff --git a/blueprints/plane/template.toml b/blueprints/plane/template.toml
index a12f4564..93607582 100644
--- a/blueprints/plane/template.toml
+++ b/blueprints/plane/template.toml
@@ -1,53 +1,59 @@
[variables]
main_domain = "${domain}"
+postgres_user = "${username}"
db_password = "${password:32}"
-minio_password = "${password:32}"
+storage_password = "${password:32}"
rabbitmq_user = "${username}"
rabbitmq_pass = "${password:32}"
secret_key = "${base64:48}"
+live_secret_key = "${base64:32}"
[config]
env = [
-"Domain=${domain}",
-"WEB_URL=${Domain}",
+"APP_DOMAIN=${main_domain}",
+"WEB_URL=http://${main_domain}",
"PGHOST=plane-db",
"PGDATABASE=plane",
-"POSTGRES_USER=${username}",
+"POSTGRES_USER=${postgres_user}",
"POSTGRES_PASSWORD=${db_password}",
"POSTGRES_DB=plane",
"POSTGRES_PORT=5432",
"PGDATA=/var/lib/postgresql/data",
+"DATABASE_URL=postgresql://${postgres_user}:${db_password}@plane-db/plane",
"REDIS_HOST=plane-redis",
"REDIS_PORT=6379",
"REDIS_URL=redis://plane-redis:6379/",
-"MINIO_ROOT_USER=access-key",
-"MINIO_ROOT_PASSWORD=${minio_password}",
+"RUSTFS_ACCESS_KEY=access-key",
+"RUSTFS_SECRET_KEY=${storage_password}",
+"RUSTFS_VOLUMES=/data",
+"RUSTFS_ADDRESS=0.0.0.0:9000",
+"RUSTFS_CONSOLE_ENABLE=false",
"AWS_REGION=",
-"AWS_ACCESS_KEY_ID=${MINIO_ROOT_USER}",
-"AWS_SECRET_ACCESS_KEY=${minio_password}",
-"AWS_S3_ENDPOINT_URL=http://plane-minio:9000",
+"AWS_ACCESS_KEY_ID=access-key",
+"AWS_SECRET_ACCESS_KEY=${storage_password}",
+"AWS_S3_ENDPOINT_URL=http://plane-storage:9000",
"AWS_S3_BUCKET_NAME=uploads",
-"NGINX_PORT=80",
"BUCKET_NAME=uploads",
"FILE_SIZE_LIMIT=5242880",
"RABBITMQ_HOST=plane-mq",
"RABBITMQ_PORT=5672",
-"RABBITMQ_DEFAULT_USER=rabbitmq_user",
+"RABBITMQ_USER=${rabbitmq_user}",
+"RABBITMQ_PASSWORD=${rabbitmq_pass}",
+"RABBITMQ_VHOST=plane",
+"RABBITMQ_DEFAULT_USER=${rabbitmq_user}",
"RABBITMQ_DEFAULT_PASS=${rabbitmq_pass}",
"RABBITMQ_DEFAULT_VHOST=plane",
-"RABBITMQ_VHOST=plane",
+"AMQP_URL=amqp://${rabbitmq_user}:${rabbitmq_pass}@plane-mq:5672/plane",
"API_BASE_URL=http://api:8000",
"DEBUG=0",
-"SENTRY_DSN=",
-"SENTRY_ENVIRONMENT=production",
-"CORS_ALLOWED_ORIGINS=https://${Domain}",
+"CORS_ALLOWED_ORIGINS=http://${main_domain}",
"GUNICORN_WORKERS=1",
"USE_MINIO=1",
-"DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@plane-db/plane",
"SECRET_KEY=${secret_key}",
-"AMQP_URL=amqp://${RABBITMQ_DEFAULT_USER}:${RABBITMQ_DEFAULT_PASS}@plane-mq:5672/plane",
"API_KEY_RATE_LIMIT=60/minute",
-"MINIO_ENDPOINT_SSL=0"
+"MINIO_ENDPOINT_SSL=0",
+"SITE_ADDRESS=:80",
+"LIVE_SERVER_SECRET_KEY=${live_secret_key}"
]
mounts = []
diff --git a/blueprints/postiz/docker-compose.yml b/blueprints/postiz/docker-compose.yml
index dfbf3ae9..a00832dd 100644
--- a/blueprints/postiz/docker-compose.yml
+++ b/blueprints/postiz/docker-compose.yml
@@ -13,10 +13,25 @@ services:
DATABASE_URL: "postgresql://${DB_USER}:${DB_PASSWORD}@postiz-postgres:5432/${DB_NAME}"
REDIS_URL: "redis://postiz-redis:6379"
BACKEND_INTERNAL_URL: "http://localhost:3000"
+ TEMPORAL_ADDRESS: "temporal:7233"
IS_GENERAL: "true"
+ DISABLE_REGISTRATION: "false"
+ RUN_CRON: "true"
+ NOT_SECURED: "true"
STORAGE_PROVIDER: "local"
UPLOAD_DIRECTORY: "/uploads"
NEXT_PUBLIC_UPLOAD_DIRECTORY: "/uploads"
+
+ # === Social Media API Settings ===
+ # These variables should be defined in the Dokploy Environment tab.
+ # For more configuration options and details, please refer to the official documentation.
+ FACEBOOK_APP_ID: ${FACEBOOK_APP_ID}
+ FACEBOOK_APP_SECRET: ${FACEBOOK_APP_SECRET}
+ LINKEDIN_CLIENT_ID: ${LINKEDIN_CLIENT_ID}
+ LINKEDIN_CLIENT_SECRET: ${LINKEDIN_CLIENT_SECRET}
+ X_API_KEY: ${X_API_KEY}
+ X_API_SECRET: ${X_API_SECRET}
+
volumes:
- postiz-config:/config/
- postiz-uploads:/uploads/
@@ -25,6 +40,8 @@ services:
condition: service_healthy
postiz-redis:
condition: service_healthy
+ temporal:
+ condition: service_started
postiz-postgres:
image: postgres:17-alpine
@@ -35,27 +52,80 @@ services:
POSTGRES_USER: ${DB_USER}
POSTGRES_DB: ${DB_NAME}
volumes:
- - postiz-postgres-data:/var/lib/postgresql/data
+ - postgres-volume:/var/lib/postgresql/data
healthcheck:
- test: pg_isready -U ${DB_USER} -d ${DB_NAME}
+ test: ["CMD-SHELL", "pg_isready -U ${DB_USER} -d ${DB_NAME}"]
interval: 10s
timeout: 3s
retries: 3
+ start_period: 10s
postiz-redis:
image: redis:7.2
restart: always
healthcheck:
- test: redis-cli ping
+ test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s
retries: 3
volumes:
- postiz-redis-data:/data
+ temporal-elasticsearch:
+ image: elasticsearch:7.17.27
+ environment:
+ - cluster.routing.allocation.disk.threshold_enabled=true
+ - cluster.routing.allocation.disk.watermark.low=512mb
+ - cluster.routing.allocation.disk.watermark.high=256mb
+ - cluster.routing.allocation.disk.watermark.flood_stage=128mb
+ - discovery.type=single-node
+ - ES_JAVA_OPTS=-Xms256m -Xmx256m
+ - xpack.security.enabled=false
+ volumes:
+ - temporal-es-data:/usr/share/elasticsearch/data
+
+ temporal-postgresql:
+ image: postgres:16
+ environment:
+ POSTGRES_PASSWORD: ${TEMPORAL_PASSWORD}
+ POSTGRES_USER: ${TEMPORAL_USER}
+ volumes:
+ - temporal-pg-data:/var/lib/postgresql/data
+ healthcheck:
+ test: ["CMD-SHELL", "pg_isready -U ${TEMPORAL_USER}"]
+ interval: 10s
+ timeout: 5s
+ retries: 5
+
+ temporal:
+ image: temporalio/auto-setup:1.28.1
+ depends_on:
+ temporal-postgresql:
+ condition: service_healthy
+ temporal-elasticsearch:
+ condition: service_started
+ environment:
+ - DB=postgres12
+ - DB_PORT=5432
+ - POSTGRES_USER=${TEMPORAL_USER}
+ - POSTGRES_PWD=${TEMPORAL_PASSWORD}
+ - POSTGRES_SEEDS=temporal-postgresql
+ - ENABLE_ES=true
+ - ES_SEEDS=temporal-elasticsearch
+ - ES_VERSION=v7
+ - TEMPORAL_NAMESPACE=default
+ healthcheck:
+ test: ["CMD", "tctl", "--address", "127.0.0.1:7233", "workflow", "list"]
+ interval: 15s
+ timeout: 10s
+ retries: 30
+ start_period: 120s
+
volumes:
- postiz-postgres-data:
+ postgres-volume:
postiz-redis-data:
postiz-config:
- postiz-uploads:
\ No newline at end of file
+ postiz-uploads:
+ temporal-es-data:
+ temporal-pg-data:
\ No newline at end of file
diff --git a/blueprints/postiz/template.toml b/blueprints/postiz/template.toml
index 260b77af..4528e909 100644
--- a/blueprints/postiz/template.toml
+++ b/blueprints/postiz/template.toml
@@ -3,19 +3,29 @@ main_domain = "${domain}"
db_password = "${password}"
db_user = "postiz"
db_name = "postiz"
+temporal_password = "${password}"
+temporal_user = "temporal"
jwt_secret = "${base64:32}"
[config]
+env = [
+ "POSTIZ_HOST=${main_domain}",
+ "JWT_SECRET=${jwt_secret}",
+ "DB_USER=${db_user}",
+ "DB_PASSWORD=${db_password}",
+ "DB_NAME=${db_name}",
+ "TEMPORAL_USER=${temporal_user}",
+ "TEMPORAL_PASSWORD=${temporal_password}",
+ "FACEBOOK_APP_ID=",
+ "FACEBOOK_APP_SECRET=",
+ "LINKEDIN_CLIENT_ID=",
+ "LINKEDIN_CLIENT_SECRET=",
+ "X_API_KEY=",
+ "X_API_SECRET="
+]
mounts = []
[[config.domains]]
serviceName = "postiz-app"
-port = 5_000
+port = 5000
host = "${main_domain}"
-
-[config.env]
-POSTIZ_HOST = "${main_domain}"
-DB_PASSWORD = "${db_password}"
-DB_USER = "${db_user}"
-DB_NAME = "${db_name}"
-JWT_SECRET = "${jwt_secret}"
diff --git a/blueprints/prefect/docker-compose.yml b/blueprints/prefect/docker-compose.yml
new file mode 100644
index 00000000..242936e8
--- /dev/null
+++ b/blueprints/prefect/docker-compose.yml
@@ -0,0 +1,90 @@
+version: "3.8"
+
+services:
+ prefect:
+ image: prefecthq/prefect:3.7.5-python3.12
+ restart: unless-stopped
+ depends_on:
+ prefect-postgres:
+ condition: service_healthy
+ prefect-redis:
+ condition: service_healthy
+ environment:
+ - PREFECT_API_DATABASE_CONNECTION_URL=postgresql+asyncpg://prefect:${POSTGRES_PASSWORD}@prefect-postgres:5432/prefect
+ - PREFECT_SERVER_API_HOST=0.0.0.0
+ - PREFECT_SERVER_UI_API_URL=https://${PREFECT_DOMAIN}/api
+ - PREFECT_MESSAGING_BROKER=prefect_redis.messaging
+ - PREFECT_MESSAGING_CACHE=prefect_redis.messaging
+ - PREFECT_REDIS_MESSAGING_HOST=prefect-redis
+ - PREFECT_REDIS_MESSAGING_PORT=6379
+ - PREFECT_REDIS_MESSAGING_DB=0
+ command: prefect server start --no-services
+ expose:
+ - 4200
+ healthcheck:
+ test:
+ [
+ "CMD",
+ "python",
+ "-c",
+ "import urllib.request as u; u.urlopen('http://localhost:4200/api/health', timeout=1)",
+ ]
+ interval: 30s
+ timeout: 10s
+ retries: 3
+ start_period: 60s
+
+ prefect-services:
+ image: prefecthq/prefect:3.7.5-python3.12
+ restart: unless-stopped
+ depends_on:
+ prefect:
+ condition: service_healthy
+ environment:
+ - PREFECT_API_DATABASE_CONNECTION_URL=postgresql+asyncpg://prefect:${POSTGRES_PASSWORD}@prefect-postgres:5432/prefect
+ - PREFECT_MESSAGING_BROKER=prefect_redis.messaging
+ - PREFECT_MESSAGING_CACHE=prefect_redis.messaging
+ - PREFECT_REDIS_MESSAGING_HOST=prefect-redis
+ - PREFECT_REDIS_MESSAGING_PORT=6379
+ - PREFECT_REDIS_MESSAGING_DB=0
+ command: prefect server services start
+
+ prefect-worker:
+ image: prefecthq/prefect:3.7.5-python3.12
+ restart: unless-stopped
+ depends_on:
+ prefect:
+ condition: service_healthy
+ environment:
+ - PREFECT_API_URL=http://prefect:4200/api
+ command: prefect worker start --pool local-pool
+
+ prefect-postgres:
+ image: postgres:14-alpine
+ restart: unless-stopped
+ environment:
+ - POSTGRES_USER=prefect
+ - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
+ - POSTGRES_DB=prefect
+ volumes:
+ - prefect-postgres-data:/var/lib/postgresql/data
+ healthcheck:
+ test: ["CMD-SHELL", "pg_isready -U prefect -d prefect"]
+ interval: 5s
+ timeout: 5s
+ retries: 5
+
+ prefect-redis:
+ image: redis:7.2-alpine
+ restart: unless-stopped
+ volumes:
+ - prefect-redis-data:/data
+ healthcheck:
+ test: ["CMD", "redis-cli", "ping"]
+ interval: 5s
+ timeout: 5s
+ retries: 5
+
+volumes:
+ prefect-postgres-data:
+ prefect-redis-data:
diff --git a/blueprints/prefect/prefect.svg b/blueprints/prefect/prefect.svg
new file mode 100644
index 00000000..07bf5b43
--- /dev/null
+++ b/blueprints/prefect/prefect.svg
@@ -0,0 +1,7 @@
+
+ Prefect
+ Prefect template icon
+
+
+
+
diff --git a/blueprints/prefect/template.toml b/blueprints/prefect/template.toml
new file mode 100644
index 00000000..15f166e5
--- /dev/null
+++ b/blueprints/prefect/template.toml
@@ -0,0 +1,15 @@
+[variables]
+main_domain = "${domain}"
+postgres_password = "${password:32}"
+
+[config]
+env = [
+ "PREFECT_DOMAIN=${main_domain}",
+ "POSTGRES_PASSWORD=${postgres_password}",
+]
+mounts = []
+
+[[config.domains]]
+serviceName = "prefect"
+port = 4200
+host = "${main_domain}"
diff --git a/blueprints/privatebin/docker-compose.yml b/blueprints/privatebin/docker-compose.yml
new file mode 100644
index 00000000..dc621ca0
--- /dev/null
+++ b/blueprints/privatebin/docker-compose.yml
@@ -0,0 +1,11 @@
+services:
+ privatebin:
+ image: privatebin/nginx-fpm-alpine:2.0.4
+ restart: unless-stopped
+ volumes:
+ - privatebin_data:/srv/data
+ ports:
+ - "8080"
+
+volumes:
+ privatebin_data:
diff --git a/blueprints/privatebin/privatebin.svg b/blueprints/privatebin/privatebin.svg
new file mode 100644
index 00000000..0391799d
--- /dev/null
+++ b/blueprints/privatebin/privatebin.svg
@@ -0,0 +1,5 @@
+
+
+
+ P
+
diff --git a/blueprints/privatebin/template.toml b/blueprints/privatebin/template.toml
new file mode 100644
index 00000000..747c3bc7
--- /dev/null
+++ b/blueprints/privatebin/template.toml
@@ -0,0 +1,11 @@
+[variables]
+main_domain = "${domain}"
+
+[config]
+env = {}
+mounts = []
+
+[[config.domains]]
+serviceName = "privatebin"
+port = 8080
+host = "${main_domain}"
diff --git a/blueprints/pyrodactyl/pyrodactyl.png b/blueprints/pyrodactyl/pyrodactyl.png
index 50c98fdd..81513193 100644
Binary files a/blueprints/pyrodactyl/pyrodactyl.png and b/blueprints/pyrodactyl/pyrodactyl.png differ
diff --git a/blueprints/qui/docker-compose.yml b/blueprints/qui/docker-compose.yml
new file mode 100644
index 00000000..0158d9cd
--- /dev/null
+++ b/blueprints/qui/docker-compose.yml
@@ -0,0 +1,13 @@
+version: "3.8"
+
+services:
+ qui:
+ image: ghcr.io/autobrr/qui:latest
+ restart: unless-stopped
+ expose:
+ - "7476"
+ volumes:
+ - qui-config:/config
+
+volumes:
+ qui-config:
diff --git a/blueprints/qui/qui.png b/blueprints/qui/qui.png
new file mode 100644
index 00000000..64897dc4
Binary files /dev/null and b/blueprints/qui/qui.png differ
diff --git a/blueprints/qui/template.toml b/blueprints/qui/template.toml
new file mode 100644
index 00000000..3858b997
--- /dev/null
+++ b/blueprints/qui/template.toml
@@ -0,0 +1,9 @@
+[variables]
+main_domain = "${domain}"
+
+[config]
+[[config.domains]]
+serviceName = "qui"
+port = 7476
+host = "${main_domain}"
+path = "/"
diff --git a/blueprints/rallly/docker-compose.yml b/blueprints/rallly/docker-compose.yml
new file mode 100644
index 00000000..ac6badae
--- /dev/null
+++ b/blueprints/rallly/docker-compose.yml
@@ -0,0 +1,66 @@
+version: "3.8"
+
+services:
+ rallly:
+ image: lukevella/rallly:4.11.1
+ restart: unless-stopped
+ depends_on:
+ - db
+ - minio
+ - minio-init
+ environment:
+ NEXT_PUBLIC_BASE_URL: ${NEXT_PUBLIC_BASE_URL}
+ DATABASE_URL: ${DATABASE_URL}
+ SECRET_PASSWORD: ${SECRET_PASSWORD}
+ SUPPORT_EMAIL: ${SUPPORT_EMAIL}
+ NOREPLY_EMAIL: ${NOREPLY_EMAIL}
+ SMTP_HOST: ${SMTP_HOST}
+ SMTP_PORT: ${SMTP_PORT}
+ SMTP_USER: ${SMTP_USER}
+ SMTP_PWD: ${SMTP_PWD}
+ SMTP_SECURE: ${SMTP_SECURE}
+ S3_ENDPOINT: ${S3_ENDPOINT}
+ S3_BUCKET_NAME: ${S3_BUCKET_NAME}
+ S3_REGION: ${S3_REGION}
+ S3_ACCESS_KEY_ID: ${S3_ACCESS_KEY_ID}
+ S3_SECRET_ACCESS_KEY: ${S3_SECRET_ACCESS_KEY}
+ INITIAL_ADMIN_EMAIL: ${INITIAL_ADMIN_EMAIL}
+
+ db:
+ image: postgres:14-alpine
+ restart: unless-stopped
+ environment:
+ POSTGRES_DB: rallly
+ POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
+ volumes:
+ - rallly-db:/var/lib/postgresql/data
+ healthcheck:
+ test: ["CMD-SHELL", "pg_isready -U postgres -d rallly"]
+ interval: 10s
+ timeout: 5s
+ retries: 5
+
+ minio:
+ image: minio/minio:latest
+ restart: unless-stopped
+ command: server /data
+ environment:
+ MINIO_ROOT_USER: ${S3_ACCESS_KEY_ID}
+ MINIO_ROOT_PASSWORD: ${S3_SECRET_ACCESS_KEY}
+ volumes:
+ - rallly-minio:/data
+
+ minio-init:
+ image: minio/mc:latest
+ depends_on:
+ - minio
+ restart: "no"
+ entrypoint: >
+ /bin/sh -c "
+ until mc alias set local http://minio:9000 ${S3_ACCESS_KEY_ID} ${S3_SECRET_ACCESS_KEY}; do sleep 2; done;
+ mc mb --ignore-existing local/rallly;
+ "
+
+volumes:
+ rallly-db:
+ rallly-minio:
\ No newline at end of file
diff --git a/blueprints/rallly/rallly.svg b/blueprints/rallly/rallly.svg
new file mode 100644
index 00000000..b4e44b30
--- /dev/null
+++ b/blueprints/rallly/rallly.svg
@@ -0,0 +1,8 @@
+
+ Rallly
+
+
+
+
+
+
\ No newline at end of file
diff --git a/blueprints/rallly/template.toml b/blueprints/rallly/template.toml
new file mode 100644
index 00000000..902a72f8
--- /dev/null
+++ b/blueprints/rallly/template.toml
@@ -0,0 +1,40 @@
+[variables]
+main_domain = "${domain}"
+support_email = "${email}"
+noreply_email = "${email}"
+initial_admin_email = "${email}"
+postgres_password = "${password:32}"
+secret_password = "${password:32}"
+s3_access_key_id = "rallly"
+s3_secret_access_key = "${password:32}"
+smtp_host = "smtp.example.com"
+smtp_port = "587"
+smtp_user = "change-me"
+smtp_password = "${password:32}"
+smtp_secure = "false"
+
+[config]
+env = [
+ "NEXT_PUBLIC_BASE_URL=https://${main_domain}",
+ "DATABASE_URL=postgres://postgres:${postgres_password}@db:5432/rallly",
+ "SECRET_PASSWORD=${secret_password}",
+ "SUPPORT_EMAIL=${support_email}",
+ "NOREPLY_EMAIL=${noreply_email}",
+ "SMTP_HOST=${smtp_host}",
+ "SMTP_PORT=${smtp_port}",
+ "SMTP_USER=${smtp_user}",
+ "SMTP_PWD=${smtp_password}",
+ "SMTP_SECURE=${smtp_secure}",
+ "S3_ENDPOINT=http://minio:9000",
+ "S3_BUCKET_NAME=rallly",
+ "S3_REGION=us-east-1",
+ "S3_ACCESS_KEY_ID=${s3_access_key_id}",
+ "S3_SECRET_ACCESS_KEY=${s3_secret_access_key}",
+ "INITIAL_ADMIN_EMAIL=${initial_admin_email}",
+ "POSTGRES_PASSWORD=${postgres_password}",
+]
+
+[[config.domains]]
+serviceName = "rallly"
+port = 3000
+host = "${main_domain}"
\ No newline at end of file
diff --git a/blueprints/rustrak-full/docker-compose.yml b/blueprints/rustrak-full/docker-compose.yml
new file mode 100644
index 00000000..16f734c7
--- /dev/null
+++ b/blueprints/rustrak-full/docker-compose.yml
@@ -0,0 +1,49 @@
+version: "3.8"
+
+services:
+ rustrak-server:
+ image: abians7/rustrak-server:v0.2.1-postgres
+ restart: unless-stopped
+ environment:
+ - HOST=0.0.0.0
+ - PORT=8080
+ - RUST_LOG=info
+ - SSL_PROXY=true
+ - DATABASE_URL=postgres://rustrak:${POSTGRES_PASSWORD}@postgres:5432/rustrak
+ - SESSION_SECRET_KEY=${SESSION_SECRET_KEY}
+ - CREATE_SUPERUSER=${CREATE_SUPERUSER}
+ ports:
+ - 8080
+ depends_on:
+ postgres:
+ condition: service_healthy
+
+ rustrak-ui:
+ image: abians7/rustrak-ui:v0.1.6
+ restart: unless-stopped
+ environment:
+ - RUSTRAK_API_URL=${RUSTRAK_API_URL}
+ ports:
+ - 3000
+ depends_on:
+ - rustrak-server
+
+ postgres:
+ image: postgres:16-alpine
+ restart: unless-stopped
+ environment:
+ - POSTGRES_USER=rustrak
+ - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
+ - POSTGRES_DB=rustrak
+ volumes:
+ - postgres_data:/var/lib/postgresql/data
+ healthcheck:
+ test: ["CMD-SHELL", "pg_isready -U rustrak -d rustrak"]
+ interval: 10s
+ timeout: 5s
+ retries: 5
+ expose:
+ - 5432
+
+volumes:
+ postgres_data:
diff --git a/blueprints/rustrak-full/rustrak.svg b/blueprints/rustrak-full/rustrak.svg
new file mode 100644
index 00000000..11d87e47
--- /dev/null
+++ b/blueprints/rustrak-full/rustrak.svg
@@ -0,0 +1,6 @@
+
+
+
+
diff --git a/blueprints/rustrak-full/template.toml b/blueprints/rustrak-full/template.toml
new file mode 100644
index 00000000..383f486f
--- /dev/null
+++ b/blueprints/rustrak-full/template.toml
@@ -0,0 +1,27 @@
+[variables]
+main_domain = "${domain}"
+api_domain = "${domain}"
+postgres_password = "${password:32}"
+session_secret_key = "${password:64}"
+admin_email = "${email}"
+admin_password = "${password:16}"
+create_superuser = "${admin_email}:${admin_password}"
+rustrak_api_url = "https://${api_domain}"
+
+[config]
+env = [
+ "POSTGRES_PASSWORD=${postgres_password}",
+ "SESSION_SECRET_KEY=${session_secret_key}",
+ "CREATE_SUPERUSER=${create_superuser}",
+ "RUSTRAK_API_URL=${rustrak_api_url}",
+]
+
+[[config.domains]]
+serviceName = "rustrak-ui"
+port = 3000
+host = "${main_domain}"
+
+[[config.domains]]
+serviceName = "rustrak-server"
+port = 8080
+host = "${api_domain}"
diff --git a/blueprints/rustrak/docker-compose.yml b/blueprints/rustrak/docker-compose.yml
new file mode 100644
index 00000000..e4c52b0f
--- /dev/null
+++ b/blueprints/rustrak/docker-compose.yml
@@ -0,0 +1,20 @@
+version: "3.8"
+
+services:
+ rustrak:
+ image: abians7/rustrak-server:v0.2.1
+ restart: unless-stopped
+ environment:
+ - HOST=0.0.0.0
+ - PORT=8080
+ - RUST_LOG=info
+ - SSL_PROXY=true
+ - SESSION_SECRET_KEY=${SESSION_SECRET_KEY}
+ - CREATE_SUPERUSER=${CREATE_SUPERUSER}
+ volumes:
+ - rustrak_data:/data
+ ports:
+ - 8080
+
+volumes:
+ rustrak_data:
diff --git a/blueprints/rustrak/rustrak.svg b/blueprints/rustrak/rustrak.svg
new file mode 100644
index 00000000..11d87e47
--- /dev/null
+++ b/blueprints/rustrak/rustrak.svg
@@ -0,0 +1,6 @@
+
+
+
+
diff --git a/blueprints/rustrak/template.toml b/blueprints/rustrak/template.toml
new file mode 100644
index 00000000..819f6f85
--- /dev/null
+++ b/blueprints/rustrak/template.toml
@@ -0,0 +1,17 @@
+[variables]
+main_domain = "${domain}"
+session_secret_key = "${password:64}"
+admin_email = "${email}"
+admin_password = "${password:16}"
+create_superuser = "${admin_email}:${admin_password}"
+
+[config]
+env = [
+ "SESSION_SECRET_KEY=${session_secret_key}",
+ "CREATE_SUPERUSER=${create_superuser}",
+]
+
+[[config.domains]]
+serviceName = "rustrak"
+port = 8080
+host = "${main_domain}"
diff --git a/blueprints/seanime/docker-compose.yml b/blueprints/seanime/docker-compose.yml
new file mode 100644
index 00000000..9f6992a0
--- /dev/null
+++ b/blueprints/seanime/docker-compose.yml
@@ -0,0 +1,26 @@
+version: "3.8"
+services:
+ seanime-init:
+ image: busybox:1.37.0
+ user: "0:0"
+ volumes:
+ - ./seanime-config:/mnt/config
+ - ./anime:/mnt/anime
+ - ./downloads:/mnt/downloads
+ command:
+ [ "sh", "-c", "chown -R 1000:1000 /mnt/config && find /mnt/config -type d -exec chmod 755 {} + && find /mnt/config -type f -exec chmod 644 {} +",]
+
+ seanime:
+ image: umagistr/seanime:v3.6.1-rootless
+ depends_on:
+ seanime-init:
+ condition: service_completed_successfully
+ environment:
+ - SEANIME_SERVER_HOST=0.0.0.0
+ expose:
+ - "43211"
+ volumes:
+ - ./seanime-config:/home/seanime/.config/Seanime
+ - ./anime:/anime
+ - ./downloads:/downloads
+ restart: unless-stopped
\ No newline at end of file
diff --git a/blueprints/seanime/seanime.png b/blueprints/seanime/seanime.png
new file mode 100644
index 00000000..9e2459d9
Binary files /dev/null and b/blueprints/seanime/seanime.png differ
diff --git a/blueprints/seanime/template.toml b/blueprints/seanime/template.toml
new file mode 100644
index 00000000..eabd94ef
--- /dev/null
+++ b/blueprints/seanime/template.toml
@@ -0,0 +1,7 @@
+[variables]
+main_domain = "${domain}"
+
+[[config.domains]]
+serviceName = "seanime"
+port = 43211
+host = "${main_domain}"
\ No newline at end of file
diff --git a/blueprints/senddock/docker-compose.yml b/blueprints/senddock/docker-compose.yml
new file mode 100644
index 00000000..c4ff03d0
--- /dev/null
+++ b/blueprints/senddock/docker-compose.yml
@@ -0,0 +1,57 @@
+version: "3.8"
+services:
+ postgres:
+ image: postgres:17-alpine
+ restart: unless-stopped
+ environment:
+ - POSTGRES_USER=senddock
+ - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
+ - POSTGRES_DB=senddock
+ volumes:
+ - pgdata:/var/lib/postgresql/data
+ healthcheck:
+ test: ["CMD-SHELL", "pg_isready -U senddock"]
+ interval: 10s
+ timeout: 5s
+ retries: 6
+
+ redis:
+ image: redis:7-alpine
+ restart: unless-stopped
+ volumes:
+ - redisdata:/data
+ healthcheck:
+ test: ["CMD", "redis-cli", "ping"]
+ interval: 10s
+ timeout: 3s
+ retries: 5
+
+ senddock:
+ image: ghcr.io/arkhe-systems/senddock:0.6.5.1
+ restart: unless-stopped
+ depends_on:
+ postgres:
+ condition: service_healthy
+ redis:
+ condition: service_healthy
+ environment:
+ - DATABASE_URL=postgres://senddock:${POSTGRES_PASSWORD}@postgres:5432/senddock?sslmode=disable
+ - REDIS_URL=redis://redis:6379
+ - JWT_SECRET=${JWT_SECRET}
+ - PUBLIC_URL=${PUBLIC_URL}
+ - FRONTEND_URL=${PUBLIC_URL}
+ - DEPLOYMENT_MODE=self-hosted
+ - SENDDOCK_LICENSE_KEY=${SENDDOCK_LICENSE_KEY}
+ - PORT=8080
+ expose:
+ - 8080
+ healthcheck:
+ test: ["CMD", "wget", "-qO-", "http://127.0.0.1:8080/health"]
+ interval: 30s
+ timeout: 5s
+ retries: 3
+ start_period: 15s
+
+volumes:
+ pgdata:
+ redisdata:
diff --git a/blueprints/senddock/senddock.svg b/blueprints/senddock/senddock.svg
new file mode 100644
index 00000000..9dc916eb
--- /dev/null
+++ b/blueprints/senddock/senddock.svg
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/blueprints/senddock/template.toml b/blueprints/senddock/template.toml
new file mode 100644
index 00000000..4a8c456e
--- /dev/null
+++ b/blueprints/senddock/template.toml
@@ -0,0 +1,17 @@
+[variables]
+main_domain = "${domain}"
+postgres_password = "${password:32}"
+jwt_secret = "${password:64}"
+
+[config]
+env = [
+ "POSTGRES_PASSWORD=${postgres_password}",
+ "JWT_SECRET=${jwt_secret}",
+ "PUBLIC_URL=https://${main_domain}",
+ "SENDDOCK_LICENSE_KEY="
+]
+
+[[config.domains]]
+serviceName = "senddock"
+port = 8080
+host = "${main_domain}"
diff --git a/blueprints/seq/README.md b/blueprints/seq/README.md
new file mode 100644
index 00000000..d7c35632
--- /dev/null
+++ b/blueprints/seq/README.md
@@ -0,0 +1,13 @@
+# Seq
+
+Seq is a self-hosted log search and structured observability server from Datalust.
+
+This Dokploy template includes:
+
+- Seq server using the official Datalust container image
+- Generated first-run admin password
+- Canonical URL configured from the Dokploy domain
+- Persistent `/data` volume
+- Dokploy domain routing for the web UI and ingestion API on port 80
+
+The template sets `ACCEPT_EULA=Y`, which is required by the official Seq container image.
\ No newline at end of file
diff --git a/blueprints/seq/docker-compose.yml b/blueprints/seq/docker-compose.yml
new file mode 100644
index 00000000..2f9aa3de
--- /dev/null
+++ b/blueprints/seq/docker-compose.yml
@@ -0,0 +1,17 @@
+version: "3.8"
+
+services:
+ seq:
+ image: datalust/seq:2025.2
+ restart: unless-stopped
+ environment:
+ ACCEPT_EULA: "Y"
+ SEQ_API_CANONICALURI: ${SEQ_API_CANONICALURI}
+ SEQ_FIRSTRUN_ADMINPASSWORD: ${SEQ_FIRSTRUN_ADMINPASSWORD}
+ expose:
+ - "80"
+ volumes:
+ - seq-data:/data
+
+volumes:
+ seq-data: {}
\ No newline at end of file
diff --git a/blueprints/seq/logo.svg b/blueprints/seq/logo.svg
new file mode 100644
index 00000000..edc1a7f4
--- /dev/null
+++ b/blueprints/seq/logo.svg
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/blueprints/seq/template.toml b/blueprints/seq/template.toml
new file mode 100644
index 00000000..73543877
--- /dev/null
+++ b/blueprints/seq/template.toml
@@ -0,0 +1,16 @@
+[variables]
+main_domain = "${domain}"
+admin_password = "${password:32}"
+
+[config]
+env = [
+ "ACCEPT_EULA=Y",
+ "SEQ_API_CANONICALURI=https://${main_domain}",
+ "SEQ_FIRSTRUN_ADMINPASSWORD=${admin_password}"
+]
+mounts = []
+
+[[config.domains]]
+serviceName = "seq"
+port = 80
+host = "${main_domain}"
\ No newline at end of file
diff --git a/blueprints/snipe-it/docker-compose.yml b/blueprints/snipe-it/docker-compose.yml
new file mode 100644
index 00000000..be3140b7
--- /dev/null
+++ b/blueprints/snipe-it/docker-compose.yml
@@ -0,0 +1,68 @@
+version: "3.8"
+
+services:
+ snipe-it:
+ image: snipe/snipe-it:v8.5.0
+ restart: unless-stopped
+ expose:
+ - 80
+ volumes:
+ - snipe-it-storage:/var/lib/snipeit
+ environment:
+ - APP_ENV=production
+ - APP_DEBUG=false
+ - APP_KEY=${APP_KEY}
+ - APP_URL=${APP_URL}
+ - APP_TIMEZONE=${APP_TIMEZONE}
+ - APP_LOCALE=${APP_LOCALE}
+ - APP_TRUSTED_PROXIES=${APP_TRUSTED_PROXIES}
+ - APP_FORCE_TLS=${APP_FORCE_TLS}
+ - SECURE_COOKIES=${SECURE_COOKIES}
+ - PRIVATE_FILESYSTEM_DISK=local
+ - PUBLIC_FILESYSTEM_DISK=local_public
+ - DB_CONNECTION=mysql
+ - DB_HOST=snipe-it-db
+ - DB_PORT=3306
+ - DB_DATABASE=${DB_DATABASE}
+ - DB_USERNAME=${DB_USERNAME}
+ - DB_PASSWORD=${DB_PASSWORD}
+ - DB_PREFIX=null
+ - DB_DUMP_PATH=/usr/bin
+ - DB_DUMP_SKIP_SSL=true
+ - DB_CHARSET=utf8mb4
+ - DB_COLLATION=utf8mb4_unicode_ci
+ - MAIL_MAILER=log
+ - MAIL_FROM_ADDR=${MAIL_FROM_ADDR}
+ - MAIL_FROM_NAME=Snipe-IT
+ - MAIL_REPLYTO_ADDR=${MAIL_FROM_ADDR}
+ - MAIL_REPLYTO_NAME=Snipe-IT
+ - ALLOW_BACKUP_DELETE=false
+ - ALLOW_DATA_PURGE=false
+ - IMAGE_LIB=gd
+ - LOG_CHANNEL=stderr
+ - CACHE_DRIVER=file
+ - SESSION_DRIVER=file
+ - QUEUE_DRIVER=sync
+ depends_on:
+ snipe-it-db:
+ condition: service_healthy
+
+ snipe-it-db:
+ image: mariadb:11.4.7
+ restart: unless-stopped
+ volumes:
+ - snipe-it-db-data:/var/lib/mysql
+ environment:
+ - MYSQL_DATABASE=${DB_DATABASE}
+ - MYSQL_USER=${DB_USERNAME}
+ - MYSQL_PASSWORD=${DB_PASSWORD}
+ - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
+ healthcheck:
+ test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
+ interval: 5s
+ timeout: 2s
+ retries: 10
+
+volumes:
+ snipe-it-storage:
+ snipe-it-db-data:
diff --git a/blueprints/snipe-it/snipe-it.png b/blueprints/snipe-it/snipe-it.png
new file mode 100644
index 00000000..423a5b74
Binary files /dev/null and b/blueprints/snipe-it/snipe-it.png differ
diff --git a/blueprints/snipe-it/template.toml b/blueprints/snipe-it/template.toml
new file mode 100644
index 00000000..aca258a5
--- /dev/null
+++ b/blueprints/snipe-it/template.toml
@@ -0,0 +1,25 @@
+[variables]
+main_domain = "${domain}"
+app_key = "${base64:32}"
+db_password = "${password:24}"
+mysql_root_password = "${password:24}"
+
+[config]
+[[config.domains]]
+serviceName = "snipe-it"
+port = 80
+host = "${main_domain}"
+
+[config.env]
+APP_KEY = "base64:${app_key}"
+APP_URL = "https://${main_domain}"
+APP_TIMEZONE = "UTC"
+APP_LOCALE = "en-US"
+APP_TRUSTED_PROXIES = "172.0.0.0/8"
+APP_FORCE_TLS = "true"
+SECURE_COOKIES = "true"
+DB_DATABASE = "snipeit"
+DB_USERNAME = "snipeit"
+DB_PASSWORD = "${db_password}"
+MYSQL_ROOT_PASSWORD = "${mysql_root_password}"
+MAIL_FROM_ADDR = "snipe-it@${main_domain}"
diff --git a/blueprints/soft-serve/docker-compose.yml b/blueprints/soft-serve/docker-compose.yml
new file mode 100644
index 00000000..ac875d21
--- /dev/null
+++ b/blueprints/soft-serve/docker-compose.yml
@@ -0,0 +1,27 @@
+version: "3.8"
+
+services:
+ soft-serve:
+ image: charmcli/soft-serve:v0.11.6
+ restart: unless-stopped
+ expose:
+ - "23231"
+ - "23232"
+ - "23233"
+ - "9418"
+ environment:
+ SOFT_SERVE_NAME: ${SOFT_SERVE_NAME}
+ SOFT_SERVE_DATA_PATH: /soft-serve
+ SOFT_SERVE_INITIAL_ADMIN_KEYS: ${SOFT_SERVE_INITIAL_ADMIN_KEYS}
+ SOFT_SERVE_SSH_LISTEN_ADDR: ":23231"
+ SOFT_SERVE_SSH_PUBLIC_URL: ${SOFT_SERVE_SSH_PUBLIC_URL}
+ SOFT_SERVE_HTTP_LISTEN_ADDR: ":23232"
+ SOFT_SERVE_HTTP_PUBLIC_URL: ${SOFT_SERVE_HTTP_PUBLIC_URL}
+ SOFT_SERVE_GIT_LISTEN_ADDR: ":9418"
+ SOFT_SERVE_STATS_LISTEN_ADDR: ":23233"
+ SOFT_SERVE_LOG_LEVEL: ${SOFT_SERVE_LOG_LEVEL}
+ volumes:
+ - soft-serve-data:/soft-serve
+
+volumes:
+ soft-serve-data:
diff --git a/blueprints/soft-serve/soft-serve.svg b/blueprints/soft-serve/soft-serve.svg
new file mode 100644
index 00000000..0bb41d55
--- /dev/null
+++ b/blueprints/soft-serve/soft-serve.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/blueprints/soft-serve/template.toml b/blueprints/soft-serve/template.toml
new file mode 100644
index 00000000..f18f883c
--- /dev/null
+++ b/blueprints/soft-serve/template.toml
@@ -0,0 +1,62 @@
+[variables]
+main_domain = "${domain}"
+server_name = "Soft Serve"
+initial_admin_keys = ""
+http_public_url = "http://${main_domain}"
+ssh_public_url = "ssh://${main_domain}:23231"
+log_level = "info"
+
+[[config.domains]]
+serviceName = "soft-serve"
+port = 23232
+host = "${main_domain}"
+path = "/"
+
+[[config.mounts]]
+filePath = "README.md"
+content = """# Soft Serve
+
+This template deploys Soft Serve, a self-hosted Git server with an SSH TUI, HTTP Git access, Git LFS support, and a lightweight web endpoint.
+
+## First Start
+
+Set `initial_admin_keys` to one or more SSH public keys before the first deployment. Soft Serve uses this value to create the initial `admin` user. The keys are consumed during initialization, so changing this variable later does not rewrite an already initialized data volume.
+
+Example value:
+
+```text
+ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA... your-name
+```
+
+## HTTP Access
+
+The Dokploy domain routes to Soft Serve's HTTP listener:
+
+- HTTP public URL: `http://${main_domain}`
+- HTTP Git clone example: `git clone http://${main_domain}/repo.git`
+
+Set `http_public_url` to `https://${main_domain}` before deploying if your Dokploy domain enforces TLS.
+
+Private HTTP access uses tokens created through the SSH admin interface.
+
+## SSH and Git Protocol Ports
+
+Soft Serve also listens inside the deployment on:
+
+- SSH/TUI: `23231`
+- Stats: `23233`
+- Git protocol: `9418`
+
+This template does not publish host TCP ports directly. Expose the SSH or Git protocol ports separately in Dokploy if you need direct terminal/TUI access, then use the configured `ssh_public_url` for clone commands.
+
+## Storage
+
+Repositories, configuration, keys, and the default SQLite database are stored in the persistent `soft-serve-data` volume mounted at `/soft-serve`.
+"""
+
+[config.env]
+SOFT_SERVE_NAME = "${server_name}"
+SOFT_SERVE_INITIAL_ADMIN_KEYS = "${initial_admin_keys}"
+SOFT_SERVE_HTTP_PUBLIC_URL = "${http_public_url}"
+SOFT_SERVE_SSH_PUBLIC_URL = "${ssh_public_url}"
+SOFT_SERVE_LOG_LEVEL = "${log_level}"
diff --git a/blueprints/speedtest-tracker/docker-compose.yml b/blueprints/speedtest-tracker/docker-compose.yml
new file mode 100644
index 00000000..234eddb4
--- /dev/null
+++ b/blueprints/speedtest-tracker/docker-compose.yml
@@ -0,0 +1,16 @@
+services:
+ speedtest-tracker:
+ image: lscr.io/linuxserver/speedtest-tracker:latest
+ restart: unless-stopped
+ environment:
+ PUID: ${PUID}
+ PGID: ${PGID}
+ APP_KEY: ${APP_KEY}
+ DB_CONNECTION: sqlite
+ volumes:
+ - speedtest_config:/config
+ ports:
+ - "80"
+
+volumes:
+ speedtest_config:
diff --git a/blueprints/speedtest-tracker/speedtest-tracker.svg b/blueprints/speedtest-tracker/speedtest-tracker.svg
new file mode 100644
index 00000000..1928bbb7
--- /dev/null
+++ b/blueprints/speedtest-tracker/speedtest-tracker.svg
@@ -0,0 +1,5 @@
+
+
+
+ S
+
diff --git a/blueprints/speedtest-tracker/template.toml b/blueprints/speedtest-tracker/template.toml
new file mode 100644
index 00000000..2ae03d8c
--- /dev/null
+++ b/blueprints/speedtest-tracker/template.toml
@@ -0,0 +1,16 @@
+[variables]
+main_domain = "${domain}"
+app_key = "${base64:32}"
+
+[config]
+mounts = []
+
+[[config.domains]]
+serviceName = "speedtest-tracker"
+port = 80
+host = "${main_domain}"
+
+[config.env]
+APP_KEY = "base64:${app_key}"
+PUID = "1000"
+PGID = "1000"
diff --git a/blueprints/supabase/docker-compose.yml b/blueprints/supabase/docker-compose.yml
index 506ddc90..3e03fb2c 100644
--- a/blueprints/supabase/docker-compose.yml
+++ b/blueprints/supabase/docker-compose.yml
@@ -1,89 +1,107 @@
# Usage
-# Start: docker compose up
-# With helpers: docker compose -f docker-compose.yml -f ./dev/docker-compose.dev.yml up
+# Start: docker compose up -d
# 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
+# Reset everything: ./reset.sh
+#
+# Dokploy: Kong is exposed on port 8000 for domain routing. Storage uses local file
+# backend by default; edit the storage service env in this file to switch to S3/MinIO.
name: supabase
services:
studio:
- container_name: ${CONTAINER_PREFIX}-studio
- image: supabase/studio:2025.04.21-sha-173cc56
+ image: supabase/studio:2026.04.27-sha-5f60601
restart: unless-stopped
healthcheck:
test:
[
- "CMD",
- "node",
- "-e",
- "fetch('http://studio:3000/api/platform/profile').then((r) => {if (r.status !== 200) throw new Error(r.status)})"
+ "CMD-SHELL",
+ "node -e \"fetch('http://localhost:3000/api/platform/profile').then((r) => {if (r.status !== 200) throw new Error(r.status)})\""
]
timeout: 10s
interval: 5s
- retries: 3
+ retries: 5
+ start_period: 30s
depends_on:
analytics:
condition: service_healthy
environment:
+ HOSTNAME: "0.0.0.0"
+
STUDIO_PG_META_URL: http://meta:8080
+ POSTGRES_PORT: ${POSTGRES_PORT}
+ POSTGRES_HOST: ${POSTGRES_HOST}
+ POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
+ PG_META_CRYPTO_KEY: ${PG_META_CRYPTO_KEY}
+ PGRST_DB_SCHEMAS: ${PGRST_DB_SCHEMAS}
+ PGRST_DB_MAX_ROWS: ${PGRST_DB_MAX_ROWS:-1000}
+ PGRST_DB_EXTRA_SEARCH_PATH: ${PGRST_DB_EXTRA_SEARCH_PATH:-public}
+
DEFAULT_ORGANIZATION_NAME: ${STUDIO_DEFAULT_ORGANIZATION}
DEFAULT_PROJECT_NAME: ${STUDIO_DEFAULT_PROJECT}
OPENAI_API_KEY: ${OPENAI_API_KEY:-}
- SUPABASE_URL: ${SUPABASE_PUBLIC_URL}
+ SUPABASE_URL: http://kong:8000
SUPABASE_PUBLIC_URL: ${SUPABASE_PUBLIC_URL}
SUPABASE_ANON_KEY: ${ANON_KEY}
SUPABASE_SERVICE_KEY: ${SERVICE_ROLE_KEY}
AUTH_JWT_SECRET: ${JWT_SECRET}
- LOGFLARE_API_KEY: ${LOGFLARE_API_KEY}
+ LOGFLARE_API_KEY: ${LOGFLARE_PUBLIC_ACCESS_TOKEN}
+ LOGFLARE_PUBLIC_ACCESS_TOKEN: ${LOGFLARE_PUBLIC_ACCESS_TOKEN}
+ LOGFLARE_PRIVATE_ACCESS_TOKEN: ${LOGFLARE_PRIVATE_ACCESS_TOKEN}
+
LOGFLARE_URL: http://analytics:4000
- NEXT_PUBLIC_ENABLE_LOGS: true
- # Comment to use Big Query backend for analytics
+ NEXT_PUBLIC_ENABLE_LOGS: "true"
NEXT_ANALYTICS_BACKEND_PROVIDER: postgres
- # Uncomment to use Big Query backend for analytics
- # NEXT_ANALYTICS_BACKEND_PROVIDER: bigquery
+ SNIPPETS_MANAGEMENT_FOLDER: /app/snippets
+ EDGE_FUNCTIONS_MANAGEMENT_FOLDER: /app/edge-functions
+ volumes:
+ - ../files/volumes/snippets:/app/snippets:Z
+ - ../files/volumes/functions:/app/edge-functions:Z
kong:
- container_name: ${CONTAINER_PREFIX}-kong
- image: kong:2.8.1
+ image: kong/kong:3.9.1
restart: unless-stopped
- # ports:
- # - ${KONG_HTTP_PORT}:8000/tcp
- # - ${KONG_HTTPS_PORT}:8443/tcp
+ healthcheck:
+ test: ["CMD", "kong", "health"]
+ interval: 5s
+ timeout: 5s
+ retries: 5
+ start_period: 30s
+ depends_on:
+ studio:
+ condition: service_healthy
expose:
- 8000
- 8443
volumes:
- # https://github.com/supabase/supabase/issues/12661
- ../files/volumes/api/kong.yml:/home/kong/temp.yml:ro,z
- depends_on:
- analytics:
- condition: service_healthy
+ - ../files/volumes/api/kong-entrypoint.sh:/home/kong/kong-entrypoint.sh:ro,z
environment:
KONG_DATABASE: "off"
- KONG_DECLARATIVE_CONFIG: /home/kong/kong.yml
- # https://github.com/supabase/cli/issues/14
+ KONG_DECLARATIVE_CONFIG: /usr/local/kong/kong.yml
KONG_DNS_ORDER: LAST,A,CNAME
- KONG_PLUGINS: request-transformer,cors,key-auth,acl,basic-auth
+ KONG_DNS_NOT_FOUND_TTL: 1
+ KONG_PLUGINS: request-transformer,cors,key-auth,acl,basic-auth,request-termination,ip-restriction,post-function
KONG_NGINX_PROXY_PROXY_BUFFER_SIZE: 160k
KONG_NGINX_PROXY_PROXY_BUFFERS: 64 160k
+ KONG_PROXY_ACCESS_LOG: /dev/stdout combined
SUPABASE_ANON_KEY: ${ANON_KEY}
SUPABASE_SERVICE_KEY: ${SERVICE_ROLE_KEY}
+ SUPABASE_PUBLISHABLE_KEY: ${SUPABASE_PUBLISHABLE_KEY:-}
+ SUPABASE_SECRET_KEY: ${SUPABASE_SECRET_KEY:-}
+ ANON_KEY_ASYMMETRIC: ${ANON_KEY_ASYMMETRIC:-}
+ SERVICE_ROLE_KEY_ASYMMETRIC: ${SERVICE_ROLE_KEY_ASYMMETRIC:-}
DASHBOARD_USERNAME: ${DASHBOARD_USERNAME}
DASHBOARD_PASSWORD: ${DASHBOARD_PASSWORD}
- CONTAINER_PREFIX: ${CONTAINER_PREFIX}
- # https://unix.stackexchange.com/a/294837
- entrypoint: bash -c 'eval "echo \"$$(cat ~/temp.yml)\"" > ~/kong.yml && /docker-entrypoint.sh kong docker-start'
+ entrypoint: ["/bin/bash", "/home/kong/kong-entrypoint.sh"]
auth:
- container_name: ${CONTAINER_PREFIX}-auth
- image: supabase/gotrue:v2.171.0
+ image: supabase/gotrue:v2.186.0
restart: unless-stopped
healthcheck:
test:
@@ -100,12 +118,8 @@ services:
retries: 3
depends_on:
db:
- # Disable this if you are using an external Postgres database
- condition: service_healthy
- analytics:
condition: service_healthy
environment:
- # the next line seems required if you want to be able to send mails from the supabase GUI
GOTRUE_MAILER_EXTERNAL_HOSTS: kong,${SUPABASE_HOST}
GOTRUE_API_HOST: 0.0.0.0
GOTRUE_API_PORT: 9999
@@ -123,16 +137,12 @@ services:
GOTRUE_JWT_DEFAULT_GROUP_NAME: authenticated
GOTRUE_JWT_EXP: ${JWT_EXPIRY}
GOTRUE_JWT_SECRET: ${JWT_SECRET}
+ GOTRUE_JWT_KEYS: ${JWT_KEYS:-[]}
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}
GOTRUE_SMTP_HOST: ${SMTP_HOST}
GOTRUE_SMTP_PORT: ${SMTP_PORT}
@@ -146,39 +156,18 @@ services:
GOTRUE_EXTERNAL_PHONE_ENABLED: ${ENABLE_PHONE_SIGNUP}
GOTRUE_SMS_AUTOCONFIRM: ${ENABLE_PHONE_AUTOCONFIRM}
- # 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_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: ""
-
- # 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:
- container_name: ${CONTAINER_PREFIX}-rest
- image: postgrest/postgrest:v12.2.11
+ image: postgrest/postgrest:v14.8
restart: unless-stopped
depends_on:
db:
- # Disable this if you are using an external Postgres database
- condition: service_healthy
- analytics:
condition: service_healthy
environment:
PGRST_DB_URI: postgres://authenticator:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}
PGRST_DB_SCHEMAS: ${PGRST_DB_SCHEMAS}
+ PGRST_DB_MAX_ROWS: ${PGRST_DB_MAX_ROWS:-1000}
+ PGRST_DB_EXTRA_SEARCH_PATH: ${PGRST_DB_EXTRA_SEARCH_PATH:-public}
PGRST_DB_ANON_ROLE: anon
PGRST_JWT_SECRET: ${JWT_SECRET}
PGRST_DB_USE_LEGACY_GUCS: "false"
@@ -190,32 +179,21 @@ services:
]
realtime:
- # This container name looks inconsistent but is correct because realtime constructs tenant id by parsing the subdomain
- container_name: realtime-dev.${CONTAINER_PREFIX}-realtime
- image: supabase/realtime:v2.34.47
+ image: supabase/realtime:v2.76.5
restart: unless-stopped
depends_on:
db:
- # Disable this if you are using an external Postgres database
- condition: service_healthy
- analytics:
condition: service_healthy
healthcheck:
test:
[
- "CMD",
- "curl",
- "-sSfL",
- "--head",
- "-o",
- "/dev/null",
- "-H",
- "Authorization: Bearer ${ANON_KEY}",
- "http://localhost:4000/api/tenants/realtime-dev/health"
+ "CMD-SHELL",
+ "curl -sSfL --head -o /dev/null -H \"Authorization: Bearer ${ANON_KEY}\" http://localhost:4000/api/tenants/realtime-dev/health"
]
timeout: 5s
- interval: 5s
+ interval: 30s
retries: 3
+ start_period: 10s
environment:
PORT: 4000
DB_HOST: ${POSTGRES_HOST}
@@ -227,20 +205,25 @@ services:
DB_ENC_KEY: supabaserealtime
API_JWT_SECRET: ${JWT_SECRET}
SECRET_KEY_BASE: ${SECRET_KEY_BASE}
+ METRICS_JWT_SECRET: ${JWT_SECRET}
ERL_AFLAGS: -proto_dist inet_tcp
DNS_NODES: "''"
RLIMIT_NOFILE: "10000"
APP_NAME: realtime
- SEED_SELF_HOST: true
- RUN_JANITOR: true
+ SEED_SELF_HOST: "true"
+ RUN_JANITOR: "true"
+ DISABLE_HEALTHCHECK_LOGGING: "true"
- # To use S3 backed storage: docker compose -f docker-compose.yml -f docker-compose.s3.yml up
storage:
- container_name: ${CONTAINER_PREFIX}-storage
- image: supabase/storage-api:v1.22.7
+ image: supabase/storage-api:v1.48.26
restart: unless-stopped
- volumes:
- - ../files/volumes/storage:/var/lib/storage:z
+ depends_on:
+ db:
+ condition: service_healthy
+ rest:
+ condition: service_started
+ imgproxy:
+ condition: service_started
healthcheck:
test:
[
@@ -254,33 +237,30 @@ services:
timeout: 5s
interval: 5s
retries: 3
- depends_on:
- db:
- # Disable this if you are using an external Postgres database
- condition: service_healthy
- rest:
- condition: service_started
- imgproxy:
- condition: service_started
+ start_period: 10s
+ volumes:
+ - ../files/volumes/storage:/var/lib/storage:z
environment:
ANON_KEY: ${ANON_KEY}
SERVICE_KEY: ${SERVICE_ROLE_KEY}
POSTGREST_URL: http://rest:3000
- PGRST_JWT_SECRET: ${JWT_SECRET}
+ AUTH_JWT_SECRET: ${JWT_SECRET}
DATABASE_URL: postgres://supabase_storage_admin:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}
+ STORAGE_PUBLIC_URL: ${SUPABASE_PUBLIC_URL}
+ REQUEST_ALLOW_X_FORWARDED_PATH: "true"
FILE_SIZE_LIMIT: 52428800
STORAGE_BACKEND: file
+ GLOBAL_S3_BUCKET: ${GLOBAL_S3_BUCKET}
FILE_STORAGE_BACKEND_PATH: /var/lib/storage
- TENANT_ID: stub
- # TODO: https://github.com/supabase/storage-api/issues/55
- REGION: stub
- GLOBAL_S3_BUCKET: stub
+ TENANT_ID: ${STORAGE_TENANT_ID}
+ REGION: ${REGION}
ENABLE_IMAGE_TRANSFORMATION: "true"
IMGPROXY_URL: http://imgproxy:5001
+ S3_PROTOCOL_ACCESS_KEY_ID: ${S3_PROTOCOL_ACCESS_KEY_ID}
+ S3_PROTOCOL_ACCESS_KEY_SECRET: ${S3_PROTOCOL_ACCESS_KEY_SECRET}
imgproxy:
- container_name: ${CONTAINER_PREFIX}-imgproxy
- image: darthsim/imgproxy:v3.8.0
+ image: darthsim/imgproxy:v3.30.1
restart: unless-stopped
volumes:
- ../files/volumes/storage:/var/lib/storage:z
@@ -298,17 +278,14 @@ services:
IMGPROXY_BIND: ":5001"
IMGPROXY_LOCAL_FILESYSTEM_ROOT: /
IMGPROXY_USE_ETAG: "true"
- IMGPROXY_ENABLE_WEBP_DETECTION: ${IMGPROXY_ENABLE_WEBP_DETECTION}
+ IMGPROXY_AUTO_WEBP: ${IMGPROXY_AUTO_WEBP}
+ IMGPROXY_MAX_SRC_RESOLUTION: 16.8
meta:
- container_name: ${CONTAINER_PREFIX}-meta
- image: supabase/postgres-meta:v0.88.9
+ image: supabase/postgres-meta:v0.96.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:
PG_META_PORT: 8080
@@ -317,23 +294,26 @@ services:
PG_META_DB_NAME: ${POSTGRES_DB}
PG_META_DB_USER: supabase_admin
PG_META_DB_PASSWORD: ${POSTGRES_PASSWORD}
+ CRYPTO_KEY: ${PG_META_CRYPTO_KEY}
functions:
- container_name: ${CONTAINER_PREFIX}-edge-functions
- image: supabase/edge-runtime:v1.67.4
+ image: supabase/edge-runtime:v1.71.2
restart: unless-stopped
volumes:
- ../files/volumes/functions:/home/deno/functions:Z
+ - deno-cache:/root/.cache/deno
depends_on:
- analytics:
+ kong:
condition: service_healthy
environment:
JWT_SECRET: ${JWT_SECRET}
SUPABASE_URL: http://kong:8000
+ SUPABASE_PUBLIC_URL: ${SUPABASE_PUBLIC_URL}
SUPABASE_ANON_KEY: ${ANON_KEY}
SUPABASE_SERVICE_ROLE_KEY: ${SERVICE_ROLE_KEY}
+ SUPABASE_PUBLISHABLE_KEYS: "{\"default\":\"${SUPABASE_PUBLISHABLE_KEY:-}\"}"
+ SUPABASE_SECRET_KEYS: "{\"default\":\"${SUPABASE_SECRET_KEY:-}\"}"
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}"
command:
[
@@ -343,32 +323,23 @@ services:
]
analytics:
- container_name: ${CONTAINER_PREFIX}-analytics
- image: supabase/logflare:1.12.0
+ image: supabase/logflare:1.36.1
restart: unless-stopped
- # ports:
- # - 4000:4000
expose:
- 4000
- # 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
+ # First boot: Logflare seeds _analytics in Postgres; allow extra time before marking unhealthy.
healthcheck:
test:
[
- "CMD",
- "curl",
- "http://localhost:4000/health"
+ "CMD-SHELL",
+ "curl -sSfL -o /dev/null http://localhost:4000/health"
]
- timeout: 5s
+ timeout: 10s
interval: 5s
- retries: 10
+ retries: 15
+ start_period: 90s
depends_on:
db:
- # Disable this if you are using an external Postgres database
condition: service_healthy
environment:
LOGFLARE_NODE_HOST: 127.0.0.1
@@ -378,55 +349,42 @@ services:
DB_PORT: ${POSTGRES_PORT}
DB_PASSWORD: ${POSTGRES_PASSWORD}
DB_SCHEMA: _analytics
- LOGFLARE_API_KEY: ${LOGFLARE_API_KEY}
- LOGFLARE_SINGLE_TENANT: true
- LOGFLARE_SUPABASE_MODE: true
+ 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}/_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
db:
- container_name: ${CONTAINER_PREFIX}-db
- image: supabase/postgres:15.8.1.060
+ image: supabase/postgres:15.8.1.085
restart: unless-stopped
volumes:
- ../files/volumes/db/realtime.sql:/docker-entrypoint-initdb.d/migrations/99-realtime.sql:Z
- # Must be superuser to create event trigger
- ../files/volumes/db/webhooks.sql:/docker-entrypoint-initdb.d/init-scripts/98-webhooks.sql:Z
- # Must be superuser to alter reserved role
- ../files/volumes/db/roles.sql:/docker-entrypoint-initdb.d/init-scripts/99-roles.sql:Z
- # Initialize the database settings with JWT_SECRET and JWT_EXP
- ../files/volumes/db/jwt.sql:/docker-entrypoint-initdb.d/init-scripts/99-jwt.sql:Z
- # PGDATA directory is persisted between restarts
- ../files/volumes/db/data:/var/lib/postgresql/data:Z
- # Changes required for internal supabase data such as _analytics
- ../files/volumes/db/_supabase.sql:/docker-entrypoint-initdb.d/migrations/97-_supabase.sql:Z
- # Changes required for Analytics support
- ../files/volumes/db/logs.sql:/docker-entrypoint-initdb.d/migrations/99-logs.sql:Z
- # Changes required for Pooler support
- ../files/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"
+ "CMD",
+ "pg_isready",
+ "-U",
+ "postgres",
+ "-h",
+ "localhost"
]
interval: 5s
timeout: 5s
- retries: 10
+ retries: 15
+ start_period: 60s
depends_on:
vector:
condition: service_healthy
@@ -446,12 +404,11 @@ services:
"-c",
"config_file=/etc/postgresql/postgresql.conf",
"-c",
- "log_min_messages=fatal" # prevents Realtime polling queries from appearing in logs
+ "log_min_messages=fatal"
]
vector:
- container_name: ${CONTAINER_PREFIX}-vector
- image: timberio/vector:0.28.1-alpine
+ image: timberio/vector:0.53.0-alpine
restart: unless-stopped
volumes:
- ../files/volumes/logs/vector.yml:/etc/vector/vector.yml:ro,z
@@ -468,9 +425,10 @@ services:
]
timeout: 5s
interval: 5s
- retries: 3
+ retries: 5
+ start_period: 10s
environment:
- LOGFLARE_API_KEY: ${LOGFLARE_API_KEY}
+ LOGFLARE_PUBLIC_ACCESS_TOKEN: ${LOGFLARE_PUBLIC_ACCESS_TOKEN}
command:
[
"--config",
@@ -479,14 +437,12 @@ services:
security_opt:
- "label=disable"
- # Update the DATABASE_URL if you are using an external Postgres database
supavisor:
- container_name: ${CONTAINER_PREFIX}-pooler
- image: supabase/supavisor:2.5.1
+ image: supabase/supavisor:2.7.4
restart: unless-stopped
- ports: # expose supavisor to the host to enable db pooler connection
- - ${POSTGRES_PORT}:5432
- - ${POOLER_PROXY_PORT_TRANSACTION}:6543
+ expose:
+ - "5432"
+ - "6543"
volumes:
- ../files/volumes/pooler/pooler.exs:/etc/pooler/pooler.exs:ro,z
healthcheck:
@@ -502,19 +458,19 @@ services:
]
interval: 10s
timeout: 5s
- retries: 5
+ retries: 10
+ start_period: 30s
depends_on:
db:
condition: service_healthy
- analytics:
- condition: service_healthy
environment:
PORT: 4000
POSTGRES_PORT: ${POSTGRES_PORT}
+ POSTGRES_HOST: ${POSTGRES_HOST}
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
- DATABASE_URL: ecto://supabase_admin:${POSTGRES_PASSWORD}@db:${POSTGRES_PORT}/_supabase
- CLUSTER_POSTGRES: true
+ 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}
@@ -525,6 +481,7 @@ services:
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",
@@ -533,4 +490,5 @@ services:
]
volumes:
- db-config:
\ No newline at end of file
+ db-config:
+ deno-cache:
diff --git a/blueprints/supabase/template.toml b/blueprints/supabase/template.toml
index f70c93cc..0e76b7dd 100644
--- a/blueprints/supabase/template.toml
+++ b/blueprints/supabase/template.toml
@@ -2,11 +2,15 @@
main_domain = "${domain}"
postgres_password = "${password:32}"
dashboard_password = "${password:32}"
-logflare_api_key = "${password:32}"
+logflare_public_access_token = "${password:32}"
+logflare_private_access_token = "${password:32}"
+pg_meta_crypto_key = "${password:32}"
+s3_protocol_access_key_id = "${password:24}"
+s3_protocol_access_key_secret = "${password:48}"
secret_key_base = "${password:64}"
vault_enc_key = "${password:32}"
jwt_secret = "${password:32}"
-container_name_prefix = "${APP_NAME}-supabase"
+pooler_tenant_id = "${uuid}"
anon_key_payload = """{
"role": "anon",
"iss": "supabase",
@@ -34,12 +38,7 @@ env = [
'# - ADDITIONAL_REDIRECT_URLS, SITE_URL should point to application using supabase for authentication',
'# They are used for redirecting after login/signup and gotrue will check them before sending emails',
'# - POSTGRES_PORT, POOLER_PROXY_PORT_TRANSACTION should be changed if you are already running other instances of supabase',
-'#',
-'# Supabase uses container names in part of its configuration so it is important to keep them',
-'# This template generates a random prefix for the container names to avoid conflicts',
-'# If you change it you will need to update routes in the vector.yml file in advanced->mounts section',
'############',
-'CONTAINER_PREFIX=${container_name_prefix}',
'',
'############',
'# Secrets',
@@ -59,6 +58,9 @@ env = [
'DASHBOARD_PASSWORD=${dashboard_password}',
'SECRET_KEY_BASE=${secret_key_base}',
'VAULT_ENC_KEY=${vault_enc_key}',
+'PG_META_CRYPTO_KEY=${pg_meta_crypto_key}',
+'LOGFLARE_PUBLIC_ACCESS_TOKEN=${logflare_public_access_token}',
+'LOGFLARE_PRIVATE_ACCESS_TOKEN=${logflare_private_access_token}',
'',
'',
'############',
@@ -68,7 +70,7 @@ env = [
'POSTGRES_HOST=db',
'POSTGRES_DB=postgres',
'POSTGRES_PORT=5432',
-'# default user is postgres',
+'POSTGRES_USER=postgres',
'',
'',
'############',
@@ -77,7 +79,8 @@ env = [
'POOLER_PROXY_PORT_TRANSACTION=6543',
'POOLER_DEFAULT_POOL_SIZE=20',
'POOLER_MAX_CLIENT_CONN=100',
-'POOLER_TENANT_ID=your-tenant-id',
+'POOLER_TENANT_ID=${pooler_tenant_id}',
+'POOLER_DB_POOL_SIZE=5',
'',
'',
'############',
@@ -94,6 +97,8 @@ env = [
'############',
'',
'PGRST_DB_SCHEMAS=public,storage,graphql_public',
+'PGRST_DB_MAX_ROWS=1000',
+'PGRST_DB_EXTRA_SEARCH_PATH=public',
'',
'',
'############',
@@ -102,10 +107,11 @@ env = [
'',
'## General',
'SITE_URL=http://localhost:3000',
-'ADDITIONAL_REDIRECT_URLS=http://${main_domain}/*,http://localhost:3000/*',
+'ADDITIONAL_REDIRECT_URLS=https://${main_domain}/*,http://localhost:3000/*',
'JWT_EXPIRY=3600',
'DISABLE_SIGNUP=false',
-'API_EXTERNAL_URL=http://${main_domain}',
+'API_EXTERNAL_URL=https://${main_domain}',
+'JWT_KEYS=[]',
'',
'## Mailer Config',
'MAILER_URLPATHS_CONFIRMATION="/auth/v1/verify"',
@@ -136,12 +142,19 @@ env = [
'STUDIO_DEFAULT_ORGANIZATION=Default Organization',
'STUDIO_DEFAULT_PROJECT=Default Project',
'',
-'STUDIO_PORT=3000',
-'# replace if you intend to use Studio outside of localhost',
-'SUPABASE_PUBLIC_URL=http://${main_domain}',
+'SUPABASE_PUBLIC_URL=https://${main_domain}',
'',
-'# Enable webp support',
-'IMGPROXY_ENABLE_WEBP_DETECTION=true',
+'############',
+'# Storage - local file backend (default). Edit docker-compose.yml storage env for S3/MinIO.',
+'############',
+'',
+'GLOBAL_S3_BUCKET=stub',
+'REGION=stub',
+'STORAGE_TENANT_ID=stub',
+'S3_PROTOCOL_ACCESS_KEY_ID=${s3_protocol_access_key_id}',
+'S3_PROTOCOL_ACCESS_KEY_SECRET=${s3_protocol_access_key_secret}',
+'',
+'IMGPROXY_AUTO_WEBP=true',
'',
'# Add your OpenAI API key to enable SQL Editor Assistant',
'OPENAI_API_KEY=',
@@ -156,14 +169,8 @@ env = [
'',
'############',
'# Logs - Configuration for Logflare',
-'# 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=${logflare_api_key}',
-'',
'# Docker socket location - this value will differ depending on your OS',
'DOCKER_SOCKET_LOCATION=/var/run/docker.sock',
'',
@@ -171,6 +178,40 @@ env = [
'GOOGLE_PROJECT_ID=GOOGLE_PROJECT_ID',
'GOOGLE_PROJECT_NUMBER=GOOGLE_PROJECT_NUMBER']
+[[config.mounts]]
+filePath = "/volumes/api/kong-entrypoint.sh"
+content = """#!/bin/bash
+# Custom entrypoint for Kong that builds Lua expressions for request-transformer
+# and performs environment variable substitution in the declarative config.
+
+if [ -n "$SUPABASE_SECRET_KEY" ] && [ -n "$SUPABASE_PUBLISHABLE_KEY" ]; then
+ export LUA_AUTH_EXPR="\$((headers.authorization ~= nil and headers.authorization:sub(1, 10) ~= 'Bearer sb_' and headers.authorization) or (headers.apikey == '$SUPABASE_SECRET_KEY' and 'Bearer $SERVICE_ROLE_KEY_ASYMMETRIC') or (headers.apikey == '$SUPABASE_PUBLISHABLE_KEY' and 'Bearer $ANON_KEY_ASYMMETRIC') or headers.apikey)"
+ export LUA_RT_WS_EXPR="\$((query_params.apikey == '$SUPABASE_SECRET_KEY' and '$SERVICE_ROLE_KEY_ASYMMETRIC') or (query_params.apikey == '$SUPABASE_PUBLISHABLE_KEY' and '$ANON_KEY_ASYMMETRIC') or query_params.apikey)"
+else
+ export LUA_AUTH_EXPR="\$((headers.authorization ~= nil and headers.authorization:sub(1, 10) ~= 'Bearer sb_' and headers.authorization) or headers.apikey)"
+ export LUA_RT_WS_EXPR="\$(query_params.apikey)"
+fi
+
+awk '{
+ result = ""
+ rest = $0
+ while (match(rest, /\$[A-Za-z_][A-Za-z_0-9]*/)) {
+ varname = substr(rest, RSTART + 1, RLENGTH - 1)
+ if (varname in ENVIRON) {
+ result = result substr(rest, 1, RSTART - 1) ENVIRON[varname]
+ } else {
+ result = result substr(rest, 1, RSTART + RLENGTH - 1)
+ }
+ rest = substr(rest, RSTART + RLENGTH)
+ }
+ print result rest
+}' /home/kong/temp.yml > "$KONG_DECLARATIVE_CONFIG"
+
+sed -i '/^[[:space:]]*- key:[[:space:]]*$/d' "$KONG_DECLARATIVE_CONFIG"
+
+exec /entrypoint.sh kong docker-start
+"""
+
[[config.mounts]]
filePath = "/volumes/api/kong.yml"
content = """_format_version: '2.1'
@@ -184,9 +225,11 @@ consumers:
- username: anon
keyauth_credentials:
- key: $SUPABASE_ANON_KEY
+ - key: $SUPABASE_PUBLISHABLE_KEY
- username: service_role
keyauth_credentials:
- key: $SUPABASE_SERVICE_KEY
+ - key: $SUPABASE_SECRET_KEY
###
### Access Control List
@@ -202,8 +245,8 @@ acls:
###
basicauth_credentials:
- consumer: DASHBOARD
- username: $DASHBOARD_USERNAME
- password: $DASHBOARD_PASSWORD
+ username: '$DASHBOARD_USERNAME'
+ password: '$DASHBOARD_PASSWORD'
###
### API Routes
@@ -237,6 +280,33 @@ services:
- /auth/v1/authorize
plugins:
- name: cors
+ - name: auth-v1-open-jwks
+ url: http://auth:9999/.well-known/jwks.json
+ routes:
+ - name: auth-v1-open-jwks
+ strip_path: true
+ paths:
+ - /auth/v1/.well-known/jwks.json
+ plugins:
+ - name: cors
+ - name: auth-v1-open-sso-acs
+ url: http://auth:9999/sso/saml/acs
+ routes:
+ - name: auth-v1-open-sso-acs
+ strip_path: true
+ paths:
+ - /sso/saml/acs
+ plugins:
+ - name: cors
+ - name: auth-v1-open-sso-metadata
+ url: http://auth:9999/sso/saml/metadata
+ routes:
+ - name: auth-v1-open-sso-metadata
+ strip_path: true
+ paths:
+ - /sso/saml/metadata
+ plugins:
+ - name: cors
## Secure Auth routes
- name: auth-v1
@@ -252,6 +322,14 @@ services:
- name: key-auth
config:
hide_credentials: false
+ - name: request-transformer
+ config:
+ add:
+ headers:
+ - "Authorization: $LUA_AUTH_EXPR"
+ replace:
+ headers:
+ - "Authorization: $LUA_AUTH_EXPR"
- name: acl
config:
hide_groups_header: true
@@ -272,7 +350,15 @@ services:
- name: cors
- name: key-auth
config:
- hide_credentials: true
+ hide_credentials: false
+ - name: request-transformer
+ config:
+ add:
+ headers:
+ - "Authorization: $LUA_AUTH_EXPR"
+ replace:
+ headers:
+ - "Authorization: $LUA_AUTH_EXPR"
- name: acl
config:
hide_groups_header: true
@@ -298,7 +384,11 @@ services:
config:
add:
headers:
- - Content-Profile:graphql_public
+ - "Content-Profile: graphql_public"
+ - "Authorization: $LUA_AUTH_EXPR"
+ replace:
+ headers:
+ - "Authorization: $LUA_AUTH_EXPR"
- name: acl
config:
hide_groups_header: true
@@ -309,7 +399,7 @@ services:
## Secure Realtime routes
- name: realtime-v1-ws
_comment: 'Realtime: /realtime/v1/* -> ws://realtime:4000/socket/*'
- url: http://realtime-dev.${CONTAINER_PREFIX}-realtime:4000/socket
+ url: http://realtime:4000/socket
protocol: ws
routes:
- name: realtime-v1-ws
@@ -321,6 +411,14 @@ services:
- name: key-auth
config:
hide_credentials: false
+ - name: request-transformer
+ config:
+ add:
+ headers:
+ - "x-api-key:$LUA_RT_WS_EXPR"
+ replace:
+ querystring:
+ - "apikey:$LUA_RT_WS_EXPR"
- name: acl
config:
hide_groups_header: true
@@ -328,8 +426,8 @@ services:
- admin
- anon
- name: realtime-v1-rest
- _comment: 'Realtime: /realtime/v1/* -> ws://realtime:4000/socket/*'
- url: http://realtime-dev.${CONTAINER_PREFIX}-realtime:4000/api
+ _comment: 'Realtime: /realtime/v1/api/* -> http://realtime:4000/api/*'
+ url: http://realtime:4000/api
protocol: http
routes:
- name: realtime-v1-rest
@@ -341,13 +439,22 @@ services:
- name: key-auth
config:
hide_credentials: false
+ - name: request-transformer
+ config:
+ add:
+ headers:
+ - "Authorization: $LUA_AUTH_EXPR"
+ replace:
+ headers:
+ - "Authorization: $LUA_AUTH_EXPR"
- name: acl
config:
hide_groups_header: true
allow:
- admin
- anon
- ## Storage routes: the storage server manages its own auth
+
+ ## Storage routes
- name: storage-v1
_comment: 'Storage: /storage/v1/* -> http://storage:5000/*'
url: http://storage:5000/
@@ -358,11 +465,28 @@ services:
- /storage/v1/
plugins:
- name: cors
+ - name: request-transformer
+ config:
+ add:
+ headers:
+ - "Authorization: $LUA_AUTH_EXPR"
+ replace:
+ headers:
+ - "Authorization: $LUA_AUTH_EXPR"
+ - name: post-function
+ config:
+ access:
+ - |
+ local auth = kong.request.get_header("authorization")
+ if auth == nil or auth == "" or auth:find("^%s*$") then
+ kong.service.request.clear_header("authorization")
+ end
## Edge Functions routes
- name: functions-v1
_comment: 'Edge Functions: /functions/v1/* -> http://functions:9000/*'
url: http://functions:9000/
+ read_timeout: 150000
routes:
- name: functions-v1-all
strip_path: true
@@ -371,15 +495,16 @@ services:
plugins:
- name: cors
- ## Analytics routes
- - name: analytics-v1
- _comment: 'Analytics: /analytics/v1/* -> http://logflare:4000/*'
- url: http://analytics:4000/
+ ## OAuth 2.0 Authorization Server Metadata
+ - name: well-known-oauth
+ url: http://auth:9999/.well-known/oauth-authorization-server
routes:
- - name: analytics-v1-all
+ - name: well-known-oauth
strip_path: true
paths:
- - /analytics/v1/
+ - /.well-known/oauth-authorization-server
+ plugins:
+ - name: cors
## Secure Database routes
- name: meta
@@ -400,6 +525,32 @@ services:
allow:
- admin
+ - name: mcp-blocker
+ url: http://studio:3000/api/mcp
+ routes:
+ - name: mcp-blocker-route
+ strip_path: true
+ paths:
+ - /api/mcp
+ plugins:
+ - name: request-termination
+ config:
+ status_code: 403
+ message: "Access is forbidden."
+
+ - name: mcp
+ url: http://studio:3000/api/mcp
+ routes:
+ - name: mcp
+ strip_path: true
+ paths:
+ - /mcp
+ plugins:
+ - name: request-termination
+ config:
+ status_code: 403
+ message: "Access is forbidden."
+
## Protected Dashboard - catch all remaining routes
- name: dashboard
_comment: 'Studio: /* -> http://studio:3000/*'
@@ -416,6 +567,10 @@ services:
hide_credentials: true
"""
+[[config.mounts]]
+filePath = "/volumes/snippets/.gitkeep"
+content = ""
+
[[config.mounts]]
filePath = "/volumes/db/init/data.sql"
content = ""
@@ -717,14 +872,25 @@ serve(async () => {
[[config.mounts]]
filePath = "/volumes/functions/main/index.ts"
-content = """import { serve } from 'https://deno.land/std@0.131.0/http/server.ts'
-import * as jose from 'https://deno.land/x/jose@v4.14.4/index.ts'
+content = """import * as jose from 'https://deno.land/x/jose@v4.14.4/index.ts'
console.log('main function started')
const JWT_SECRET = Deno.env.get('JWT_SECRET')
+const SUPABASE_URL = Deno.env.get('SUPABASE_URL')
const VERIFY_JWT = Deno.env.get('VERIFY_JWT') === 'true'
+let SUPABASE_JWT_KEYS: ReturnType | null = null
+if (SUPABASE_URL) {
+ try {
+ SUPABASE_JWT_KEYS = jose.createRemoteJWKSet(
+ new URL('/auth/v1/.well-known/jwks.json', SUPABASE_URL)
+ )
+ } catch (e) {
+ console.error('Failed to fetch JWKS from SUPABASE_URL:', e)
+ }
+}
+
function getAuthToken(req: Request) {
const authHeader = req.headers.get('authorization')
if (!authHeader) {
@@ -737,25 +903,53 @@ function getAuthToken(req: Request) {
return token
}
-async function verifyJWT(jwt: string): Promise {
+async function isValidLegacyJWT(jwt: string): Promise {
+ if (!JWT_SECRET) {
+ console.error('JWT_SECRET not available for HS256 token verification')
+ return false
+ }
const encoder = new TextEncoder()
const secretKey = encoder.encode(JWT_SECRET)
try {
await jose.jwtVerify(jwt, secretKey)
- } catch (err) {
- console.error(err)
+ } catch (e) {
+ console.error('Symmetric Legacy JWT verification error', e)
return false
}
return true
}
-serve(async (req: Request) => {
+async function isValidJWT(jwt: string): Promise {
+ if (!SUPABASE_JWT_KEYS) {
+ console.error('JWKS not available for ES256/RS256 token verification')
+ return false
+ }
+ try {
+ await jose.jwtVerify(jwt, SUPABASE_JWT_KEYS)
+ } catch (e) {
+ console.error('Asymmetric JWT verification error', e)
+ return false
+ }
+ return true
+}
+
+async function isValidHybridJWT(jwt: string): Promise {
+ const { alg: jwtAlgorithm } = jose.decodeProtectedHeader(jwt)
+ if (jwtAlgorithm === 'HS256') {
+ return await isValidLegacyJWT(jwt)
+ }
+ if (jwtAlgorithm === 'ES256' || jwtAlgorithm === 'RS256') {
+ return await isValidJWT(jwt)
+ }
+ return false
+}
+
+Deno.serve(async (req: Request) => {
if (req.method !== 'OPTIONS' && VERIFY_JWT) {
try {
const token = getAuthToken(req)
- const isValidJWT = await verifyJWT(token)
-
- if (!isValidJWT) {
+ const isValid = await isValidHybridJWT(token)
+ if (!isValid) {
return new Response(JSON.stringify({ msg: 'Invalid JWT' }), {
status: 401,
headers: { 'Content-Type': 'application/json' },
@@ -822,8 +1016,6 @@ content = """api:
sources:
docker_host:
type: docker_logs
- exclude_containers:
- - ${container_name_prefix}-vector
transforms:
project_logs:
@@ -833,7 +1025,15 @@ transforms:
source: |-
.project = "default"
.event_message = del(.message)
- .appname = replace!(del(.container_name), "${container_name_prefix}", "supabase")
+ compose_service, label_err = get(.label, ["com.docker.compose.service"])
+ if label_err != null || compose_service == null {
+ abort
+ }
+ compose_service = to_string!(compose_service)
+ if compose_service == "vector" {
+ abort
+ }
+ .appname = "supabase-" + compose_service
del(.container_created_at)
del(.container_id)
del(.source_type)
@@ -847,12 +1047,12 @@ transforms:
inputs:
- project_logs
route:
- kong: '.appname == "supabase-kong"'
+ kong: '.appname == "supabase-kong" || .appname == "supabase-envoy"'
auth: '.appname == "supabase-auth"'
rest: '.appname == "supabase-rest"'
- realtime: '.appname == "realtime-dev.${CONTAINER_PREFIX}-realtime"'
+ realtime: '.appname == "supabase-realtime"'
storage: '.appname == "supabase-storage"'
- functions: '.appname == "supabase-edge-functions"'
+ functions: '.appname == "supabase-functions"'
db: '.appname == "supabase-db"'
# Ignores non nginx errors since they are related with kong booting up
kong_logs:
@@ -866,15 +1066,17 @@ transforms:
.metadata.request.headers.referer = req.referer
.metadata.request.headers.user_agent = req.agent
.metadata.request.headers.cf_connecting_ip = req.client
- .metadata.request.method = req.method
- .metadata.request.path = req.path
- .metadata.request.protocol = req.protocol
.metadata.response.status_code = req.status
+ url, split_err = split(req.request, " ")
+ if split_err == null {
+ .metadata.request.method = url[0]
+ .metadata.request.path = url[1]
+ .metadata.request.protocol = url[2]
+ }
}
if err != null {
abort
}
- # Ignores non nginx errors since they are related with kong booting up
kong_err:
type: remap
inputs:
@@ -918,14 +1120,18 @@ transforms:
parsed, err = parse_regex(.event_message, r'^(?P