From 843d94ae713f5e1ba6d75ec2d99876fbe8d09fa3 Mon Sep 17 00:00:00 2001 From: arasors Date: Mon, 13 Jul 2026 15:39:13 +0800 Subject: [PATCH 1/2] feat: add Sentroy platform and mail server templates Sentroy is a self-hostable workspace suite (mail, storage, auth/OIDC, status, WhatsApp, issue tracker, audio studio, downloader, MongoDB backup) on MongoDB, plus a standalone mail server (Postfix/Dovecot/Rspamd + REST API). Both use public prebuilt ghcr.io/sentroy-co/sentroy-oss-* images and derive every URL from one root_domain variable. --- .../sentroy-mailserver/docker-compose.yml | 92 ++++++++++ blueprints/sentroy-mailserver/logo.svg | 29 ++++ blueprints/sentroy-mailserver/meta.json | 17 ++ blueprints/sentroy-mailserver/template.toml | 53 ++++++ blueprints/sentroy/docker-compose.yml | 161 ++++++++++++++++++ blueprints/sentroy/logo.svg | 29 ++++ blueprints/sentroy/meta.json | 17 ++ blueprints/sentroy/template.toml | 99 +++++++++++ 8 files changed, 497 insertions(+) create mode 100644 blueprints/sentroy-mailserver/docker-compose.yml create mode 100644 blueprints/sentroy-mailserver/logo.svg create mode 100644 blueprints/sentroy-mailserver/meta.json create mode 100644 blueprints/sentroy-mailserver/template.toml create mode 100644 blueprints/sentroy/docker-compose.yml create mode 100644 blueprints/sentroy/logo.svg create mode 100644 blueprints/sentroy/meta.json create mode 100644 blueprints/sentroy/template.toml diff --git a/blueprints/sentroy-mailserver/docker-compose.yml b/blueprints/sentroy-mailserver/docker-compose.yml new file mode 100644 index 000000000..af87486b4 --- /dev/null +++ b/blueprints/sentroy-mailserver/docker-compose.yml @@ -0,0 +1,92 @@ +services: + postgres: + image: postgres:16-alpine + restart: unless-stopped + env_file: + - .env + volumes: + - mail-pg:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U sentroy -d maildb"] + interval: 5s + timeout: 3s + retries: 10 + start_period: 30s + + redis: + image: redis:7-alpine + restart: unless-stopped + command: redis-server --appendonly yes --maxmemory 128mb --maxmemory-policy noeviction + volumes: + - mail-redis:/data + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 10s + timeout: 5s + retries: 5 + + rspamd: + image: ghcr.io/sentroy-co/sentroy-oss-mailserver-rspamd:latest + restart: unless-stopped + volumes: + - mail-dkim:/etc/rspamd/dkim + depends_on: + redis: + condition: service_healthy + + postfix: + image: ghcr.io/sentroy-co/sentroy-oss-mailserver-postfix:latest + restart: unless-stopped + env_file: + - .env + ports: + - "25:25" + - "587:587" + - "465:465" + volumes: + - mail-data:/var/mail + - mail-dkim:/etc/rspamd/dkim:ro + - mail-virtual:/etc/postfix/virtual + depends_on: + - rspamd + + dovecot: + image: ghcr.io/sentroy-co/sentroy-oss-mailserver-dovecot:latest + restart: unless-stopped + ports: + - "143:143" + - "993:993" + volumes: + - mail-data:/var/mail + - mail-users:/etc/dovecot/users-data + depends_on: + - postfix + + api: + image: ghcr.io/sentroy-co/sentroy-oss-mailserver-api:latest + restart: unless-stopped + env_file: + - .env + volumes: + - mail-dkim:/etc/rspamd/dkim + - mail-virtual:/etc/postfix/virtual + - mail-users:/etc/dovecot/users-data + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_healthy + +volumes: + mail-pg: + driver: local + mail-redis: + driver: local + mail-data: + driver: local + mail-dkim: + driver: local + mail-virtual: + driver: local + mail-users: + driver: local diff --git a/blueprints/sentroy-mailserver/logo.svg b/blueprints/sentroy-mailserver/logo.svg new file mode 100644 index 000000000..bf6c5e901 --- /dev/null +++ b/blueprints/sentroy-mailserver/logo.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/blueprints/sentroy-mailserver/meta.json b/blueprints/sentroy-mailserver/meta.json new file mode 100644 index 000000000..29cd49626 --- /dev/null +++ b/blueprints/sentroy-mailserver/meta.json @@ -0,0 +1,17 @@ +{ + "id": "sentroy-mailserver", + "name": "Sentroy Mail Server", + "version": "1.64.226", + "description": "Self-hosted transactional and inbox mail server (Postfix, Dovecot, Rspamd, Postgres, Redis) with a Fastify REST API. A self-hostable Resend/Postal alternative driven over HTTP.", + "logo": "logo.svg", + "links": { + "github": "https://github.com/Sentroy-Co/sentroy", + "website": "https://sentroy.com", + "docs": "https://sentroy.com/docs/mail" + }, + "tags": [ + "email", + "smtp", + "imap" + ] +} diff --git a/blueprints/sentroy-mailserver/template.toml b/blueprints/sentroy-mailserver/template.toml new file mode 100644 index 000000000..f5140d62c --- /dev/null +++ b/blueprints/sentroy-mailserver/template.toml @@ -0,0 +1,53 @@ +[variables] +# Edit these to your mail domain, then set DNS: A mail. -> server IP, +# MX -> mail., SPF/DMARC TXT, and PTR/rDNS at your provider. +mail_domain = "example.com" +mail_hostname = "mail.example.com" +server_ip = "203.0.113.10" +postgres_password = "${password:32}" +jwt_secret = "${base64:48}" +smtp_pass = "${password:32}" +imap_pass = "${password:32}" +imap_master_pass = "${password:32}" +admin_token = "${base64:48}" + +[config] + +[[config.domains]] +serviceName = "api" +port = 3000 +host = "api.${mail_domain}" + +[config.env] +# Zero-touch admin token: ADMIN_API_KEY is provisioned into the DB idempotently +# on first boot (no setup script). Read it from this template's variables. +ADMIN_API_KEY = "${admin_token}" +POSTGRES_DB = "maildb" +POSTGRES_USER = "sentroy" +POSTGRES_PASSWORD = "${postgres_password}" +DATABASE_URL = "postgresql://sentroy:${postgres_password}@postgres:5432/maildb" +REDIS_URL = "redis://redis:6379" +API_PORT = "3000" +NODE_ENV = "production" +LOG_LEVEL = "info" +JWT_SECRET = "${jwt_secret}" +API_ALLOWED_ORIGINS = "*" +API_BASE_URL = "https://api.${mail_domain}/api/v1" +SERVER_IP = "${server_ip}" +MAIL_HOSTNAME = "${mail_hostname}" +MAIL_DOMAIN = "${mail_domain}" +SMTP_HOST = "postfix" +SMTP_PORT = "25" +SMTP_USER = "api@${mail_hostname}" +SMTP_PASS = "${smtp_pass}" +IMAP_HOST = "dovecot" +IMAP_PORT = "143" +IMAP_USER = "inbox@${mail_hostname}" +IMAP_PASS = "${imap_pass}" +IMAP_MASTER_USER = "sentroy" +IMAP_MASTER_PASS = "${imap_master_pass}" +DKIM_KEYS_PATH = "/etc/rspamd/dkim" +QUEUE_CONCURRENCY = "5" +DOMAIN_VERIFY_INTERVAL = "300000" +IMAP_POOL_SIZE = "5" +DOVECOT_USERS_FILE = "/etc/dovecot/users-data/users" diff --git a/blueprints/sentroy/docker-compose.yml b/blueprints/sentroy/docker-compose.yml new file mode 100644 index 000000000..46d08dc6e --- /dev/null +++ b/blueprints/sentroy/docker-compose.yml @@ -0,0 +1,161 @@ +services: + mongo: + image: mongo:7 + restart: unless-stopped + env_file: + - .env + volumes: + - sentroy-mongo:/data/db + healthcheck: + test: ["CMD", "mongosh", "--quiet", "--eval", "db.adminCommand('ping').ok"] + interval: 10s + timeout: 5s + retries: 10 + start_period: 30s + + core: + image: ghcr.io/sentroy-co/sentroy-oss-core:latest + restart: unless-stopped + env_file: + - .env + environment: + - PORT=3000 + - CDN_API_URL=http://cdn:4100 + depends_on: + mongo: + condition: service_healthy + + storage: + image: ghcr.io/sentroy-co/sentroy-oss-storage:latest + restart: unless-stopped + env_file: + - .env + environment: + - PORT=3002 + - CDN_API_URL=http://cdn:4100 + depends_on: + mongo: + condition: service_healthy + + cdn: + image: ghcr.io/sentroy-co/sentroy-oss-cdn:latest + restart: unless-stopped + env_file: + - .env + environment: + - PORT=4100 + + auth2: + image: ghcr.io/sentroy-co/sentroy-oss-auth2:latest + restart: unless-stopped + env_file: + - .env + environment: + - PORT=3003 + depends_on: + mongo: + condition: service_healthy + + status: + image: ghcr.io/sentroy-co/sentroy-oss-status:latest + restart: unless-stopped + env_file: + - .env + environment: + - PORT=3004 + depends_on: + mongo: + condition: service_healthy + + studio: + image: ghcr.io/sentroy-co/sentroy-oss-studio:latest + restart: unless-stopped + env_file: + - .env + environment: + - PORT=3006 + depends_on: + mongo: + condition: service_healthy + + whatsapp: + image: ghcr.io/sentroy-co/sentroy-oss-whatsapp:latest + restart: unless-stopped + env_file: + - .env + environment: + - PORT=3007 + - WHATSAPP_GATEWAY_URL=http://whatsapp-gateway:4200 + depends_on: + mongo: + condition: service_healthy + + whatsapp-gateway: + image: ghcr.io/sentroy-co/sentroy-oss-whatsapp-gateway:latest + restart: unless-stopped + env_file: + - .env + environment: + - PORT=4200 + depends_on: + mongo: + condition: service_healthy + + linear: + image: ghcr.io/sentroy-co/sentroy-oss-linear:latest + restart: unless-stopped + env_file: + - .env + environment: + - PORT=3009 + depends_on: + mongo: + condition: service_healthy + + downloader: + image: ghcr.io/sentroy-co/sentroy-oss-downloader:latest + restart: unless-stopped + env_file: + - .env + environment: + - PORT=3008 + - DOWNLOADER_WORKER_URL=http://downloader-worker:4300 + + downloader-worker: + image: ghcr.io/sentroy-co/sentroy-oss-downloader-worker:latest + restart: unless-stopped + env_file: + - .env + environment: + - PORT=4300 + volumes: + - sentroy-downloads:/downloads + + backup: + image: ghcr.io/sentroy-co/sentroy-oss-backup:latest + restart: unless-stopped + env_file: + - .env + environment: + - PORT=3010 + - BACKUP_WORKER_URL=http://backup-worker:4400 + depends_on: + mongo: + condition: service_healthy + + backup-worker: + image: ghcr.io/sentroy-co/sentroy-oss-backup-worker:latest + restart: unless-stopped + env_file: + - .env + environment: + - PORT=4400 + depends_on: + mongo: + condition: service_healthy + +volumes: + sentroy-mongo: + driver: local + sentroy-downloads: + driver: local diff --git a/blueprints/sentroy/logo.svg b/blueprints/sentroy/logo.svg new file mode 100644 index 000000000..bf6c5e901 --- /dev/null +++ b/blueprints/sentroy/logo.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/blueprints/sentroy/meta.json b/blueprints/sentroy/meta.json new file mode 100644 index 000000000..cd0cece87 --- /dev/null +++ b/blueprints/sentroy/meta.json @@ -0,0 +1,17 @@ +{ + "id": "sentroy", + "name": "Sentroy", + "version": "1.64.226", + "description": "Self-hostable workspace suite — mail, storage, auth/OIDC, status, WhatsApp, issue tracker, audio studio, downloader and MongoDB backup — on MongoDB.", + "logo": "logo.svg", + "links": { + "github": "https://github.com/Sentroy-Co/sentroy", + "website": "https://sentroy.com", + "docs": "https://sentroy.com/docs" + }, + "tags": [ + "workspace", + "productivity", + "platform" + ] +} diff --git a/blueprints/sentroy/template.toml b/blueprints/sentroy/template.toml new file mode 100644 index 000000000..042572fe2 --- /dev/null +++ b/blueprints/sentroy/template.toml @@ -0,0 +1,99 @@ +[variables] +# Edit root_domain to your domain, then point wildcard DNS (*. + ) +# at this server. Every app is served at a fixed subdomain of it. +root_domain = "sentroy.example.com" +mongo_password = "${password:32}" +auth_secret = "${base64:64}" +internal_secret = "${password:48}" +env_master = "${base64:64}" +cdn_secret = "${password:32}" +whatsapp_key = "${base64:32}" +downloader_secret = "${password:32}" +backup_secret = "${password:32}" +admin_api_key = "${base64:48}" +admin_password = "${password:24}" + +[config] + +[[config.domains]] +serviceName = "core" +port = 3000 +host = "${root_domain}" + +[[config.domains]] +serviceName = "storage" +port = 3002 +host = "storage.${root_domain}" + +[[config.domains]] +serviceName = "cdn" +port = 4100 +host = "cdn.${root_domain}" + +[[config.domains]] +serviceName = "auth2" +port = 3003 +host = "auth.${root_domain}" + +[[config.domains]] +serviceName = "status" +port = 3004 +host = "status.${root_domain}" + +[[config.domains]] +serviceName = "studio" +port = 3006 +host = "studio.${root_domain}" + +[[config.domains]] +serviceName = "whatsapp" +port = 3007 +host = "whatsapp.${root_domain}" + +[[config.domains]] +serviceName = "linear" +port = 3009 +host = "linear.${root_domain}" + +[[config.domains]] +serviceName = "downloader" +port = 3008 +host = "youtube.${root_domain}" + +[[config.domains]] +serviceName = "backup" +port = 3010 +host = "backup.${root_domain}" + +[config.env] +# One knob — server code + the client-bundle sentinel are both resolved from +# SENTROY_ROOT_DOMAIN at container start, so a single prebuilt image serves any +# domain. Other app URLs are derived from it; no per-app URL needed. +SENTROY_ROOT_DOMAIN = "${root_domain}" +DOMAIN = "${root_domain}" +NODE_ENV = "production" +MONGO_INITDB_ROOT_USERNAME = "sentroy" +MONGO_INITDB_ROOT_PASSWORD = "${mongo_password}" +MONGODB_URI = "mongodb://sentroy:${mongo_password}@mongo:27017/sentroy?authSource=admin" +MONGODB_DATABASE = "sentroy" +BETTER_AUTH_SECRET = "${auth_secret}" +BETTER_AUTH_URL = "https://${root_domain}" +AUTH_COOKIE_DOMAIN = ".${root_domain}" +AUTH_TRUSTED_ORIGINS = "https://${root_domain}" +INTERNAL_API_SECRET = "${internal_secret}" +SENTROY_ENV_MASTER_KEY = "${env_master}" +CDN_API_SECRET = "${cdn_secret}" +SENTROY_ADMIN_API_KEY = "${admin_api_key}" +ADMIN_EMAIL = "admin@${root_domain}" +ADMIN_PASSWORD = "${admin_password}" +WHATSAPP_ENC_KEY = "${whatsapp_key}" +DOWNLOADER_API_SECRET = "${downloader_secret}" +BACKUP_API_SECRET = "${backup_secret}" +TURNSTILE_DISABLED = "true" +NEXT_PUBLIC_TURNSTILE_DISABLED = "true" +# Object storage (S3-compatible) — REQUIRED for Storage + Backup. Fill these in. +IDRIVE_ENDPOINT = "" +IDRIVE_REGION = "" +IDRIVE_BUCKET = "" +IDRIVE_ACCESS_KEY = "" +IDRIVE_SECRET_KEY = "" From 64dc238d6c7ef187cf2e8900b8a906eb7cc5f599 Mon Sep 17 00:00:00 2001 From: arasors Date: Mon, 13 Jul 2026 15:46:52 +0800 Subject: [PATCH 2/2] fix: drop mail server template (Dokploy CI disallows fixed TCP port mapping) The mail server needs SMTP/IMAP on fixed host ports (25/587/465/143/993), which the blueprint CI rejects (only proxy-routed HTTP ports allowed). Keep the HTTP-only Sentroy platform template, which passes cleanly. --- .../sentroy-mailserver/docker-compose.yml | 92 ------------------- blueprints/sentroy-mailserver/logo.svg | 29 ------ blueprints/sentroy-mailserver/meta.json | 17 ---- blueprints/sentroy-mailserver/template.toml | 53 ----------- 4 files changed, 191 deletions(-) delete mode 100644 blueprints/sentroy-mailserver/docker-compose.yml delete mode 100644 blueprints/sentroy-mailserver/logo.svg delete mode 100644 blueprints/sentroy-mailserver/meta.json delete mode 100644 blueprints/sentroy-mailserver/template.toml diff --git a/blueprints/sentroy-mailserver/docker-compose.yml b/blueprints/sentroy-mailserver/docker-compose.yml deleted file mode 100644 index af87486b4..000000000 --- a/blueprints/sentroy-mailserver/docker-compose.yml +++ /dev/null @@ -1,92 +0,0 @@ -services: - postgres: - image: postgres:16-alpine - restart: unless-stopped - env_file: - - .env - volumes: - - mail-pg:/var/lib/postgresql/data - healthcheck: - test: ["CMD-SHELL", "pg_isready -U sentroy -d maildb"] - interval: 5s - timeout: 3s - retries: 10 - start_period: 30s - - redis: - image: redis:7-alpine - restart: unless-stopped - command: redis-server --appendonly yes --maxmemory 128mb --maxmemory-policy noeviction - volumes: - - mail-redis:/data - healthcheck: - test: ["CMD", "redis-cli", "ping"] - interval: 10s - timeout: 5s - retries: 5 - - rspamd: - image: ghcr.io/sentroy-co/sentroy-oss-mailserver-rspamd:latest - restart: unless-stopped - volumes: - - mail-dkim:/etc/rspamd/dkim - depends_on: - redis: - condition: service_healthy - - postfix: - image: ghcr.io/sentroy-co/sentroy-oss-mailserver-postfix:latest - restart: unless-stopped - env_file: - - .env - ports: - - "25:25" - - "587:587" - - "465:465" - volumes: - - mail-data:/var/mail - - mail-dkim:/etc/rspamd/dkim:ro - - mail-virtual:/etc/postfix/virtual - depends_on: - - rspamd - - dovecot: - image: ghcr.io/sentroy-co/sentroy-oss-mailserver-dovecot:latest - restart: unless-stopped - ports: - - "143:143" - - "993:993" - volumes: - - mail-data:/var/mail - - mail-users:/etc/dovecot/users-data - depends_on: - - postfix - - api: - image: ghcr.io/sentroy-co/sentroy-oss-mailserver-api:latest - restart: unless-stopped - env_file: - - .env - volumes: - - mail-dkim:/etc/rspamd/dkim - - mail-virtual:/etc/postfix/virtual - - mail-users:/etc/dovecot/users-data - depends_on: - postgres: - condition: service_healthy - redis: - condition: service_healthy - -volumes: - mail-pg: - driver: local - mail-redis: - driver: local - mail-data: - driver: local - mail-dkim: - driver: local - mail-virtual: - driver: local - mail-users: - driver: local diff --git a/blueprints/sentroy-mailserver/logo.svg b/blueprints/sentroy-mailserver/logo.svg deleted file mode 100644 index bf6c5e901..000000000 --- a/blueprints/sentroy-mailserver/logo.svg +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/blueprints/sentroy-mailserver/meta.json b/blueprints/sentroy-mailserver/meta.json deleted file mode 100644 index 29cd49626..000000000 --- a/blueprints/sentroy-mailserver/meta.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "id": "sentroy-mailserver", - "name": "Sentroy Mail Server", - "version": "1.64.226", - "description": "Self-hosted transactional and inbox mail server (Postfix, Dovecot, Rspamd, Postgres, Redis) with a Fastify REST API. A self-hostable Resend/Postal alternative driven over HTTP.", - "logo": "logo.svg", - "links": { - "github": "https://github.com/Sentroy-Co/sentroy", - "website": "https://sentroy.com", - "docs": "https://sentroy.com/docs/mail" - }, - "tags": [ - "email", - "smtp", - "imap" - ] -} diff --git a/blueprints/sentroy-mailserver/template.toml b/blueprints/sentroy-mailserver/template.toml deleted file mode 100644 index f5140d62c..000000000 --- a/blueprints/sentroy-mailserver/template.toml +++ /dev/null @@ -1,53 +0,0 @@ -[variables] -# Edit these to your mail domain, then set DNS: A mail. -> server IP, -# MX -> mail., SPF/DMARC TXT, and PTR/rDNS at your provider. -mail_domain = "example.com" -mail_hostname = "mail.example.com" -server_ip = "203.0.113.10" -postgres_password = "${password:32}" -jwt_secret = "${base64:48}" -smtp_pass = "${password:32}" -imap_pass = "${password:32}" -imap_master_pass = "${password:32}" -admin_token = "${base64:48}" - -[config] - -[[config.domains]] -serviceName = "api" -port = 3000 -host = "api.${mail_domain}" - -[config.env] -# Zero-touch admin token: ADMIN_API_KEY is provisioned into the DB idempotently -# on first boot (no setup script). Read it from this template's variables. -ADMIN_API_KEY = "${admin_token}" -POSTGRES_DB = "maildb" -POSTGRES_USER = "sentroy" -POSTGRES_PASSWORD = "${postgres_password}" -DATABASE_URL = "postgresql://sentroy:${postgres_password}@postgres:5432/maildb" -REDIS_URL = "redis://redis:6379" -API_PORT = "3000" -NODE_ENV = "production" -LOG_LEVEL = "info" -JWT_SECRET = "${jwt_secret}" -API_ALLOWED_ORIGINS = "*" -API_BASE_URL = "https://api.${mail_domain}/api/v1" -SERVER_IP = "${server_ip}" -MAIL_HOSTNAME = "${mail_hostname}" -MAIL_DOMAIN = "${mail_domain}" -SMTP_HOST = "postfix" -SMTP_PORT = "25" -SMTP_USER = "api@${mail_hostname}" -SMTP_PASS = "${smtp_pass}" -IMAP_HOST = "dovecot" -IMAP_PORT = "143" -IMAP_USER = "inbox@${mail_hostname}" -IMAP_PASS = "${imap_pass}" -IMAP_MASTER_USER = "sentroy" -IMAP_MASTER_PASS = "${imap_master_pass}" -DKIM_KEYS_PATH = "/etc/rspamd/dkim" -QUEUE_CONCURRENCY = "5" -DOMAIN_VERIFY_INTERVAL = "300000" -IMAP_POOL_SIZE = "5" -DOVECOT_USERS_FILE = "/etc/dovecot/users-data/users"