diff --git a/apps/dokploy/public/templates/activepieces.svg b/apps/dokploy/public/templates/activepieces.svg
new file mode 100644
index 00000000..dcf0a52b
--- /dev/null
+++ b/apps/dokploy/public/templates/activepieces.svg
@@ -0,0 +1,4 @@
+
+
\ No newline at end of file
diff --git a/apps/dokploy/public/templates/discord-tickets.png b/apps/dokploy/public/templates/discord-tickets.png
new file mode 100644
index 00000000..030c3a4c
Binary files /dev/null and b/apps/dokploy/public/templates/discord-tickets.png differ
diff --git a/apps/dokploy/public/templates/discordtickets.png b/apps/dokploy/public/templates/discordtickets.png
new file mode 100644
index 00000000..030c3a4c
Binary files /dev/null and b/apps/dokploy/public/templates/discordtickets.png differ
diff --git a/apps/dokploy/public/templates/invoiceshelf.png b/apps/dokploy/public/templates/invoiceshelf.png
new file mode 100644
index 00000000..cee025e0
Binary files /dev/null and b/apps/dokploy/public/templates/invoiceshelf.png differ
diff --git a/apps/dokploy/public/templates/peppermint.svg b/apps/dokploy/public/templates/peppermint.svg
new file mode 100644
index 00000000..b6fff994
--- /dev/null
+++ b/apps/dokploy/public/templates/peppermint.svg
@@ -0,0 +1,13 @@
+
diff --git a/apps/dokploy/public/templates/postiz.png b/apps/dokploy/public/templates/postiz.png
new file mode 100644
index 00000000..1d435abc
Binary files /dev/null and b/apps/dokploy/public/templates/postiz.png differ
diff --git a/apps/dokploy/public/templates/slash.png b/apps/dokploy/public/templates/slash.png
new file mode 100644
index 00000000..c843b409
Binary files /dev/null and b/apps/dokploy/public/templates/slash.png differ
diff --git a/apps/dokploy/public/templates/windmill.svg b/apps/dokploy/public/templates/windmill.svg
new file mode 100644
index 00000000..2b06716f
--- /dev/null
+++ b/apps/dokploy/public/templates/windmill.svg
@@ -0,0 +1,29 @@
+
+
diff --git a/apps/dokploy/templates/activepieces/docker-compose.yml b/apps/dokploy/templates/activepieces/docker-compose.yml
new file mode 100644
index 00000000..e990379b
--- /dev/null
+++ b/apps/dokploy/templates/activepieces/docker-compose.yml
@@ -0,0 +1,67 @@
+version: "3.8"
+
+services:
+ activepieces:
+ image: activepieces/activepieces:0.35.0
+ restart: unless-stopped
+ networks:
+ - dokploy-network
+ depends_on:
+ postgres:
+ condition: service_healthy
+ redis:
+ condition: service_healthy
+ environment:
+ AP_ENGINE_EXECUTABLE_PATH: dist/packages/engine/main.js
+ AP_API_KEY: ${AP_API_KEY}
+ AP_ENCRYPTION_KEY: ${AP_ENCRYPTION_KEY}
+ AP_JWT_SECRET: ${AP_JWT_SECRET}
+ AP_ENVIRONMENT: prod
+ AP_FRONTEND_URL: https://${AP_HOST}
+ AP_WEBHOOK_TIMEOUT_SECONDS: 30
+ AP_TRIGGER_DEFAULT_POLL_INTERVAL: 5
+ AP_POSTGRES_DATABASE: activepieces
+ AP_POSTGRES_HOST: postgres
+ AP_POSTGRES_PORT: 5432
+ AP_POSTGRES_USERNAME: activepieces
+ AP_POSTGRES_PASSWORD: ${AP_POSTGRES_PASSWORD}
+ AP_EXECUTION_MODE: UNSANDBOXED
+ AP_REDIS_HOST: redis
+ AP_REDIS_PORT: 6379
+ AP_SANDBOX_RUN_TIME_SECONDS: 600
+ AP_TELEMETRY_ENABLED: "false"
+ AP_TEMPLATES_SOURCE_URL: https://cloud.activepieces.com/api/v1/flow-templates
+
+ postgres:
+ image: postgres:14
+ restart: unless-stopped
+ networks:
+ - dokploy-network
+ environment:
+ POSTGRES_DB: activepieces
+ POSTGRES_PASSWORD: ${AP_POSTGRES_PASSWORD}
+ POSTGRES_USER: activepieces
+ volumes:
+ - postgres_data:/var/lib/postgresql/data
+ healthcheck:
+ test: ["CMD-SHELL", "pg_isready -U activepieces -d activepieces"]
+ interval: 30s
+ timeout: 30s
+ retries: 3
+
+ redis:
+ image: redis:7
+ restart: unless-stopped
+ networks:
+ - dokploy-network
+ volumes:
+ - redis_data:/data
+ healthcheck:
+ test: ["CMD", "redis-cli", "ping"]
+ interval: 30s
+ timeout: 30s
+ retries: 3
+
+volumes:
+ postgres_data:
+ redis_data:
\ No newline at end of file
diff --git a/apps/dokploy/templates/activepieces/index.ts b/apps/dokploy/templates/activepieces/index.ts
new file mode 100644
index 00000000..60f8981f
--- /dev/null
+++ b/apps/dokploy/templates/activepieces/index.ts
@@ -0,0 +1,40 @@
+import {
+ type DomainSchema,
+ type Schema,
+ type Template,
+ generateRandomDomain,
+} from "../utils";
+
+export function generate(schema: Schema): Template {
+ const mainDomain = generateRandomDomain(schema);
+
+ const apiKey = Array.from({length: 32}, () =>
+ Math.floor(Math.random() * 16).toString(16)).join('');
+ const encryptionKey = Array.from({length: 32}, () =>
+ Math.floor(Math.random() * 16).toString(16)).join('');
+ const jwtSecret = Array.from({length: 32}, () =>
+ Math.floor(Math.random() * 16).toString(16)).join('');
+ const postgresPassword = Array.from({length: 32}, () =>
+ Math.floor(Math.random() * 16).toString(16)).join('');
+
+ const domains: DomainSchema[] = [
+ {
+ host: mainDomain,
+ port: 80,
+ serviceName: "activepieces",
+ },
+ ];
+
+ const envs = [
+ `AP_HOST=${mainDomain}`,
+ `AP_API_KEY=${apiKey}`,
+ `AP_ENCRYPTION_KEY=${encryptionKey}`,
+ `AP_JWT_SECRET=${jwtSecret}`,
+ `AP_POSTGRES_PASSWORD=${postgresPassword}`,
+ ];
+
+ return {
+ domains,
+ envs,
+ };
+}
\ No newline at end of file
diff --git a/apps/dokploy/templates/discord-tickets/docker-compose.yml b/apps/dokploy/templates/discord-tickets/docker-compose.yml
new file mode 100644
index 00000000..44324e1e
--- /dev/null
+++ b/apps/dokploy/templates/discord-tickets/docker-compose.yml
@@ -0,0 +1,54 @@
+version: "3.8"
+
+services:
+ mysql:
+ image: mysql:8
+ restart: unless-stopped
+ hostname: mysql
+ networks:
+ - dokploy-network
+ volumes:
+ - tickets-mysql:/var/lib/mysql
+ environment:
+ MYSQL_DATABASE: ${MYSQL_DATABASE}
+ MYSQL_PASSWORD: ${MYSQL_PASSWORD}
+ MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
+ MYSQL_USER: ${MYSQL_USER}
+ healthcheck:
+ test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u${MYSQL_USER}", "-p${MYSQL_PASSWORD}"]
+ interval: 10s
+ timeout: 5s
+ retries: 5
+
+ bot:
+ image: eartharoid/discord-tickets:4.0.21
+ depends_on:
+ mysql:
+ condition: service_healthy
+ restart: unless-stopped
+ hostname: bot
+ networks:
+ - dokploy-network
+ volumes:
+ - tickets-bot:/home/container/user
+ - /etc/timezone:/etc/timezone:ro
+ - /etc/localtime:/etc/localtime:ro
+ tty: true
+ stdin_open: true
+ environment:
+ DB_CONNECTION_URL: mysql://${MYSQL_USER}:${MYSQL_PASSWORD}@mysql/${MYSQL_DATABASE}
+ DISCORD_SECRET: ${DISCORD_SECRET}
+ DISCORD_TOKEN: ${DISCORD_TOKEN}
+ ENCRYPTION_KEY: ${ENCRYPTION_KEY}
+ DB_PROVIDER: mysql
+ HTTP_EXTERNAL: https://${TICKETS_HOST}
+ HTTP_HOST: 0.0.0.0
+ HTTP_PORT: 8169
+ HTTP_TRUST_PROXY: "true"
+ PUBLIC_BOT: "false"
+ PUBLISH_COMMANDS: "true"
+ SUPER: ${SUPER_USERS}
+
+volumes:
+ tickets-mysql:
+ tickets-bot:
\ No newline at end of file
diff --git a/apps/dokploy/templates/discord-tickets/index.ts b/apps/dokploy/templates/discord-tickets/index.ts
new file mode 100644
index 00000000..e2a42649
--- /dev/null
+++ b/apps/dokploy/templates/discord-tickets/index.ts
@@ -0,0 +1,46 @@
+import {
+ type DomainSchema,
+ type Schema,
+ type Template,
+ generatePassword,
+ generateRandomDomain,
+} from "../utils";
+
+export function generate(schema: Schema): Template {
+ const mainDomain = generateRandomDomain(schema);
+ const mysqlPassword = generatePassword();
+ const mysqlRootPassword = generatePassword();
+ const mysqlUser = "tickets";
+ const mysqlDatabase = "tickets";
+
+ // Generate encryption key in the format they use
+ const encryptionKey = Array.from({length: 48}, () =>
+ Math.floor(Math.random() * 16).toString(16)).join('');
+
+ const domains: DomainSchema[] = [
+ {
+ host: mainDomain,
+ port: 8169,
+ serviceName: "bot",
+ },
+ ];
+
+ const envs = [
+ `TICKETS_HOST=${mainDomain}`,
+ `MYSQL_DATABASE=${mysqlDatabase}`,
+ `MYSQL_PASSWORD=${mysqlPassword}`,
+ `MYSQL_ROOT_PASSWORD=${mysqlRootPassword}`,
+ `MYSQL_USER=${mysqlUser}`,
+ `ENCRYPTION_KEY=${encryptionKey}`,
+ // These need to be set by the user through the UI
+ `# Follow the guide at: https://discordtickets.app/self-hosting/installation/docker/#creating-the-discord-application`,
+ `DISCORD_SECRET=`,
+ `DISCORD_TOKEN=`,
+ `SUPER_USERS=YOUR_DISCORD_USER_ID`, // Default super user
+ ];
+
+ return {
+ domains,
+ envs,
+ };
+}
\ No newline at end of file
diff --git a/apps/dokploy/templates/invoiceshelf/docker-compose.yml b/apps/dokploy/templates/invoiceshelf/docker-compose.yml
new file mode 100644
index 00000000..ac4c8d26
--- /dev/null
+++ b/apps/dokploy/templates/invoiceshelf/docker-compose.yml
@@ -0,0 +1,55 @@
+version: "3.8"
+
+services:
+ invoiceshelf_db:
+ image: postgres:15
+ networks:
+ - dokploy-network
+ volumes:
+ - postgres_data:/var/lib/postgresql/data
+ environment:
+ - POSTGRES_PASSWORD=${DB_PASSWORD}
+ - POSTGRES_USER=${DB_USERNAME}
+ - POSTGRES_DB=${DB_DATABASE}
+ healthcheck:
+ test: ["CMD-SHELL", "pg_isready -U ${DB_USERNAME}"]
+ interval: 10s
+ timeout: 5s
+ retries: 5
+
+ invoiceshelf:
+ image: invoiceshelf/invoiceshelf:latest
+ networks:
+ - dokploy-network
+ volumes:
+ - app_data:/data
+ - app_conf:/conf
+ environment:
+ - PHP_TZ=UTC
+ - TIMEZONE=UTC
+ - APP_NAME=InvoiceShelf
+ - APP_ENV=production
+ - APP_DEBUG=false
+ - APP_URL=http://${INVOICESHELF_HOST}
+ - DB_CONNECTION=pgsql
+ - DB_HOST=invoiceshelf_db
+ - DB_PORT=5432
+ - DB_DATABASE=${DB_DATABASE}
+ - DB_USERNAME=${DB_USERNAME}
+ - DB_PASSWORD=${DB_PASSWORD}
+ - CACHE_STORE=file
+ - SESSION_DRIVER=file
+ - SESSION_LIFETIME=120
+ - SESSION_ENCRYPT=true
+ - SESSION_PATH=/
+ - SESSION_DOMAIN=${INVOICESHELF_HOST}
+ - SANCTUM_STATEFUL_DOMAINS=${INVOICESHELF_HOST}
+ - STARTUP_DELAY=10
+ depends_on:
+ invoiceshelf_db:
+ condition: service_healthy
+
+volumes:
+ postgres_data:
+ app_data:
+ app_conf:
\ No newline at end of file
diff --git a/apps/dokploy/templates/invoiceshelf/index.ts b/apps/dokploy/templates/invoiceshelf/index.ts
new file mode 100644
index 00000000..2e7c5cf7
--- /dev/null
+++ b/apps/dokploy/templates/invoiceshelf/index.ts
@@ -0,0 +1,34 @@
+import {
+ type DomainSchema,
+ type Schema,
+ type Template,
+ generatePassword,
+ generateRandomDomain,
+} from "../utils";
+
+export function generate(schema: Schema): Template {
+ const mainDomain = generateRandomDomain(schema);
+ const dbPassword = generatePassword();
+ const dbUsername = "invoiceshelf";
+ const dbDatabase = "invoiceshelf";
+
+ const domains: DomainSchema[] = [
+ {
+ host: mainDomain,
+ port: 80,
+ serviceName: "invoiceshelf",
+ },
+ ];
+
+ const envs = [
+ `INVOICESHELF_HOST=${mainDomain}`,
+ `DB_PASSWORD=${dbPassword}`,
+ `DB_USERNAME=${dbUsername}`,
+ `DB_DATABASE=${dbDatabase}`,
+ ];
+
+ return {
+ domains,
+ envs,
+ };
+}
\ No newline at end of file
diff --git a/apps/dokploy/templates/peppermint/docker-compose.yml b/apps/dokploy/templates/peppermint/docker-compose.yml
new file mode 100644
index 00000000..a20bedf4
--- /dev/null
+++ b/apps/dokploy/templates/peppermint/docker-compose.yml
@@ -0,0 +1,36 @@
+version: "3.8"
+
+services:
+ peppermint_postgres:
+ image: postgres:latest
+ restart: always
+ networks:
+ - dokploy-network
+ volumes:
+ - pgdata:/var/lib/postgresql/data
+ environment:
+ POSTGRES_USER: peppermint
+ POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
+ POSTGRES_DB: peppermint
+ healthcheck:
+ test: ["CMD-SHELL", "pg_isready -U peppermint"]
+ interval: 10s
+ timeout: 5s
+ retries: 5
+
+ peppermint:
+ image: pepperlabs/peppermint:latest
+ restart: always
+ networks:
+ - dokploy-network
+ depends_on:
+ peppermint_postgres:
+ condition: service_healthy
+ environment:
+ DB_USERNAME: "peppermint"
+ DB_PASSWORD: ${POSTGRES_PASSWORD}
+ DB_HOST: "peppermint_postgres"
+ SECRET: ${SECRET}
+
+volumes:
+ pgdata:
\ No newline at end of file
diff --git a/apps/dokploy/templates/peppermint/index.ts b/apps/dokploy/templates/peppermint/index.ts
new file mode 100644
index 00000000..867a5254
--- /dev/null
+++ b/apps/dokploy/templates/peppermint/index.ts
@@ -0,0 +1,43 @@
+import {
+ type DomainSchema,
+ type Schema,
+ type Template,
+ generateBase64,
+ generatePassword,
+ generateRandomDomain,
+} from "../utils";
+
+export function generate(schema: Schema): Template {
+ // Generate domains and secrets
+ const mainDomain = generateRandomDomain(schema);
+ const apiDomain = generateRandomDomain(schema);
+ const postgresPassword = generatePassword();
+ const secret = generateBase64(32);
+
+ // Configure domain routing
+ const domains: DomainSchema[] = [
+ {
+ host: mainDomain,
+ port: 3000,
+ serviceName: "peppermint",
+ },
+ {
+ host: apiDomain,
+ port: 5003,
+ serviceName: "peppermint",
+ },
+ ];
+
+ // Set environment variables
+ const envs = [
+ `MAIN_DOMAIN=${mainDomain}`,
+ `API_DOMAIN=${apiDomain}`,
+ `POSTGRES_PASSWORD=${postgresPassword}`,
+ `SECRET=${secret}`,
+ ];
+
+ return {
+ domains,
+ envs,
+ };
+}
\ No newline at end of file
diff --git a/apps/dokploy/templates/postiz/docker-compose.yml b/apps/dokploy/templates/postiz/docker-compose.yml
new file mode 100644
index 00000000..42a4b976
--- /dev/null
+++ b/apps/dokploy/templates/postiz/docker-compose.yml
@@ -0,0 +1,64 @@
+version: "3.8"
+
+services:
+ postiz:
+ image: ghcr.io/gitroomhq/postiz-app:latest
+ restart: always
+ networks:
+ - dokploy-network
+ environment:
+ MAIN_URL: "https://${POSTIZ_HOST}"
+ FRONTEND_URL: "https://${POSTIZ_HOST}"
+ NEXT_PUBLIC_BACKEND_URL: "https://${POSTIZ_HOST}/api"
+ JWT_SECRET: ${JWT_SECRET}
+ DATABASE_URL: "postgresql://${DB_USER}:${DB_PASSWORD}@postiz-postgres:5432/${DB_NAME}"
+ REDIS_URL: "redis://postiz-redis:6379"
+ BACKEND_INTERNAL_URL: "http://localhost:3000"
+ IS_GENERAL: "true"
+ STORAGE_PROVIDER: "local"
+ UPLOAD_DIRECTORY: "/uploads"
+ NEXT_PUBLIC_UPLOAD_DIRECTORY: "/uploads"
+ volumes:
+ - postiz-config:/config/
+ - postiz-uploads:/uploads/
+ depends_on:
+ postiz-postgres:
+ condition: service_healthy
+ postiz-redis:
+ condition: service_healthy
+
+ postiz-postgres:
+ image: postgres:17-alpine
+ restart: always
+ networks:
+ - dokploy-network
+ environment:
+ POSTGRES_PASSWORD: ${DB_PASSWORD}
+ POSTGRES_USER: ${DB_USER}
+ POSTGRES_DB: ${DB_NAME}
+ volumes:
+ - postgres-volume:/var/lib/postgresql/data
+ healthcheck:
+ test: pg_isready -U ${DB_USER} -d ${DB_NAME}
+ interval: 10s
+ timeout: 3s
+ retries: 3
+
+ postiz-redis:
+ image: redis:7.2
+ restart: always
+ networks:
+ - dokploy-network
+ healthcheck:
+ test: redis-cli ping
+ interval: 10s
+ timeout: 3s
+ retries: 3
+ volumes:
+ - postiz-redis-data:/data
+
+volumes:
+ postgres-volume:
+ postiz-redis-data:
+ postiz-config:
+ postiz-uploads:
\ No newline at end of file
diff --git a/apps/dokploy/templates/postiz/index.ts b/apps/dokploy/templates/postiz/index.ts
new file mode 100644
index 00000000..44015465
--- /dev/null
+++ b/apps/dokploy/templates/postiz/index.ts
@@ -0,0 +1,37 @@
+import {
+ type DomainSchema,
+ type Schema,
+ type Template,
+ generatePassword,
+ generateRandomDomain,
+ generateBase64,
+} from "../utils";
+
+export function generate(schema: Schema): Template {
+ const mainDomain = generateRandomDomain(schema);
+ const dbPassword = generatePassword();
+ const dbUser = "postiz";
+ const dbName = "postiz";
+ const jwtSecret = generateBase64(32);
+
+ const domains: DomainSchema[] = [
+ {
+ host: mainDomain,
+ port: 5000,
+ serviceName: "postiz",
+ },
+ ];
+
+ const envs = [
+ `POSTIZ_HOST=${mainDomain}`,
+ `DB_PASSWORD=${dbPassword}`,
+ `DB_USER=${dbUser}`,
+ `DB_NAME=${dbName}`,
+ `JWT_SECRET=${jwtSecret}`,
+ ];
+
+ return {
+ domains,
+ envs,
+ };
+}
\ No newline at end of file
diff --git a/apps/dokploy/templates/slash/docker-compose.yml b/apps/dokploy/templates/slash/docker-compose.yml
new file mode 100644
index 00000000..fce3114e
--- /dev/null
+++ b/apps/dokploy/templates/slash/docker-compose.yml
@@ -0,0 +1,37 @@
+version: "3.8"
+
+services:
+ slash:
+ image: yourselfhosted/slash:latest
+ networks:
+ - dokploy-network
+ volumes:
+ - slash_data:/var/opt/slash
+ environment:
+ - SLASH_DRIVER=postgres
+ - SLASH_DSN=postgresql://${DB_USER}:${DB_PASSWORD}@db:5432/${DB_NAME}?sslmode=disable
+ depends_on:
+ db:
+ condition: service_healthy
+ restart: unless-stopped
+
+ db:
+ image: postgres:16-alpine
+ networks:
+ - dokploy-network
+ volumes:
+ - postgres_data:/var/lib/postgresql/data
+ environment:
+ - POSTGRES_USER=${DB_USER}
+ - POSTGRES_PASSWORD=${DB_PASSWORD}
+ - POSTGRES_DB=${DB_NAME}
+ healthcheck:
+ test: ["CMD-SHELL", "pg_isready -U ${DB_USER} -d ${DB_NAME}"]
+ interval: 10s
+ timeout: 5s
+ retries: 5
+ restart: unless-stopped
+
+volumes:
+ slash_data:
+ postgres_data:
\ No newline at end of file
diff --git a/apps/dokploy/templates/slash/index.ts b/apps/dokploy/templates/slash/index.ts
new file mode 100644
index 00000000..5d2bcdb2
--- /dev/null
+++ b/apps/dokploy/templates/slash/index.ts
@@ -0,0 +1,33 @@
+import {
+ type DomainSchema,
+ type Schema,
+ type Template,
+ generatePassword,
+ generateRandomDomain,
+} from "../utils";
+
+export function generate(schema: Schema): Template {
+ const mainDomain = generateRandomDomain(schema);
+ const dbPassword = generatePassword();
+ const dbUser = "slash";
+ const dbName = "slash";
+
+ const domains: DomainSchema[] = [
+ {
+ host: mainDomain,
+ port: 5231,
+ serviceName: "slash",
+ },
+ ];
+
+ const envs = [
+ `DB_USER=${dbUser}`,
+ `DB_PASSWORD=${dbPassword}`,
+ `DB_NAME=${dbName}`,
+ ];
+
+ return {
+ domains,
+ envs,
+ };
+}
\ No newline at end of file
diff --git a/apps/dokploy/templates/templates.ts b/apps/dokploy/templates/templates.ts
index 322eb8e2..1ad1a012 100644
--- a/apps/dokploy/templates/templates.ts
+++ b/apps/dokploy/templates/templates.ts
@@ -703,6 +703,104 @@ export const templates: TemplateData[] = [
load: () => import("./lobe-chat/index").then((m) => m.generate),
},
{
+ id: "peppermint",
+ name: "Peppermint",
+ version: "latest",
+ description: "Peppermint is a modern, open-source API development platform that helps you build, test and document your APIs.",
+ logo: "peppermint.svg",
+ links: {
+ github: "https://github.com/Peppermint-Lab/peppermint",
+ website: "https://peppermint.sh/",
+ docs: "https://docs.peppermint.sh/"
+ },
+ tags: ["api", "development", "documentation"],
+ load: () => import("./peppermint/index").then((m) => m.generate),
+ },
+ {
+ id: "windmill",
+ name: "Windmill",
+ version: "latest",
+ description: "A developer platform to build production-grade workflows and internal apps. Open-source alternative to Airplane, Retool, and GitHub Actions.",
+ logo: "windmill.svg",
+ links: {
+ github: "https://github.com/windmill-labs/windmill",
+ website: "https://www.windmill.dev/",
+ docs: "https://docs.windmill.dev/",
+ },
+ tags: ["workflow", "automation", "development"],
+ load: () => import("./windmill/index").then((m) => m.generate),
+ },
+ {
+ id: "activepieces",
+ name: "Activepieces",
+ version: "0.35.0",
+ description: "Open-source no-code business automation tool. An alternative to Zapier, Make.com, and Tray.",
+ logo: "activepieces.svg",
+ links: {
+ github: "https://github.com/activepieces/activepieces",
+ website: "https://www.activepieces.com/",
+ docs: "https://www.activepieces.com/docs",
+ },
+ tags: ["automation", "workflow", "no-code"],
+ load: () => import("./activepieces/index").then((m) => m.generate),
+ },
+ {
+ id: "invoiceshelf",
+ name: "InvoiceShelf",
+ version: "latest",
+ description: "InvoiceShelf is a self-hosted open source invoicing system for freelancers and small businesses.",
+ logo: "invoiceshelf.png",
+ links: {
+ github: "https://github.com/InvoiceShelf/invoiceshelf",
+ website: "https://invoiceshelf.com",
+ docs: "https://github.com/InvoiceShelf/invoiceshelf#readme",
+ },
+ tags: ["invoice", "business", "finance"],
+ load: () => import("./invoiceshelf/index").then((m) => m.generate),
+ },
+ {
+ id: "postiz",
+ name: "Postiz",
+ version: "latest",
+ description: "Postiz is a modern, open-source platform for managing and publishing content across multiple channels.",
+ logo: "postiz.png",
+ links: {
+ github: "https://github.com/gitroomhq/postiz",
+ website: "https://postiz.io",
+ docs: "https://docs.postiz.io",
+ },
+ tags: ["cms", "content-management", "publishing"],
+ load: () => import("./postiz/index").then((m) => m.generate),
+ },
+ {
+ id: "slash",
+ name: "Slash",
+ version: "latest",
+ description: "Slash is a modern, self-hosted bookmarking service and link shortener that helps you organize and share your favorite links.",
+ logo: "slash.png",
+ links: {
+ github: "https://github.com/yourselfhosted/slash",
+ website: "https://github.com/yourselfhosted/slash#readme",
+ docs: "https://github.com/yourselfhosted/slash/wiki",
+ },
+ tags: ["bookmarks", "link-shortener", "self-hosted"],
+ load: () => import("./slash/index").then((m) => m.generate),
+ },
+ {
+ id: "discord-tickets",
+ name: "Discord Tickets",
+ version: "4.0.21",
+ description: "An open-source Discord bot for creating and managing support ticket channels.",
+ logo: "discord-tickets.png",
+ links: {
+ github: "https://github.com/discord-tickets/bot",
+ website: "https://discordtickets.app",
+ docs: "https://discordtickets.app/self-hosting/installation/docker/",
+ },
+ tags: ["discord", "tickets", "support"],
+ load: () => import("./discord-tickets/index").then((m) => m.generate),
+ },
+ {
id: "nextcloud-aio",
name: "Nextcloud All in One",
version: "30.0.2",
diff --git a/apps/dokploy/templates/windmill/docker-compose.yml b/apps/dokploy/templates/windmill/docker-compose.yml
new file mode 100644
index 00000000..5646c47a
--- /dev/null
+++ b/apps/dokploy/templates/windmill/docker-compose.yml
@@ -0,0 +1,107 @@
+version: "3.8"
+
+services:
+ db:
+ image: postgres:16
+ shm_size: 1g
+ restart: unless-stopped
+ volumes:
+ - db_data:/var/lib/postgresql/data
+ networks:
+ - dokploy-network
+ environment:
+ POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
+ POSTGRES_DB: windmill
+ healthcheck:
+ test: ["CMD-SHELL", "pg_isready -U postgres"]
+ interval: 10s
+ timeout: 5s
+ retries: 5
+
+ windmill_server:
+ image: ghcr.io/windmill-labs/windmill:main
+ networks:
+ - dokploy-network
+ restart: unless-stopped
+ environment:
+ - DATABASE_URL=${DATABASE_URL}
+ - MODE=server
+ - BASE_URL=http://${WINDMILL_HOST}
+ depends_on:
+ db:
+ condition: service_healthy
+ volumes:
+ - worker_logs:/tmp/windmill/logs
+
+ windmill_worker:
+ image: ghcr.io/windmill-labs/windmill:main
+ deploy:
+ replicas: 3
+ resources:
+ limits:
+ cpus: "1"
+ memory: 2048M
+ restart: unless-stopped
+ networks:
+ - dokploy-network
+ environment:
+ - DATABASE_URL=${DATABASE_URL}
+ - MODE=worker
+ - WORKER_GROUP=default
+ depends_on:
+ db:
+ condition: service_healthy
+ volumes:
+ - /var/run/docker.sock:/var/run/docker.sock
+ - worker_dependency_cache:/tmp/windmill/cache
+ - worker_logs:/tmp/windmill/logs
+
+ windmill_worker_native:
+ image: ghcr.io/windmill-labs/windmill:main
+ deploy:
+ replicas: 1
+ resources:
+ limits:
+ cpus: "0.1"
+ memory: 128M
+ restart: unless-stopped
+ networks:
+ - dokploy-network
+ environment:
+ - DATABASE_URL=${DATABASE_URL}
+ - MODE=worker
+ - WORKER_GROUP=native
+ - NUM_WORKERS=8
+ - SLEEP_QUEUE=200
+ depends_on:
+ db:
+ condition: service_healthy
+ volumes:
+ - worker_logs:/tmp/windmill/logs
+
+ lsp:
+ image: ghcr.io/windmill-labs/windmill-lsp:latest
+ restart: unless-stopped
+ networks:
+ - dokploy-network
+ volumes:
+ - lsp_cache:/root/.cache
+
+ caddy:
+ image: ghcr.io/windmill-labs/caddy-l4:latest
+ restart: unless-stopped
+ networks:
+ - dokploy-network
+ volumes:
+ - ../files/Caddyfile:/etc/caddy/Caddyfile
+ environment:
+ - BASE_URL=":80"
+ depends_on:
+ - windmill_server
+ - lsp
+
+volumes:
+ db_data:
+ worker_dependency_cache:
+ worker_logs:
+ lsp_cache:
\ No newline at end of file
diff --git a/apps/dokploy/templates/windmill/index.ts b/apps/dokploy/templates/windmill/index.ts
new file mode 100644
index 00000000..875b7afa
--- /dev/null
+++ b/apps/dokploy/templates/windmill/index.ts
@@ -0,0 +1,43 @@
+import {
+ type DomainSchema,
+ type Schema,
+ type Template,
+ generatePassword,
+ generateRandomDomain,
+} from "../utils";
+
+export function generate(schema: Schema): Template {
+ const mainDomain = generateRandomDomain(schema);
+ const postgresPassword = generatePassword();
+
+ const domains: DomainSchema[] = [
+ {
+ host: mainDomain,
+ port: 80,
+ serviceName: "caddy",
+ },
+ ];
+
+ const envs = [
+ `WINDMILL_HOST=${mainDomain}`,
+ `POSTGRES_PASSWORD=${postgresPassword}`,
+ `DATABASE_URL=postgres://postgres:${postgresPassword}@db/windmill?sslmode=disable`,
+ ];
+
+ const mounts: Template["mounts"] = [
+ {
+ filePath: "Caddyfile",
+ content: `:80 {
+ bind 0.0.0.0
+ reverse_proxy /ws/* http://lsp:3001
+ reverse_proxy /* http://windmill_server:8000
+}`,
+ },
+ ];
+
+ return {
+ domains,
+ envs,
+ mounts,
+ };
+}
\ No newline at end of file