diff --git a/AGENTS.md b/AGENTS.md index c34d6beb..753da746 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -170,6 +170,16 @@ This document provides essential context for AI models interacting with this pro - **Env:** Array of strings: `env = ["KEY=VALUE", "DB_PASSWORD=${db_pass}"]` - **Available helpers:** `${domain}`, `${password:length}`, `${base64:length}`, `${hash:length}`, `${uuid}`, `${randomPort}`, `${email}`, `${username}`, `${timestamp}`, `${timestamps:datetime}`, `${timestampms:datetime}`, `${jwt:secret_var:payload_var}` - **JWT helper example:** `${jwt:mysecret:mypayload}` with payload containing `exp: ${timestamps:2030-01-01T00:00:00Z}` + - **Volume bind mounts (in docker-compose.yml):** When mounting host paths, do NOT use absolute paths like `"/folder:/path/in/container"`. Use relative paths instead: + ```yaml + # Invalid + volumes: + - "/folder:/path/in/container" ❌ + # Valid + volumes: + - "../files/my-database:/var/lib/mysql" ✅ + - "../files/my-configs:/etc/my-app/config" ✅ + ``` - **meta.json Requirements:** diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2671d5af..967ef6f2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -20,6 +20,11 @@ This project adheres to the [Contributor Covenant Code of Conduct](https://www.c For larger changes or questions, open an issue first to discuss your ideas. +### Pull Request Guidelines + +- **Keep PRs small and focused.** Avoid very large PRs; prefer several smaller PRs (e.g., one template or one logical change per PR). This speeds up review and keeps the history clear. +- **Test before submitting.** Any PR that has not been tested by the contributor will be closed. This keeps the PR queue tidy and ensures that only contributions that have been verified by their authors are considered. + ## Adding a New Template To add a new template, follow these steps: diff --git a/blueprints/alist/docker-compose.yml b/blueprints/alist/docker-compose.yml index 9ff67c94..1577387f 100644 --- a/blueprints/alist/docker-compose.yml +++ b/blueprints/alist/docker-compose.yml @@ -1,7 +1,7 @@ version: '3.3' services: alist: - image: xhofe/alist:v3.41.0 + image: xhofe/alist:v3.55.0 volumes: - alist-data:/opt/alist/data environment: diff --git a/blueprints/appsmith/docker-compose.yml b/blueprints/appsmith/docker-compose.yml index f520ee36..e22be557 100644 --- a/blueprints/appsmith/docker-compose.yml +++ b/blueprints/appsmith/docker-compose.yml @@ -1,6 +1,10 @@ version: "3.8" services: appsmith: - image: index.docker.io/appsmith/appsmith-ee:v1.29 + image: appsmith/appsmith-ee:v1.94 volumes: - - ../files/stacks:/appsmith-stacks + - appsmith-data:/appsmith-stacks + restart: unless-stopped + +volumes: + appsmith-data: \ No newline at end of file diff --git a/blueprints/budibase/docker-compose.yml b/blueprints/budibase/docker-compose.yml index 92ad3288..17d08eef 100644 --- a/blueprints/budibase/docker-compose.yml +++ b/blueprints/budibase/docker-compose.yml @@ -1,8 +1,8 @@ services: - apps: - image: budibase.docker.scarf.sh/budibase/apps:3.5.3 - restart: unless-stopped + apps: + image: budibase/apps:3.23.47 + restart: unless-stopped environment: SELF_HOSTED: 1 LOG_LEVEL: info @@ -39,10 +39,10 @@ services: timeout: 15s retries: 5 start_period: 10s - worker: - image: budibase.docker.scarf.sh/budibase/worker:3.2.25 - restart: unless-stopped + worker: + image: budibase/worker:3.23.47 + restart: unless-stopped environment: SELF_HOSTED: 1 LOG_LEVEL: info @@ -78,10 +78,10 @@ services: timeout: 15s retries: 5 start_period: 10s - minio: - image: minio/minio:RELEASE.2024-11-07T00-52-20Z - restart: unless-stopped + minio: + image: minio/minio:RELEASE.2025-09-07T16-13-09Z + restart: unless-stopped volumes: - 'minio_data:/data' environment: @@ -98,10 +98,10 @@ services: interval: 30s timeout: 20s retries: 3 - proxy: - image: budibase/proxy:3.2.25 - restart: unless-stopped + proxy: + image: budibase/proxy:3.23.47 + restart: unless-stopped environment: PROXY_RATE_LIMIT_WEBHOOKS_PER_SECOND: 10 PROXY_RATE_LIMIT_API_PER_SECOND: 20 @@ -130,10 +130,10 @@ services: timeout: 15s retries: 5 start_period: 10s + couchdb: image: budibase/couchdb:v3.3.3 restart: unless-stopped - environment: COUCHDB_USER: budibase COUCHDB_PASSWORD: ${BB_COUCHDB_PASSWORD} @@ -150,9 +150,9 @@ services: start_period: 10s volumes: - 'couchdb3_data:/opt/couchdb/data' - redis: - image: redis:7.2-alpine + redis: + image: redis:8.4-alpine restart: unless-stopped command: 'redis-server --requirepass "${BB_REDIS_PASSWORD}"' volumes: @@ -168,22 +168,9 @@ services: timeout: 15s retries: 5 start_period: 10s - watchtower: - restart: unless-stopped - - image: containrrr/watchtower:1.7.1 - volumes: - - '/var/run/docker.sock:/var/run/docker.sock' - command: '--debug --http-api-update bbapps bbworker bbproxy' - environment: - WATCHTOWER_HTTP_API: true - WATCHTOWER_HTTP_API_TOKEN: ${BB_WATCHTOWER_PASSWORD} - WATCHTOWER_CLEANUP: true - labels: - - com.centurylinklabs.watchtower.enable=false volumes: minio_data: couchdb3_data: - redis_data: \ No newline at end of file + redis_data: diff --git a/blueprints/habitica/docker-compose.yml b/blueprints/habitica/docker-compose.yml index af226516..3990e571 100644 --- a/blueprints/habitica/docker-compose.yml +++ b/blueprints/habitica/docker-compose.yml @@ -1,13 +1,18 @@ -version: "3.8" - services: server: image: docker.io/awinterstein/habitica-server:latest restart: unless-stopped depends_on: - - mongo + mongo: + condition: service_healthy environment: - - NODE_DB_URI=mongodb://mongo/habitica + NODE_DB_URI: "mongodb://${MONGO_HABITICA_USER}:${MONGO_HABITICA_PASSWORD}@mongo/habitica?authSource=habitica" + INVITE_ONLY: "${INVITE_ONLY}" + EMAIL_SERVER_URL: "${EMAIL_SERVER_URL}" + EMAIL_SERVER_PORT: "${EMAIL_SERVER_PORT}" + EMAIL_SERVER_AUTH_USER: "${EMAIL_SERVER_AUTH_USER}" + EMAIL_SERVER_AUTH_PASSWORD: "${EMAIL_SERVER_AUTH_PASSWORD}" + ADMIN_EMAIL: "${ADMIN_EMAIL}" client: image: docker.io/awinterstein/habitica-client:latest @@ -20,12 +25,64 @@ services: mongo: image: docker.io/mongo:latest restart: unless-stopped - command: ["--replSet", "rs", "--bind_ip_all", "--port", "27017"] + command: > + bash -c " + echo \"${MONGO_KEYFILE_CONTENT}\" > /etc/mongo-keyfile && + chown 999:999 /etc/mongo-keyfile && + chmod 400 /etc/mongo-keyfile && + exec docker-entrypoint.sh mongod --replSet rs --bind_ip_all --port 27017 --keyFile /etc/mongo-keyfile + " + environment: + MONGO_INITDB_ROOT_USERNAME: ${MONGO_ADMIN_USER} + MONGO_INITDB_ROOT_PASSWORD: ${MONGO_ADMIN_PASSWORD} + MONGO_KEYFILE_CONTENT: ${MONGO_KEYFILE_CONTENT} + MONGO_HABITICA_USER: ${MONGO_HABITICA_USER} + MONGO_HABITICA_PASSWORD: ${MONGO_HABITICA_PASSWORD} + # --------------------------------------------------------- + # SMART HEALTHCHECK: Auto-fixes Hostname Mismatches for replicaSet + # --------------------------------------------------------- healthcheck: - test: echo "try { rs.status() } catch (err) { rs.initiate() }" | mongosh --port 27017 --quiet - interval: 10s - timeout: 30s - retries: 30 + test: | + mongosh --port 27017 --quiet -u "${MONGO_ADMIN_USER}" -p "${MONGO_ADMIN_PASSWORD}" --authenticationDatabase admin --eval " + try { + // 1. Hostname Fix + const config = rs.conf(); + const currentHost = require('os').hostname() + ':27017'; + if (config.members[0].host !== currentHost) { + config.members[0].host = currentHost; + rs.reconfig(config, { force: true }); + } + + // 2. User Creation Logic + const targetDb = db.getSiblingDB('habitica'); + const hUser = process.env.MONGO_HABITICA_USER; + const hPass = process.env.MONGO_HABITICA_PASSWORD; + + // We can only check/create users if we are Primary + if (rs.isMaster().ismaster) { + if (!targetDb.getUser(hUser)) { + print('Creating missing user ' + hUser + '...'); + targetDb.createUser({ user: hUser, pwd: hPass, roles: ['readWrite'] }); + } + // SUCCESS: User exists and we are Primary + quit(0); + } else { + // We are not Primary yet (still electing), so we cannot confirm user exists. + // Fail the check so the dependent app waits. + print('Waiting for Primary state...'); + quit(1); + } + } catch (err) { + // If not initialized, initiate and FAIL this check so we wait for the next cycle + try { + rs.initiate({ _id: 'rs', members: [{ _id: 0, host: require('os').hostname() + ':27017' }] }); + } catch (e) {} + quit(1); + } + " + interval: 5s + timeout: 10s + retries: 20 volumes: - habitica-mongo-data:/data/db diff --git a/blueprints/habitica/template.toml b/blueprints/habitica/template.toml index 3888ae24..a8cb5fc6 100644 --- a/blueprints/habitica/template.toml +++ b/blueprints/habitica/template.toml @@ -1,6 +1,9 @@ [variables] main_domain = "${domain}" mail_password = "${password:32}" +mongo_key = "${base64:756}" +mongo_admin_password = "${password}" +mongo_habitica_password = "${password}" [config] [[config.domains]] @@ -9,16 +12,21 @@ port = 80 host = "habitica.${main_domain}" [config.env] - -BASE_URL="https://habitica.${main_domain}" -INVITE_ONLY="false" -EMAIL_SERVER_URL="mail.example.com" -EMAIL_SERVER_PORT="587" -EMAIL_SERVER_AUTH_USER="mail_user" -EMAIL_SERVER_AUTH_PASSWORD="${mail_password}" +BASE_URL = "https://habitica.${main_domain}" +INVITE_ONLY = "false" +EMAIL_SERVER_URL = "mail.example.com" +EMAIL_SERVER_PORT = "587" +EMAIL_SERVER_AUTH_USER = "mail_user" +EMAIL_SERVER_AUTH_PASSWORD = "${mail_password}" +MONGO_KEYFILE_CONTENT = "${mongo_key}" +MONGO_ADMIN_USER = "admin" +MONGO_ADMIN_PASSWORD = "${mongo_admin_password}" +MONGO_HABITICA_USER = "habitica" +MONGO_HABITICA_PASSWORD = "${mongo_habitica_password}" +ADMIN_EMAIL = "no-reply@${main_domain}" [[config.mounts]] serviceName = "mongo" type = "volume" source = "habitica-mongo-data" -target = "/data/db" \ No newline at end of file +target = "/data/db" diff --git a/blueprints/invoiceshelf/docker-compose.yml b/blueprints/invoiceshelf/docker-compose.yml index 8d2c8265..bc4e8ff0 100644 --- a/blueprints/invoiceshelf/docker-compose.yml +++ b/blueprints/invoiceshelf/docker-compose.yml @@ -20,8 +20,7 @@ services: image: invoiceshelf/invoiceshelf:nightly volumes: - - invoiceshelf-app-data:/data - - invoiceshelf-app-conf:/conf + - invoiceshelf-storage:/var/www/html/storage environment: - PHP_TZ=UTC - TIMEZONE=UTC @@ -49,5 +48,4 @@ services: volumes: invoiceshelf-postgres-data: - invoiceshelf-app-data: - invoiceshelf-app-conf: \ No newline at end of file + invoiceshelf-storage: diff --git a/blueprints/ipfs/docker-compose.yml b/blueprints/ipfs/docker-compose.yml new file mode 100644 index 00000000..4275f553 --- /dev/null +++ b/blueprints/ipfs/docker-compose.yml @@ -0,0 +1,17 @@ +version: "3.8" +services: + ipfs: + image: ipfs/kubo:latest + restart: unless-stopped + environment: + - IPFS_PROFILE=server + volumes: + - ipfs_data:/data/ipfs + - ipfs_staging:/export + ports: + - 4001 + - 8080 + - 5001 +volumes: + ipfs_data: {} + ipfs_staging: {} diff --git a/blueprints/ipfs/ipfs.svg b/blueprints/ipfs/ipfs.svg new file mode 100644 index 00000000..1b90c313 --- /dev/null +++ b/blueprints/ipfs/ipfs.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/blueprints/ipfs/template.toml b/blueprints/ipfs/template.toml new file mode 100644 index 00000000..89d4677e --- /dev/null +++ b/blueprints/ipfs/template.toml @@ -0,0 +1,25 @@ +[variables] +gateway_domain = "${domain}" +api_domain = "${domain}" + +[config] +env = [] + +[[config.domains]] +serviceName = "ipfs" +port = 8080 +host = "${gateway_domain}" + +[[config.domains]] +serviceName = "ipfs" +port = 5001 +host = "${api_domain}" + +[[config.mounts]] +filePath = "/container-init.d/001-configure-api.sh" +content = """ +#!/bin/sh +ipfs config Addresses.API /ip4/0.0.0.0/tcp/5001 +ipfs config --json API.HTTPHeaders.Access-Control-Allow-Origin '["*"]' +ipfs config --json API.HTTPHeaders.Access-Control-Allow-Methods '["PUT", "POST", "GET"]' +""" diff --git a/blueprints/nextcloud-aio/docker-compose.yml b/blueprints/nextcloud-aio/docker-compose.yml index 1f4e43e6..f262b157 100644 --- a/blueprints/nextcloud-aio/docker-compose.yml +++ b/blueprints/nextcloud-aio/docker-compose.yml @@ -1,6 +1,6 @@ services: nextcloud: - image: nextcloud:30.0.2 + image: nextcloud:32.0.5 restart: always ports: diff --git a/blueprints/postgres-pgdog/docker-compose.yml b/blueprints/postgres-pgdog/docker-compose.yml new file mode 100644 index 00000000..f5164d9c --- /dev/null +++ b/blueprints/postgres-pgdog/docker-compose.yml @@ -0,0 +1,33 @@ +services: + postgres-pgdog: + image: ${PGDOG_IMAGE} + restart: unless-stopped + # Uncomment 'ports' settings below to enable external access + # ports: + # - "6432:6432" + volumes: + - ../files/pgdog.toml:/pgdog/pgdog.toml + - ../files/users.toml:/pgdog/users.toml + environment: + - RUST_LOG=${RUST_LOG} + depends_on: + postgres: + condition: service_healthy + + postgres: + image: ${POSTGRES_IMAGE} + restart: unless-stopped + environment: + - POSTGRES_USER=${POSTGRES_USER} + - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} + - POSTGRES_DB=${POSTGRES_DB} + volumes: + - postgres-data:/var/lib/postgresql + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"] + interval: 10s + timeout: 5s + retries: 5 + +volumes: + postgres-data: diff --git a/blueprints/postgres-pgdog/postgres-pgdog.png b/blueprints/postgres-pgdog/postgres-pgdog.png new file mode 100644 index 00000000..bbc4aae7 Binary files /dev/null and b/blueprints/postgres-pgdog/postgres-pgdog.png differ diff --git a/blueprints/postgres-pgdog/template.toml b/blueprints/postgres-pgdog/template.toml new file mode 100644 index 00000000..2ffc4ec0 --- /dev/null +++ b/blueprints/postgres-pgdog/template.toml @@ -0,0 +1,36 @@ +[variables] +postgres_user = "${username}" +postgres_password = "${password:32}" +postgres_db = "postgres" +pgdog_image = "ghcr.io/pgdogdev/pgdog:v0.1.26" +postgres_image = "postgres:18-alpine" + +[[config.mounts]] +filePath = "pgdog.toml" +content = """ +[general] +host = "0.0.0.0" +port = 6432 + +[[databases]] +name = "${postgres_db}" +host = "postgres" +port = 5432 +""" + +[[config.mounts]] +filePath = "users.toml" +content = """ +[[users]] +name = "${postgres_user}" +database = "${postgres_db}" +password = "${postgres_password}" +""" + +[config.env] +POSTGRES_USER = "${postgres_user}" +POSTGRES_PASSWORD = "${postgres_password}" +POSTGRES_DB = "${postgres_db}" +PGDOG_IMAGE = "${pgdog_image}" +POSTGRES_IMAGE = "${postgres_image}" +RUST_LOG = "info" diff --git a/blueprints/pulse/docker-compose.yml b/blueprints/pulse/docker-compose.yml new file mode 100644 index 00000000..074aec07 --- /dev/null +++ b/blueprints/pulse/docker-compose.yml @@ -0,0 +1,22 @@ +version: "3.8" +services: + pulse: + image: rcourtman/pulse:5.1 + restart: always + expose: + - 7655 + volumes: + - pulse_data:/data + - /var/run/docker.sock:/var/run/docker.sock + environment: + - PULSE_AUTH_USER=${PULSE_AUTH_USER} + - PULSE_AUTH_PASS=${PULSE_AUTH_PASS} + healthcheck: + test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:7655/api/health"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + +volumes: + pulse_data: \ No newline at end of file diff --git a/blueprints/pulse/pulse.svg b/blueprints/pulse/pulse.svg new file mode 100644 index 00000000..428a6e54 --- /dev/null +++ b/blueprints/pulse/pulse.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/blueprints/pulse/template.toml b/blueprints/pulse/template.toml new file mode 100644 index 00000000..865990c4 --- /dev/null +++ b/blueprints/pulse/template.toml @@ -0,0 +1,13 @@ +[variables] +main_domain = "${domain}" +pulse_auth_user = "${username}" +pulse_auth_pass = "${password:32}" + +[config] +env = ["PULSE_AUTH_USER=${pulse_auth_user}", "PULSE_AUTH_PASS=${pulse_auth_pass}"] +mounts = [] + +[[config.domains]] +serviceName = "pulse" +port = 7_655 +host = "${main_domain}" \ No newline at end of file diff --git a/blueprints/seaweedfs/docker-compose.yml b/blueprints/seaweedfs/docker-compose.yml new file mode 100644 index 00000000..ca4a0968 --- /dev/null +++ b/blueprints/seaweedfs/docker-compose.yml @@ -0,0 +1,114 @@ +services: + master: + image: chrislusf/seaweedfs:4.02 + command: > + -v=0 + master + -volumeSizeLimitMB=10240 + -ip=master + -ip.bind=0.0.0.0 + -port=9333 + -mdir=/data/master + volumes: + - seaweedfs-master:/data/master + restart: unless-stopped + healthcheck: + test: ["CMD", "wget", "-q", "--spider", "http://localhost:9333"] + interval: 30s + timeout: 10s + retries: 3 + expose: + - 9333 + deploy: + resources: + limits: + memory: 512M + reservations: + memory: 256M + + volume: + image: chrislusf/seaweedfs:4.02 + command: > + -v=0 + volume + -mserver="master:9333" + -port=8080 + -dir=/data/volume + -max=100 + volumes: + - seaweedfs-volume:/data/volume + depends_on: + master: + condition: service_healthy + restart: unless-stopped + expose: + - 8080 + deploy: + resources: + limits: + memory: 1G + reservations: + memory: 512M + + filer: + image: chrislusf/seaweedfs:4.02 + command: > + -v=0 + filer + -defaultReplicaPlacement=000 + -master="master:9333" + -ip=filer + -ip.bind=0.0.0.0 + -port=8888 + environment: + - WEED_MASTER=master:9333 + volumes: + - seaweedfs-filer:/data + depends_on: + - master + - volume + restart: unless-stopped + # # Secure the GUI with username/password + # labels: + # # htpasswd -nb admin admin + # - "traefik.http.middlewares.basic-auth.basicauth.users=admin:$$apr1$$aLLYxhdC$$ZAW26eJfBRC8qWjCkcZns." + # - "traefik.http.routers.service-name.middlewares=basic-auth" + healthcheck: + test: ["CMD", "wget", "-q", "--spider", "http://localhost:8888"] + interval: 30s + timeout: 10s + retries: 3 + deploy: + resources: + limits: + memory: 1G + reservations: + memory: 512M + expose: + - 8888 + + s3: + image: chrislusf/seaweedfs:4.02 + command: > + -v=0 + s3 + -filer="filer:8888" + -ip.bind=0.0.0.0 + -port=8333 + environment: + - AWS_ACCESS_KEY_ID=${S3_ACCESS_KEY} + - AWS_SECRET_ACCESS_KEY=${S3_SECRET_KEY} + restart: unless-stopped + deploy: + resources: + limits: + memory: 512M + reservations: + memory: 256M + expose: + - 8333 + +volumes: + seaweedfs-master: + seaweedfs-volume: + seaweedfs-filer: diff --git a/blueprints/seaweedfs/seaweedfs.svg b/blueprints/seaweedfs/seaweedfs.svg new file mode 100644 index 00000000..61fce568 --- /dev/null +++ b/blueprints/seaweedfs/seaweedfs.svg @@ -0,0 +1,317 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/blueprints/seaweedfs/template.toml b/blueprints/seaweedfs/template.toml new file mode 100644 index 00000000..a72ae280 --- /dev/null +++ b/blueprints/seaweedfs/template.toml @@ -0,0 +1,27 @@ +[variables] +main_domain = "${domain}" +filer_domain = "filer.${domain}" +master_domain = "master.${domain}" +s3_domain = "s3.${domain}" + +[config] +mounts = [] + +[[config.domains]] +serviceName = "filer" +port = 8888 +host = "${filer_domain}" + +[[config.domains]] +serviceName = "master" +port = 9333 +host = "${master_domain}" + +[[config.domains]] +serviceName = "s3" +port = 8333 +host = "${s3_domain}" + +[config.env] +S3_ACCESS_KEY = "admin" +S3_SECRET_KEY = "${password:16}" diff --git a/blueprints/strapi/docker-compose.yml b/blueprints/strapi/docker-compose.yml new file mode 100644 index 00000000..6ac724fc --- /dev/null +++ b/blueprints/strapi/docker-compose.yml @@ -0,0 +1,58 @@ +# Self-host guide: +# - https://strapi.io/blog/how-to-self-host-your-headless-cms-using-docker-compose + +services: + strapi: + image: elestio/strapi-production:v5.33.0 + environment: + # https://docs.strapi.io/cms/configurations/environment + NODE_ENV: production + STRAPI_TELEMETRY_DISABLED: true + STRAPI_PLUGIN_I18N_INIT_LOCALE_CODE: en + FAST_REFRESH: true + JWT_SECRET: ${JWT_SECRET} + ADMIN_JWT_SECRET: ${ADMIN_JWT_SECRET} + DATABASE_CLIENT: postgres + DATABASE_HOST: strapi_postgres + DATABASE_PORT: 5432 + DATABASE_NAME: strapi + DATABASE_USERNAME: strapi + DATABASE_PASSWORD: ${POSTGRES_PASSWORD} + volumes: + - strapi_data:/srv/app + expose: + - 1337 + depends_on: + - strapi_postgres + healthcheck: + test: + - CMD + - wget + - "-q" + - "--spider" + - "http://127.0.0.1:1337" + start_period: 3s + interval: 30s + timeout: 10s + retries: 5 + + strapi_postgres: + image: postgres:18 + environment: + POSTGRES_DB: strapi + POSTGRES_USER: strapi + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + volumes: + - strapi_postgres_data:/var/lib/postgresql + healthcheck: + test: + - CMD-SHELL + - "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}" + start_period: 3s + interval: 30s + timeout: 10s + retries: 5 + +volumes: + strapi_data: + strapi_postgres_data: diff --git a/blueprints/strapi/strapi.svg b/blueprints/strapi/strapi.svg new file mode 100644 index 00000000..1e4ed993 --- /dev/null +++ b/blueprints/strapi/strapi.svg @@ -0,0 +1,23 @@ + + + + + + + + diff --git a/blueprints/strapi/template.toml b/blueprints/strapi/template.toml new file mode 100644 index 00000000..0acddaf5 --- /dev/null +++ b/blueprints/strapi/template.toml @@ -0,0 +1,15 @@ +[variables] +main_domain = "${domain}" +postgres_password = "${password:32}" +jwt_secret = "${password:32}" +admin_jwt_secret = "${password:32}" + +[[config.domains]] +serviceName = "strapi" +port = 1337 +host = "${main_domain}" + +[config.env] +POSTGRES_PASSWORD = "${postgres_password}" +JWT_SECRET = "${jwt_secret}" +ADMIN_JWT_SECRET = "${admin_jwt_secret}" diff --git a/blueprints/supabase/docker-compose.yml b/blueprints/supabase/docker-compose.yml index 7d4dae81..506ddc90 100644 --- a/blueprints/supabase/docker-compose.yml +++ b/blueprints/supabase/docker-compose.yml @@ -77,6 +77,7 @@ services: SUPABASE_SERVICE_KEY: ${SERVICE_ROLE_KEY} 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' diff --git a/blueprints/supabase/template.toml b/blueprints/supabase/template.toml index 9f35f79c..f70c93cc 100644 --- a/blueprints/supabase/template.toml +++ b/blueprints/supabase/template.toml @@ -309,7 +309,7 @@ services: ## Secure Realtime routes - name: realtime-v1-ws _comment: 'Realtime: /realtime/v1/* -> ws://realtime:4000/socket/*' - url: http://realtime-dev.supabase-realtime:4000/socket + url: http://realtime-dev.${CONTAINER_PREFIX}-realtime:4000/socket protocol: ws routes: - name: realtime-v1-ws @@ -329,7 +329,7 @@ services: - anon - name: realtime-v1-rest _comment: 'Realtime: /realtime/v1/* -> ws://realtime:4000/socket/*' - url: http://realtime-dev.supabase-realtime:4000/api + url: http://realtime-dev.${CONTAINER_PREFIX}-realtime:4000/api protocol: http routes: - name: realtime-v1-rest @@ -850,7 +850,7 @@ transforms: kong: '.appname == "supabase-kong"' auth: '.appname == "supabase-auth"' rest: '.appname == "supabase-rest"' - realtime: '.appname == "realtime-dev.supabase-realtime"' + realtime: '.appname == "realtime-dev.${CONTAINER_PREFIX}-realtime"' storage: '.appname == "supabase-storage"' functions: '.appname == "supabase-edge-functions"' db: '.appname == "supabase-db"' diff --git a/blueprints/superset/docker-compose.yml b/blueprints/superset/docker-compose.yml index 076fe0a8..3a20fd04 100644 --- a/blueprints/superset/docker-compose.yml +++ b/blueprints/superset/docker-compose.yml @@ -15,23 +15,14 @@ # ## NETWORK INSTRUCTIONS # # If you want to connect superset with other internal databases managed by -# Dokploy (on dokploy-network) using internal hostnames, you will need to -# uncomment the `networks` section, both for the superset container and -# at the very bottom of this docker-compose template. +# Dokploy using internal hostnames, you will need to connect the `superset` +# container to those networks. # -# Note that the `superset` service name/hostname will not be unique on the -# global `dokploy-network`. If you plan to: -# -# 1. deploy a second instance of superset on dokploy-network, and -# 2. have other containers on dokploy-network utilise the second instance's -# Superset API (https://superset.apache.org/docs/api) -# -# Please change the service name of the second instance. services: superset: - image: amancevice/superset - restart: always + image: amancevice/superset:6.0.0 + restart: unless-stopped #networks: # - dokploy-network depends_on: @@ -52,14 +43,14 @@ services: REDIS_HOST: superset_redis superset_postgres: - image: postgres - restart: always + image: postgres:18 + restart: unless-stopped environment: POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} POSTGRES_DB: ${POSTGRES_DB} volumes: - - superset_postgres_data:/var/lib/postgresql/data + - superset_postgres_data:/var/lib/postgresql healthcheck: test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"] interval: 30s @@ -67,8 +58,8 @@ services: retries: 3 superset_redis: - image: redis - restart: always + image: redis:8 + restart: unless-stopped volumes: - superset_redis_data:/data command: redis-server --requirepass ${REDIS_PASSWORD} @@ -78,10 +69,6 @@ services: timeout: 10s retries: 3 -#networks: -# dokploy-network: -# external: true - volumes: superset_postgres_data: superset_redis_data: diff --git a/blueprints/superset/template.toml b/blueprints/superset/template.toml index ec4535fd..7cee12fc 100644 --- a/blueprints/superset/template.toml +++ b/blueprints/superset/template.toml @@ -3,7 +3,6 @@ main_domain = "${domain}" secret_key = "${password:30}" postgres_password = "${password:30}" redis_password = "${password:30}" -mapbox_api_key = "" [[config.domains]] serviceName = "superset" @@ -12,7 +11,7 @@ host = "${main_domain}" [config.env] SECRET_KEY = "${secret_key}" -MAPBOX_API_KEY = "${mapbox_api_key}" +MAPBOX_API_KEY = "" POSTGRES_DB = "superset" POSTGRES_USER = "superset" POSTGRES_PASSWORD = "${postgres_password}" diff --git a/blueprints/trilium-next/docker-compose.yml b/blueprints/trilium-next/docker-compose.yml new file mode 100755 index 00000000..6ffc82a5 --- /dev/null +++ b/blueprints/trilium-next/docker-compose.yml @@ -0,0 +1,23 @@ +# Running `docker-compose up` will create/use the "trilium-data" directory in the user home +services: + trilium_next: + # Optionally, replace `latest` with a version tag like `v0.110.3` + # Using `latest` may cause unintended updates to the container + image: triliumnext/trilium:v0.101.3 + # Restart the container unless it was stopped by the user + restart: unless-stopped + environment: + - TRILIUM_DATA_DIR=/home/node/trilium-data + ports: + # By default, Trilium will be available at http://localhost:8080 + # It will also be accessible at http://:8080 + # You might want to limit this with something like Docker Networks, reverse proxies, or firewall rules, + # however be aware that using UFW is known to not work with default Docker installations, see: + # https://docs.docker.com/engine/network/packet-filtering-firewalls/#docker-and-ufw + - "8080" + volumes: + # Unless TRILIUM_DATA_DIR is set, the data will be stored in the "trilium-data" directory in the home directory. + # This can also be changed with by replacing the line below with `- /path/of/your/choice:/home/node/trilium-data + - ${TRILIUM_DATA_DIR:-~/trilium-data}:/home/node/trilium-data + - /etc/timezone:/etc/timezone:ro + - /etc/localtime:/etc/localtime:ro diff --git a/blueprints/trilium-next/template.toml b/blueprints/trilium-next/template.toml new file mode 100755 index 00000000..0292bb68 --- /dev/null +++ b/blueprints/trilium-next/template.toml @@ -0,0 +1,13 @@ +[variables] +main_domain = "${domain}" + +[config] +env = [ +"TRILIUM_DATA_DIR=/root" +] +mount = [] + +[[config.domains]] +serviceName = "trilium_next" +port = 8080 +host = "${main_domain}" diff --git a/blueprints/trilium-next/trilium-next-logo.svg b/blueprints/trilium-next/trilium-next-logo.svg new file mode 100644 index 00000000..79f47a82 --- /dev/null +++ b/blueprints/trilium-next/trilium-next-logo.svg @@ -0,0 +1,2 @@ + +Trilium Notes \ No newline at end of file diff --git a/blueprints/trmnl-byos-laravel/docker-compose.yml b/blueprints/trmnl-byos-laravel/docker-compose.yml index f571719d..61674d23 100644 --- a/blueprints/trmnl-byos-laravel/docker-compose.yml +++ b/blueprints/trmnl-byos-laravel/docker-compose.yml @@ -1,6 +1,6 @@ services: trmnl-byos-laravel: - image: ghcr.io/usetrmnl/byos_laravel:0.21.0 + image: ghcr.io/usetrmnl/byos_laravel:0.27.0 environment: - APP_URL=${APP_URL} - PHP_OPCACHE_ENABLE=${PHP_OPCACHE_ENABLE} diff --git a/blueprints/uptime-kuma/docker-compose.yml b/blueprints/uptime-kuma/docker-compose.yml index ca80a8a3..f50c2013 100644 --- a/blueprints/uptime-kuma/docker-compose.yml +++ b/blueprints/uptime-kuma/docker-compose.yml @@ -1,7 +1,7 @@ version: "3.8" services: uptime-kuma: - image: louislam/uptime-kuma:1.23.15 + image: louislam/uptime-kuma:2.1.0 restart: always volumes: - uptime-kuma-data:/app/data diff --git a/blueprints/vikunja/docker-compose.yml b/blueprints/vikunja/docker-compose.yml index 11b744b0..0d1c7fbe 100644 --- a/blueprints/vikunja/docker-compose.yml +++ b/blueprints/vikunja/docker-compose.yml @@ -1,17 +1,17 @@ -version: "3.8" - services: vikunja: image: vikunja/vikunja + user: "0:0" environment: - VIKUNJA_SERVICE_PUBLICURL: http://vikunja.local - VIKUNJA_DATABASE_HOST: db + VIKUNJA_SERVICE_PUBLICURL: ${VIKUNJA_SERVICE_PUBLICURL} + VIKUNJA_PUBLIC_PORT: ${VIKUNJA_PUBLIC_PORT} + VIKUNJA_DATABASE_HOST: ${VIKUNJA_DATABASE_HOST} VIKUNJA_DATABASE_PASSWORD: ${VIKUNJA_DATABASE_PASSWORD} - VIKUNJA_DATABASE_TYPE: postgres - VIKUNJA_DATABASE_USER: vikunja - VIKUNJA_DATABASE_DATABASE: vikunja + VIKUNJA_DATABASE_TYPE: ${VIKUNJA_DATABASE_TYPE} + VIKUNJA_DATABASE_USER: ${VIKUNJA_DATABASE_USER} + VIKUNJA_DATABASE_DATABASE: ${VIKUNJA_DATABASE_DATABASE} VIKUNJA_SERVICE_JWTSECRET: ${VIKUNJA_SERVICE_JWTSECRET} - expose: + ports: - 3456 volumes: - vikunja-files:/app/vikunja/files @@ -24,15 +24,16 @@ services: image: postgres:17 environment: POSTGRES_PASSWORD: ${VIKUNJA_DATABASE_PASSWORD} - POSTGRES_USER: vikunja - POSTGRES_DB: vikunja + POSTGRES_USER: ${VIKUNJA_DATABASE_USER} + POSTGRES_DB: ${VIKUNJA_DATABASE_DATABASE} volumes: - vikunja-db:/var/lib/postgresql/data restart: unless-stopped healthcheck: - test: ["CMD-SHELL", "pg_isready -h localhost -U $$POSTGRES_USER"] - interval: 2s - start_period: 30s + test: ["CMD-SHELL", "pg_isready", "-U", "${VIKUNJA_DATABASE_USER}", "-d", "${VIKUNJA_DATABASE_DATABASE}"] + interval: 10s + timeout: 5s + retries: 3 volumes: vikunja-files: {} diff --git a/blueprints/vikunja/template.toml b/blueprints/vikunja/template.toml index 0a4e88f9..1740d3e6 100644 --- a/blueprints/vikunja/template.toml +++ b/blueprints/vikunja/template.toml @@ -18,10 +18,6 @@ VIKUNJA_DATABASE_USER = "vikunja" VIKUNJA_DATABASE_DATABASE = "vikunja" VIKUNJA_SERVICE_JWTSECRET = "${jwt_secret}" -POSTGRES_PASSWORD = "${db_password}" -POSTGRES_USER = "vikunja" -POSTGRES_DB = "vikunja" - [[config.mounts]] serviceName = "vikunja" volumeName = "vikunja-files" diff --git a/blueprints/wg-easy/docker-compose.yml b/blueprints/wg-easy/docker-compose.yml index 1161bb12..0a98f6d9 100644 --- a/blueprints/wg-easy/docker-compose.yml +++ b/blueprints/wg-easy/docker-compose.yml @@ -3,24 +3,23 @@ volumes: services: wg-easy: - image: ghcr.io/wg-easy/wg-easy:15 - restart: unless-stopped environment: - - WG_HOST=${WIREGUARD_HOST} - - PASSWORD=${WIREGUARD_PASSWORD} - - WG_PORT=51820 + - INIT_ENABLED=1 + - INIT_HOST=${WIREGUARD_HOST} + - INIT_PORT=51820 + - INIT_USERNAME=admin + - INIT_PASSWORD=${WIREGUARD_PASSWORD} + - INIT_DNS=1.1.1.1,8.8.8.8 - PORT=51821 - - WG_MTU=1280 - - WG_DEFAULT_DNS=1.1.1.1,8.8.8.8 - - WG_ALLOWED_IPS=0.0.0.0/0 - - WG_POST_UP=iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE; iptables -A FORWARD -i wg0 -j ACCEPT; iptables -A FORWARD -o wg0 -j ACCEPT; - - WG_POST_DOWN=iptables -t nat -D POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE; iptables -D FORWARD -i wg0 -j ACCEPT; iptables -D FORWARD -o wg0 -j ACCEPT; + image: ghcr.io/wg-easy/wg-easy:15 + container_name: wg-easy volumes: - etc_wireguard:/etc/wireguard - /lib/modules:/lib/modules:ro ports: - "51820:51820/udp" - "51821:51821/tcp" + restart: unless-stopped cap_add: - NET_ADMIN - SYS_MODULE diff --git a/blueprints/wuzapi/docker-compose.yml b/blueprints/wuzapi/docker-compose.yml new file mode 100644 index 00000000..87b5b8b8 --- /dev/null +++ b/blueprints/wuzapi/docker-compose.yml @@ -0,0 +1,36 @@ +version: "3.8" +services: + wuzapi-server: + image: asternic/wuzapi:sha-30c1805 + restart: unless-stopped + expose: + - 8080 + environment: + - WUZAPI_ADMIN_TOKEN=${WUZAPI_ADMIN_TOKEN} + - WUZAPI_GLOBAL_ENCRYPTION_KEY=${WUZAPI_GLOBAL_ENCRYPTION_KEY} + - DB_USER=${DB_USER:-wuzapi} + - DB_PASSWORD=${DB_PASSWORD:-wuzapi} + - DB_NAME=${DB_NAME:-wuzapi} + - DB_HOST=db + - DB_PORT=5432 + - TZ=${TZ:-UTC} + depends_on: + - db + + db: + image: postgres:16-alpine + restart: always + environment: + POSTGRES_USER: ${DB_USER:-wuzapi} + POSTGRES_PASSWORD: ${DB_PASSWORD:-wuzapi} + POSTGRES_DB: ${DB_NAME:-wuzapi} + volumes: + - db_data:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U $${DB_USER:-wuzapi}"] + interval: 5s + timeout: 5s + retries: 5 + +volumes: + db_data: diff --git a/blueprints/wuzapi/template.toml b/blueprints/wuzapi/template.toml new file mode 100644 index 00000000..71d95c49 --- /dev/null +++ b/blueprints/wuzapi/template.toml @@ -0,0 +1,20 @@ +[variables] +main_domain = "${domain}" +admin_token = "${password:32}" +encryption_key = "${password:32}" +db_user = "wuzapi" +db_password = "${password:32}" +db_name = "wuzapi" + +[config] +[[config.domains]] +serviceName = "wuzapi-server" +port = 8080 +host = "${main_domain}" + +[config.env] +WUZAPI_ADMIN_TOKEN = "${admin_token}" +WUZAPI_GLOBAL_ENCRYPTION_KEY = "${encryption_key}" +DB_USER = "${db_user}" +DB_PASSWORD = "${db_password}" +DB_NAME = "${db_name}" diff --git a/blueprints/wuzapi/wuzapi.png b/blueprints/wuzapi/wuzapi.png new file mode 100644 index 00000000..f48f5d33 Binary files /dev/null and b/blueprints/wuzapi/wuzapi.png differ diff --git a/meta.json b/meta.json index f7dca105..42cdf342 100644 --- a/meta.json +++ b/meta.json @@ -164,13 +164,13 @@ { "id": "alist", "name": "AList", - "version": "v3.41.0", + "version": "v3.55.0", "description": "🗂️A file list/WebDAV program that supports multiple storages, powered by Gin and Solidjs.", "logo": "alist.svg", "links": { "github": "https://github.com/AlistGo/alist", - "website": "https://alist.nn.ci", - "docs": "https://alist.nn.ci/guide/install/docker.html" + "website": "https://alistgo.com/", + "docs": "https://alistgo.com/guide/install/docker.html" }, "tags": [ "file", @@ -350,7 +350,7 @@ { "id": "appsmith", "name": "Appsmith", - "version": "v1.29", + "version": "v1.94", "description": "Appsmith is a free and open source platform for building internal tools and applications.", "logo": "appsmith.png", "links": { @@ -896,7 +896,7 @@ { "id": "budibase", "name": "Budibase", - "version": "3.5.3", + "version": "3.23.47", "description": "Budibase is an open-source low-code platform that saves engineers 100s of hours building forms, portals, and approval apps, securely.", "logo": "budibase.svg", "links": { @@ -3204,6 +3204,24 @@ "finance" ] }, + { + "id": "ipfs", + "name": "IPFS (Kubo)", + "version": "latest", + "description": "IPFS (Kubo) is a decentralized peer-to-peer file sharing and storage network node. Host your own IPFS gateway and API.", + "logo": "ipfs.svg", + "links": { + "github": "https://github.com/ipfs/kubo", + "website": "https://ipfs.tech/", + "docs": "https://docs.ipfs.tech/" + }, + "tags": [ + "storage", + "decentralized", + "p2p", + "self-hosted" + ] + }, { "id": "it-tools", "name": "IT Tools", @@ -4367,8 +4385,8 @@ "description": "Obsidian LiveSync with CouchDB for real-time note synchronization.", "logo": "obsidian.png", "links": { - "github": "https://github.com/apache/couchdb", - "website": "https://couchdb.apache.org/", + "github": "https://github.com/vrtmrz/obsidian-livesync", + "website": "https://obsidian.md/sync", "docs": "https://docs.couchdb.apache.org/" }, "tags": [ @@ -5127,6 +5145,25 @@ "webmail" ] }, + { + "id": "postgres-pgdog", + "name": "PostgreSQL with PgDog", + "version": "0.1.26", + "description": "PostgreSQL database with PgDog connection pooler, load balancer, and horizontal scaling proxy. A modern alternative to PgBouncer with multi-threading support.", + "logo": "postgres-pgdog.png", + "links": { + "github": "https://github.com/pgdogdev/pgdog", + "website": "https://pgdog.dev", + "docs": "https://docs.pgdog.dev" + }, + "tags": [ + "database", + "postgresql", + "pooler", + "proxy", + "load-balancer" + ] + }, { "id": "postgresus", "name": "Postgresus", @@ -5213,6 +5250,24 @@ "management" ] }, + { + "id": "pulse", + "name": "Pulse", + "version": "latest", + "description": "A responsive monitoring platform for Proxmox VE, PBS, and Docker with real-time metrics across nodes and containers.", + "logo": "pulse.svg", + "links": { + "github": "https://github.com/rcourtman/Pulse", + "website": "https://pulserelay.pro/", + "docs": "https://github.com/rcourtman/Pulse/blob/main/docs/README.md" + }, + "tags": [ + "monitoring", + "proxmox", + "docker", + "metrics" + ] + }, { "id": "pyrodactyl", "name": "Pyrodactyl", @@ -5593,6 +5648,25 @@ "aggregator" ] }, + { + "id": "seaweedfs", + "name": "SeaweedFS", + "version": "latest", + "description": "SeaweedFS is a fast distributed storage system for blobs, objects, and files. Features S3-compatible API, POSIX FUSE mount, and WebDAV support.", + "logo": "seaweedfs.svg", + "links": { + "github": "https://github.com/seaweedfs/seaweedfs", + "website": "https://seaweedfs.com/", + "docs": "https://github.com/seaweedfs/seaweedfs/wiki" + }, + "tags": [ + "storage", + "s3", + "distributed", + "object-storage", + "file-system" + ] + }, { "id": "shlink", "name": "Shlink", @@ -5824,6 +5898,24 @@ "media" ] }, + { + "id": "strapi", + "name": "Strapi", + "version": "v5.33.0", + "description": "Open-source headless CMS to build powerful APIs with built-in content management.", + "logo": "strapi.svg", + "links": { + "github": "https://github.com/strapi/strapi", + "discord": "https://discord.com/invite/strapi", + "docs": "https://docs.strapi.io", + "website": "https://strapi.io" + }, + "tags": [ + "headless", + "cms", + "content-management" + ] + }, { "id": "supabase", "name": "SupaBase", @@ -5845,7 +5937,7 @@ { "id": "superset", "name": "Superset (Unofficial)", - "version": "latest", + "version": "6.0.0", "description": "Data visualization and data exploration platform.", "logo": "superset.svg", "links": { @@ -6049,10 +6141,27 @@ "personal-use" ] }, + { + "id": "trilium-next", + "name": "TriliumNext", + "version": "latest", + "description": "Is a free and open-source, cross-platform hierarchical note taking application with focus on building large personal knowledge bases.", + "logo": "trilium-next-logo.svg", + "links": { + "github": "https://github.com/TriliumNext/Trilium", + "website": "https://triliumnotes.org/", + "docs": "https://docs.triliumnotes.org/" + }, + "tags": [ + "self-hosted", + "productivity", + "personal-use" + ] + }, { "id": "trmnl-byos-laravel", "name": "TRMNL BYOS Laravel", - "version": "0.21.0", + "version": "0.27.0", "description": "TRMNL BYOS Laravel is a self-hosted application to manage TRMNL e-ink devices.", "logo": "byos-laravel.svg", "links": { @@ -6182,7 +6291,7 @@ { "id": "uptime-kuma", "name": "Uptime Kuma", - "version": "1.23.15", + "version": "2.1.0", "description": "Uptime Kuma is a free and open source monitoring tool that allows you to monitor your websites and applications.", "logo": "uptime-kuma.png", "links": { @@ -6270,7 +6379,7 @@ "description": "Vikunja is a self-hosted, open-source to-do list application to organize tasks, projects, and notes.", "logo": "image.png", "links": { - "github": "https://kolaente.dev/vikunja/", + "github": "https://github.com/go-vikunja/vikunja", "website": "https://vikunja.io/", "docs": "https://vikunja.io/docs/" }, @@ -6419,6 +6528,24 @@ "cms" ] }, + { + "id": "wuzapi", + "name": "WuzAPI", + "version": "v1.0.0", + "description": "A RESTful API service for WhatsApp with multiple device support and concurrent sessions.", + "logo": "wuzapi.png", + "links": { + "github": "https://github.com/asternic/wuzapi", + "website": "https://www.wuzapi.app/", + "docs": "https://github.com/asternic/wuzapi/blob/main/README.md" + }, + "tags": [ + "api", + "whatsapp", + "messaging", + "automation" + ] + }, { "id": "xsshunter", "name": "XSSHunter",