Compare commits

..
Author SHA1 Message Date
Mauricio SiuandClaude Fable 5 21c1fec5d8 feat: validator opt-out marker for intentional host ports + annotate rustdesk
The validate-docker-compose CI on this PR was failing on rustdesk's
hbbs/hbbr port mappings (21115-21119) — intentional host-published ports
for the RustDesk relay/rendezvous protocol, which Traefik cannot route.

Adds a '# dokploy: allow-host-ports' top-of-file marker that downgrades
the port-mapping errors to warnings for such protocol templates
(mail/game/streaming/VPN/remote-desktop), and annotates rustdesk.
Other exception templates (poste.io, mailu, oryx, fivem...) can be
annotated case-by-case as the weekly audit (#1049) surfaces them.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-06 01:22:34 -06:00
Mauricio Siu f8a75dba2b Merge remote-tracking branch 'origin/canary' into fix/normalize-empty-mounts 2026-08-06 01:21:15 -06:00
Mauricio SiuandClaude Fable 5 b9c4365e9f fix: normalize template.toml mounts across all blueprints (closes #1047)
- 79 blueprints declared a bare [[config.mounts]] header (one empty array
  element in TOML) -> replaced with the repo idiom 'mounts = []'
- 38 blueprints carried doc-style mount blocks (name/mountPath/description)
  that don't match the schema (filePath/content) and are inert in Dokploy's
  template processor -> removed; their named volumes already live in each
  docker-compose.yml
- penpot: duplicate 'expose' map key made its docker-compose.yml invalid
  YAML -> merged into one expose list

After this, validate-template.ts passes for all 502 blueprints. The
remaining validate-docker-compose.ts flags are the intentional host-port
templates (mail/game/streaming protocols: poste.io, mailu, oryx, fivem,
lodestone, etc.) which the validator does not yet model as exceptions.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-03 04:28:49 -06:00
66 changed files with 529 additions and 1030 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 105 KiB

-32
View File
@@ -1,32 +0,0 @@
version: "3.8"
services:
9router:
image: decolua/9router:0.5.40
restart: unless-stopped
environment:
DATA_DIR: /app/data
PORT: "20128"
HOSTNAME: "0.0.0.0"
NODE_ENV: production
JWT_SECRET: ${JWT_SECRET}
INITIAL_PASSWORD: ${INITIAL_PASSWORD}
API_KEY_SECRET: ${API_KEY_SECRET}
MACHINE_ID_SALT: ${MACHINE_ID_SALT}
BASE_URL: http://${ROUTER_HOST}
NEXT_PUBLIC_BASE_URL: http://${ROUTER_HOST}
HEADROOM_URL: http://headroom:8787
AUTH_COOKIE_SECURE: "false"
volumes:
- 9router-data:/app/data
depends_on:
- headroom
# Optional token-reduction proxy that 9Router calls through HEADROOM_URL.
# Shipped as a sidecar because the 9Router image does not bundle it.
headroom:
image: ghcr.io/chopratejas/headroom:0.6.7
restart: unless-stopped
volumes:
9router-data:
-17
View File
@@ -1,17 +0,0 @@
{
"id": "9router",
"name": "9Router",
"version": "0.5.40",
"description": "Self-hosted AI model router that rotates requests across 40+ providers with automatic fallback, exposing an OpenAI-compatible endpoint for coding agents.",
"logo": "9router.png",
"links": {
"github": "https://github.com/decolua/9router",
"website": "https://9router.com",
"docs": "https://github.com/decolua/9router/blob/master/DOCKER.md"
},
"tags": [
"ai",
"proxy",
"developer-tools"
]
}
-21
View File
@@ -1,21 +0,0 @@
[variables]
main_domain = "${domain}"
jwt_secret = "${password:64}"
initial_password = "${password:32}"
api_key_secret = "${password:64}"
machine_id_salt = "${password:32}"
[config]
env = [
"ROUTER_HOST=${main_domain}",
"JWT_SECRET=${jwt_secret}",
"INITIAL_PASSWORD=${initial_password}",
"API_KEY_SECRET=${api_key_secret}",
"MACHINE_ID_SALT=${machine_id_salt}",
]
mounts = []
[[config.domains]]
serviceName = "9router"
port = 20128
host = "${main_domain}"
+1 -3
View File
@@ -1,4 +1,3 @@
# dokploy: allow-host-ports — DNS (53/tcp+udp), DHCP (67/68) and DNS-over-TLS/QUIC (853) are not HTTP protocols; clients must reach them directly on the host, Traefik cannot route them.
version: "3.8"
services:
adguardhome:
@@ -11,8 +10,7 @@ services:
- "68:68/tcp" # DHCP Client
- "853:853/tcp" # DNS over TLS, DNS-over-QUIC
- "853:853/udp" # DNS over TLS, DNS-over-QUIC
expose:
- 6060 # HTTP (pprof) — debug endpoint, no need to publish it on the host
- "6060:6060/tcp" # HTTP (pprof)
volumes:
- adguardhome-work:/opt/adguardhome/work
- adguardhome-conf:/opt/adguardhome/conf
-1
View File
@@ -1,4 +1,3 @@
# dokploy: allow-host-ports — Anytype clients speak the any-sync protocol (TCP 33010, UDP/QUIC 33020) directly against the server; it is not HTTP, so Traefik cannot route it.
# Example: Any-Sync-Bundle with embedded MongoDB and Redis (all-in-one image)
#
# Usage:
+1 -1
View File
@@ -2,7 +2,7 @@ version: "3.8"
services:
chatto:
image: ghcr.io/chattocorp/chatto:0.4
image: ghcr.io/chattocorp/chatto:0.3.8
restart: unless-stopped
expose:
- "4000"
+1 -1
View File
@@ -1,7 +1,7 @@
{
"id": "chatto",
"name": "Chatto (single binary)",
"version": "0.4.x",
"version": "0.3.8",
"description": "A fully-featured real-time chat application for teams and communities. This template deploys the single Chatto binary with embedded NATS. Note: email/password registration requires SMTP to be configured after deployment; voice/video calls are not included in the single-binary setup.",
"logo": "logo.png",
"links": {
+11
View File
@@ -6,6 +6,8 @@
services:
chibisafe:
image: chibisafe/chibisafe:latest
networks:
- chibinet
environment:
- BASE_API_URL=http://chibisafe_server:8000
restart: unless-stopped
@@ -18,6 +20,8 @@ services:
chibisafe_server:
image: chibisafe/chibisafe-server:latest
networks:
- chibinet
volumes:
- database:/app/database:rw
- uploads:/app/uploads:rw
@@ -39,6 +43,8 @@ services:
caddy:
image: caddy:2-alpine
networks:
- chibinet
volumes:
- ../files/Caddyfile:/etc/caddy/Caddyfile:ro
- uploads:/app/uploads:ro
@@ -56,3 +62,8 @@ volumes:
database:
uploads:
logs:
networks:
chibinet:
driver: bridge
internal: true
-8
View File
@@ -1,8 +0,0 @@
<svg width="1031" height="244" viewBox="0 0 1031 244" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M374.72 225.76C356.8 225.76 341.027 221.653 327.4 213.44C313.773 205.04 303.133 193.093 295.48 177.6C287.827 162.107 284 143.627 284 122.16C284 100.88 287.733 82.4933 295.2 67C302.853 51.32 313.493 39.28 327.12 30.88C340.747 22.2933 356.707 18 375 18C399.64 18 418.773 24.16 432.4 36.48C446.027 48.8 454.893 65.88 459 87.72L427.36 89.4C424.747 75.7733 419.147 65.1333 410.56 57.48C401.973 49.64 390.12 45.72 375 45.72C362.867 45.72 352.32 48.8 343.36 54.96C334.587 61.12 327.68 69.8933 322.64 81.28C317.787 92.6667 315.36 106.293 315.36 122.16C315.36 138.027 317.787 151.653 322.64 163.04C327.68 174.427 334.68 183.107 343.64 189.08C352.6 195.053 362.96 198.04 374.72 198.04C390.773 198.04 403.187 193.84 411.96 185.44C420.92 176.853 426.52 165.093 428.76 150.16L460.4 151.84C457.973 166.96 453.12 180.027 445.84 191.04C438.56 202.053 428.947 210.64 417 216.8C405.053 222.773 390.96 225.76 374.72 225.76Z" fill="white"/>
<path d="M488.982 221.28V72.32H516.142L517.262 111.8L514.742 110.96C516.795 97.52 520.902 87.72 527.062 81.56C533.409 75.4 541.902 72.32 552.542 72.32H566.822V98.92H552.542C545.075 98.92 538.822 100.133 533.782 102.56C528.742 104.987 524.915 108.72 522.302 113.76C519.875 118.8 518.662 125.333 518.662 133.36V221.28H488.982Z" fill="white"/>
<path d="M648.166 224.64C633.606 224.64 621.006 221.467 610.366 215.12C599.913 208.773 591.793 199.72 586.006 187.96C580.406 176.2 577.606 162.48 577.606 146.8C577.606 131.12 580.406 117.493 586.006 105.92C591.793 94.16 599.913 85.1067 610.366 78.76C620.82 72.2267 633.14 68.96 647.326 68.96C660.766 68.96 672.62 72.1333 682.886 78.48C693.153 84.64 701.086 93.6 706.686 105.36C712.473 117.12 715.366 131.307 715.366 147.92V155.48H608.406C609.153 170.04 612.98 180.96 619.886 188.24C626.98 195.52 636.5 199.16 648.446 199.16C657.22 199.16 664.5 197.107 670.286 193C676.073 188.893 680.086 183.387 682.326 176.48L713.126 178.44C709.206 192.253 701.46 203.453 689.886 212.04C678.5 220.44 664.593 224.64 648.166 224.64ZM608.406 133.08H684.006C683.073 119.827 679.246 110.027 672.526 103.68C665.993 97.3333 657.593 94.16 647.326 94.16C636.686 94.16 627.913 97.52 621.006 104.24C614.286 110.773 610.086 120.387 608.406 133.08Z" fill="white"/>
<path d="M805.64 224.64C791.08 224.64 778.48 221.467 767.84 215.12C757.387 208.773 749.267 199.72 743.48 187.96C737.88 176.2 735.08 162.48 735.08 146.8C735.08 131.12 737.88 117.493 743.48 105.92C749.267 94.16 757.387 85.1067 767.84 78.76C778.293 72.2267 790.613 68.96 804.8 68.96C818.24 68.96 830.093 72.1333 840.36 78.48C850.627 84.64 858.56 93.6 864.16 105.36C869.947 117.12 872.84 131.307 872.84 147.92V155.48H765.88C766.627 170.04 770.453 180.96 777.36 188.24C784.453 195.52 793.973 199.16 805.92 199.16C814.693 199.16 821.973 197.107 827.76 193C833.547 188.893 837.56 183.387 839.8 176.48L870.6 178.44C866.68 192.253 858.933 203.453 847.36 212.04C835.973 220.44 822.067 224.64 805.64 224.64ZM765.88 133.08H841.48C840.547 119.827 836.72 110.027 830 103.68C823.467 97.3333 815.067 94.16 804.8 94.16C794.16 94.16 785.387 97.52 778.48 104.24C771.76 110.773 767.56 120.387 765.88 133.08Z" fill="white"/>
<path d="M954.714 224.64C942.02 224.64 930.914 221.467 921.394 215.12C912.06 208.773 904.874 199.813 899.834 188.24C894.98 176.48 892.554 162.667 892.554 146.8C892.554 130.933 895.074 117.213 900.114 105.64C905.154 93.88 912.34 84.8267 921.674 78.48C931.007 72.1333 942.02 68.96 954.714 68.96C964.98 68.96 974.127 71.1067 982.154 75.4C990.18 79.6933 996.247 85.6667 1000.35 93.32V22.48H1030.03V221.28H1002.31L1001.47 198.88C997.367 206.907 991.114 213.253 982.714 217.92C974.5 222.4 965.167 224.64 954.714 224.64ZM962.554 198.88C970.58 198.88 977.394 196.827 982.994 192.72C988.594 188.613 992.887 182.64 995.874 174.8C998.86 166.96 1000.35 157.627 1000.35 146.8C1000.35 135.6 998.86 126.173 995.874 118.52C992.887 110.68 988.594 104.8 982.994 100.88C977.394 96.7733 970.58 94.72 962.554 94.72C950.607 94.72 941.087 99.3867 933.994 108.72C926.9 117.867 923.354 130.56 923.354 146.8C923.354 162.853 926.9 175.547 933.994 184.88C941.087 194.213 950.607 198.88 962.554 198.88Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M156.683 25.8912C156.683 20.7784 153.949 16.6984 150.153 15.8682L50.8845 0.803281C44.4474 -0.207939 40.8385 -0.418278 34.4022 1.07664C21.948 4.53448 19.4689 5.55156 7.16796 9.52026C1.74137 10.8567 0 14.8659 0 20.1609L0.111367 226.189C0.111367 231.049 3.3005 234.218 7.66406 235.676C14.0626 237.863 21.4027 240.262 28.5807 242.489C33.5011 244.038 38.8467 244.038 45.3161 243.664C52.231 243.259 92.7685 236.617 149.596 229.044C154.101 228.447 156.663 224.772 156.663 221.087L156.713 25.8912H156.683ZM132.658 192.425C134.521 192.222 139.148 190.127 139.148 184.639V59.9491C139.279 57.4788 137.528 52.9533 132.445 52.5382L75.861 44.5097C70.7786 44.2971 68.0552 47.9924 68.0552 51.4043V194.055C68.2678 196.525 70.161 200.362 75.2333 199.542L132.658 192.425Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 4.9 KiB

-65
View File
@@ -1,65 +0,0 @@
version: "3.8"
services:
creed:
build:
context: https://github.com/connorhpbrn/creed.git#e9b096d6d68fef6df336338bc9965a94ab62f75e
dockerfile_inline: |
FROM node:20-alpine AS builder
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
ARG NEXT_PUBLIC_SITE_URL
ARG NEXT_PUBLIC_SUPABASE_URL
ARG NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY
ARG NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY
ARG NEXT_PUBLIC_CONTACT_EMAIL
ARG NEXT_PUBLIC_GITHUB_URL
ENV NEXT_PUBLIC_SITE_URL=$NEXT_PUBLIC_SITE_URL \
NEXT_PUBLIC_SUPABASE_URL=$NEXT_PUBLIC_SUPABASE_URL \
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=$NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY \
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=$NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY \
NEXT_PUBLIC_CONTACT_EMAIL=$NEXT_PUBLIC_CONTACT_EMAIL \
NEXT_PUBLIC_GITHUB_URL=$NEXT_PUBLIC_GITHUB_URL
RUN npm run build
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next ./.next
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json
COPY --from=builder /app/next.config.ts ./next.config.ts
EXPOSE 3000
CMD ["npm", "start"]
args:
NEXT_PUBLIC_SITE_URL: ${NEXT_PUBLIC_SITE_URL}
NEXT_PUBLIC_SUPABASE_URL: ${NEXT_PUBLIC_SUPABASE_URL}
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY: ${NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY}
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY: ${NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY}
NEXT_PUBLIC_CONTACT_EMAIL: ${NEXT_PUBLIC_CONTACT_EMAIL}
NEXT_PUBLIC_GITHUB_URL: ${NEXT_PUBLIC_GITHUB_URL}
restart: unless-stopped
environment:
- NEXT_PUBLIC_SITE_URL=${NEXT_PUBLIC_SITE_URL}
- NEXT_PUBLIC_SUPABASE_URL=${NEXT_PUBLIC_SUPABASE_URL}
- NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=${NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY}
- SUPABASE_SECRET_KEY=${SUPABASE_SECRET_KEY}
- CREED_ENCRYPTION_SECRET=${CREED_ENCRYPTION_SECRET}
- STRIPE_SECRET_KEY=${STRIPE_SECRET_KEY}
- NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=${NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY}
- STRIPE_WEBHOOK_SECRET=${STRIPE_WEBHOOK_SECRET}
- OPENROUTER_PLATFORM_KEY=${OPENROUTER_PLATFORM_KEY}
- ANALYSIS_MODEL=${ANALYSIS_MODEL}
- TAB_MODEL=${TAB_MODEL}
- PANEL_MODEL=${PANEL_MODEL}
- RESEND_API_KEY=${RESEND_API_KEY}
- RESEND_FROM_EMAIL=${RESEND_FROM_EMAIL}
- GITHUB_OAUTH_CLIENT_ID=${GITHUB_OAUTH_CLIENT_ID}
- GITHUB_OAUTH_CLIENT_SECRET=${GITHUB_OAUTH_CLIENT_SECRET}
- NEXT_PUBLIC_CONTACT_EMAIL=${NEXT_PUBLIC_CONTACT_EMAIL}
- NEXT_PUBLIC_GITHUB_URL=${NEXT_PUBLIC_GITHUB_URL}
- CREED_CSP_ENFORCE=${CREED_CSP_ENFORCE}
expose:
- 3000
-19
View File
@@ -1,19 +0,0 @@
{
"id": "creed",
"name": "Creed",
"version": "e9b096d",
"description": "One personal context file every AI agent reads before answering and proposes updates to as it learns about you. Requires an external Supabase project (see instructions).",
"logo": "creed.svg",
"links": {
"github": "https://github.com/connorhpbrn/creed",
"website": "https://creed.md",
"docs": "https://creed.md/docs"
},
"tags": [
"ai",
"productivity",
"mcp",
"nextjs",
"supabase"
]
}
-105
View File
@@ -1,105 +0,0 @@
[variables]
main_domain = "${domain}"
creed_encryption_secret = "${base64:32}"
[config]
env = [
"NEXT_PUBLIC_SITE_URL=https://${main_domain}",
"NEXT_PUBLIC_SUPABASE_URL=",
"NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=",
"SUPABASE_SECRET_KEY=",
"CREED_ENCRYPTION_SECRET=${creed_encryption_secret}",
"STRIPE_SECRET_KEY=",
"NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=",
"STRIPE_WEBHOOK_SECRET=",
"OPENROUTER_PLATFORM_KEY=",
"ANALYSIS_MODEL=",
"TAB_MODEL=",
"PANEL_MODEL=",
"RESEND_API_KEY=",
"RESEND_FROM_EMAIL=Creed <hello@example.com>",
"GITHUB_OAUTH_CLIENT_ID=",
"GITHUB_OAUTH_CLIENT_SECRET=",
"NEXT_PUBLIC_CONTACT_EMAIL=",
"NEXT_PUBLIC_GITHUB_URL=https://github.com/connorhpbrn/creed",
"CREED_CSP_ENFORCE=",
]
[[config.domains]]
serviceName = "creed"
port = 3000
host = "${main_domain}"
[[config.mounts]]
filePath = "README.md"
content = """# Creed
Creed (creed.md) is a personal context file: one Markdown file every AI agent
reads before answering and proposes updates to as it learns about you. This
template builds the app from source (https://github.com/connorhpbrn/creed)
and runs it as a stateless Next.js container — Postgres, auth, and storage
live in Supabase, which is **not** part of this template.
## Before you deploy
Creed needs a Supabase project. It is not enough to point it at a plain
Postgres database: the app relies on Supabase Auth, Row Level Security, and
realtime subscriptions, and its schema is applied through the Supabase CLI.
1. Create a Supabase project — either a hosted one at supabase.com, or your
own self-hosted instance (Dokploy has a separate **Supabase** template you
can deploy for this).
2. On a machine with Node 20+, clone the Creed repo and push its schema to
your project:
```bash
git clone https://github.com/connorhpbrn/creed.git
cd creed && npm install
supabase link --project-ref <your-project-ref>
supabase db push
```
3. From Project Settings -> API in your Supabase dashboard, copy the
project URL, the publishable (anon) key, and the secret (service_role)
key.
## Required environment variables
Fill these in on the **Environment** tab before the first deploy, then
redeploy:
- `NEXT_PUBLIC_SUPABASE_URL`: your Supabase project URL.
- `NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY`: the Supabase anon/publishable key.
- `SUPABASE_SECRET_KEY`: the Supabase service_role/secret key. Server-only,
never exposed to the browser.
- `CREED_ENCRYPTION_SECRET` is generated for you (used to encrypt provider
tokens at rest).
- `NEXT_PUBLIC_SITE_URL` is set to this service's domain automatically.
The app boots with only these set, but sign-in, AI features, and billing
stay disabled until their own variables are configured.
## Optional integrations
- **Stripe** (paid plans): `STRIPE_SECRET_KEY`, `NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY`,
`STRIPE_WEBHOOK_SECRET`. Create a webhook endpoint at
`https://<your-domain>/api/stripe/webhook` in the Stripe dashboard for the
signing secret.
- **OpenRouter** (managed AI credits): `OPENROUTER_PLATFORM_KEY` from
https://openrouter.ai/keys. `ANALYSIS_MODEL`, `TAB_MODEL`, `PANEL_MODEL`
override the default model per AI feature and can be left blank.
- **Resend** (Company invite emails): `RESEND_API_KEY` and
`RESEND_FROM_EMAIL` (must be on a domain verified in Resend).
- **GitHub OAuth** (repo sync, not sign-in): create an OAuth App at
https://github.com/settings/developers with callback URL
`https://<your-domain>/auth/github/callback`, then set
`GITHUB_OAUTH_CLIENT_ID` and `GITHUB_OAUTH_CLIENT_SECRET`.
- `CREED_CSP_ENFORCE=1` switches the Content-Security-Policy header from
report-only to enforcing. Leave it unset for at least one deploy cycle so
you can check the browser console for violations first.
## Notes
- This template builds the image from the Creed GitHub repository during
deployment; the first deploy can take a few minutes.
- The app itself is stateless — all data lives in Supabase, so there are no
volumes to back up here.
"""
+4 -2
View File
@@ -23,6 +23,7 @@ services:
- us
data-api:
container_name: datalens-data-api
image: ghcr.io/datalens-tech/datalens-data-api:0.2192.0
restart: always
environment:
@@ -42,6 +43,7 @@ services:
- pg-compeng
pg-us:
container_name: datalens-pg-us
image: postgres:16-alpine
restart: always
environment:
@@ -73,8 +75,8 @@ services:
datalens:
image: ghcr.io/datalens-tech/datalens-ui:0.2601.0
restart: always
expose:
- 8080 # web UI — routed through Traefik via the template domain
ports:
- ${UI_PORT:-8080}:8080
depends_on:
- us
- control-api
+2 -2
View File
@@ -4,8 +4,8 @@ services:
image: 'docker.dragonflydb.io/dragonflydb/dragonfly'
ulimits:
memlock: -1
expose:
- 6379
ports:
- "6379:6379"
volumes:
- dragonflydata:/data
environment:
@@ -8,6 +8,12 @@ services:
MASTERPASS: ${MASTERPASS}
volumes:
- drizzle-gateway:/app
networks:
- dokploy-network
volumes:
drizzle-gateway:
networks:
dokploy-network:
external: true
@@ -3,6 +3,7 @@ version: '3.8'
services:
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:8.10.2
container_name: elasticsearch
environment:
- discovery.type=single-node
- xpack.security.enabled=false
@@ -19,6 +20,7 @@ services:
kibana:
image: docker.elastic.co/kibana/kibana:8.10.2
container_name: kibana
environment:
- ELASTICSEARCH_HOSTS=http://elasticsearch:9200
expose:
+8
View File
@@ -21,6 +21,10 @@ services:
volumes:
- emqx_data:/opt/emqx/data
- emqx_log:/opt/emqx/log
networks:
dokploy-network:
aliases:
- emqx-service
restart: unless-stopped
healthcheck:
test: ["CMD", "/opt/emqx/bin/emqx_ctl", "status"]
@@ -48,3 +52,7 @@ services:
volumes:
emqx_data:
emqx_log:
networks:
dokploy-network:
external: true
+1 -1
View File
@@ -1,7 +1,7 @@
# dokploy: allow-host-ports — Enshrouded game clients connect over raw UDP (15637 game, 27015 Steam query); Traefik cannot route UDP game traffic.
services:
enshrouded:
image: mornedhels/enshrouded-server:latest
container_name: enshrouded
hostname: enshrouded
restart: unless-stopped
stop_grace_period: 90s
+31
View File
@@ -10,6 +10,8 @@ services:
<<: *custom_image
volumes:
- sites:/home/frappe/frappe-bench/sites
networks:
- bench-network
healthcheck:
test:
- CMD
@@ -40,6 +42,8 @@ services:
volumes:
- sites:/home/frappe/frappe-bench/sites
networks:
- bench-network
healthcheck:
test:
@@ -59,6 +63,8 @@ services:
- default
volumes:
- sites:/home/frappe/frappe-bench/sites
networks:
- bench-network
healthcheck:
test:
- CMD
@@ -81,6 +87,8 @@ services:
- long
volumes:
- sites:/home/frappe/frappe-bench/sites
networks:
- bench-network
healthcheck:
test:
- CMD
@@ -103,6 +111,8 @@ services:
- short
volumes:
- sites:/home/frappe/frappe-bench/sites
networks:
- bench-network
healthcheck:
test:
- CMD
@@ -135,6 +145,8 @@ services:
required: true
volumes:
- sites:/home/frappe/frappe-bench/sites
networks:
- bench-network
websocket:
<<: *custom_image
@@ -155,6 +167,8 @@ services:
required: true
volumes:
- sites:/home/frappe/frappe-bench/sites
networks:
- bench-network
configurator:
<<: *custom_image
@@ -183,6 +197,8 @@ services:
REGENERATE_APPS_TXT: "${REGENERATE_APPS_TXT:-0}"
volumes:
- sites:/home/frappe/frappe-bench/sites
networks:
- bench-network
create-site:
<<: *custom_image
@@ -221,6 +237,8 @@ services:
DB_PORT: "${DB_PORT:-3306}"
DB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
INSTALL_APP_ARGS: ${INSTALL_APP_ARGS}
networks:
- bench-network
migration:
<<: *custom_image
@@ -240,6 +258,8 @@ services:
bench --site all set-config -p pause_scheduler 0;
volumes:
- sites:/home/frappe/frappe-bench/sites
networks:
- bench-network
db:
image: mariadb:10.6
@@ -262,6 +282,8 @@ services:
- MARIADB_ROOT_PASSWORD=${DB_ROOT_PASSWORD}
volumes:
- db-data:/var/lib/mysql
networks:
- bench-network
redis-cache:
deploy:
@@ -270,6 +292,8 @@ services:
image: redis:6.2-alpine
volumes:
- redis-cache-data:/data
networks:
- bench-network
healthcheck:
test:
- CMD
@@ -286,6 +310,8 @@ services:
image: redis:6.2-alpine
volumes:
- redis-queue-data:/data
networks:
- bench-network
healthcheck:
test:
- CMD
@@ -302,6 +328,8 @@ services:
image: redis:6.2-alpine
volumes:
- redis-socketio-data:/data
networks:
- bench-network
healthcheck:
test:
- CMD
@@ -321,3 +349,6 @@ volumes:
type: "${SITE_VOLUME_TYPE}"
o: "${SITE_VOLUME_OPTS}"
device: "${SITE_VOLUME_DEV}"
networks:
bench-network:
+1 -2
View File
@@ -1,6 +1,5 @@
# dokploy: allow-host-ports — FiveM game clients connect over raw TCP/UDP on 30120; Traefik cannot route game traffic.
# docker-compose.yml
#
#
# IMPORTANT: FiveM Template - Two Deployment Modes
#
# MODE 1: Standard FiveM Server
+1 -1
View File
@@ -1,6 +1,6 @@
services:
fmd-server:
image: registry.gitlab.com/fmd-foss/fmd-server:0.16.0
image: registry.gitlab.com/fmd-foss/fmd-server:v0.11.0
expose:
- 8080
environment:
+1 -1
View File
@@ -1,7 +1,7 @@
{
"id": "fmd-server",
"name": "FMD Server",
"version": "0.16.0",
"version": "0.11.0",
"description": "A server to communicate with the FMD Android app, to locate and control your devices.",
"logo": "fmd-server.svg",
"links": {
-1
View File
@@ -1,4 +1,3 @@
# dokploy: allow-host-ports — VoIP stack: SIP signaling (5060-5063 TCP/UDP), RTP media (10000-10100/udp) and the gRPC API endpoints (envoy 8449, rtpengine control 8080) are reached directly by phones/SDKs; these protocols cannot be routed by Traefik.
services:
dashboard:
image: fonoster/dashboard:0.15.15
+8 -9
View File
@@ -1,8 +1,7 @@
version: "3.8"
services:
forgejo:
image: codeberg.org/forgejo/forgejo:16
depends_on:
- db
image: codeberg.org/forgejo/forgejo:10
environment:
- USER_UID=${USER_UID}
- USER_GID=${USER_GID}
@@ -11,17 +10,15 @@ services:
- FORGEJO__database__NAME=forgejo
- FORGEJO__database__USER=forgejo
- FORGEJO__database__PASSWD=forgejo
- FORGEJO__server__DOMAIN=${FORGEJO_DOMAIN}
- FORGEJO__server__SSH_DOMAIN=${FORGEJO_SSH_DOMAIN}
- FORGEJO__server__ROOT_URL=https://${FORGEJO_DOMAIN}/
restart: always
expose:
- 3000
- 22
volumes:
- forgejo_server:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
depends_on:
- db
db:
image: postgres:17
restart: always
@@ -29,8 +26,10 @@ services:
- POSTGRES_USER=forgejo
- POSTGRES_PASSWORD=forgejo
- POSTGRES_DB=forgejo
volumes:
- forgejo_db:/var/lib/postgresql/data
volumes:
forgejo_db:
driver: local
+1 -1
View File
@@ -1,7 +1,7 @@
{
"id": "forgejo",
"name": "Forgejo",
"version": "16",
"version": "10",
"description": "Forgejo is a self-hosted lightweight software forge. Easy to install and low maintenance, it just does the job",
"logo": "forgejo.svg",
"links": {
+1 -6
View File
@@ -2,12 +2,7 @@
main_domain = "${domain}"
[config]
env = [
"USER_UID=1000",
"USER_GID=1000",
"FORGEJO_DOMAIN=${main_domain}",
"FORGEJO_SSH_DOMAIN=${main_domain}"
]
env = ["USER_UID=1000", "USER_GID=1000"]
mounts = []
[[config.domains]]
+31
View File
@@ -10,6 +10,8 @@ services:
<<: *custom_image
volumes:
- sites:/home/frappe/frappe-bench/sites
networks:
- bench-network
healthcheck:
test:
- CMD
@@ -40,6 +42,8 @@ services:
volumes:
- sites:/home/frappe/frappe-bench/sites
networks:
- bench-network
healthcheck:
test:
@@ -59,6 +63,8 @@ services:
- default
volumes:
- sites:/home/frappe/frappe-bench/sites
networks:
- bench-network
healthcheck:
test:
- CMD
@@ -81,6 +87,8 @@ services:
- long
volumes:
- sites:/home/frappe/frappe-bench/sites
networks:
- bench-network
healthcheck:
test:
- CMD
@@ -103,6 +111,8 @@ services:
- short
volumes:
- sites:/home/frappe/frappe-bench/sites
networks:
- bench-network
healthcheck:
test:
- CMD
@@ -135,6 +145,8 @@ services:
required: true
volumes:
- sites:/home/frappe/frappe-bench/sites
networks:
- bench-network
websocket:
<<: *custom_image
@@ -155,6 +167,8 @@ services:
required: true
volumes:
- sites:/home/frappe/frappe-bench/sites
networks:
- bench-network
configurator:
<<: *custom_image
@@ -183,6 +197,8 @@ services:
REGENERATE_APPS_TXT: "${REGENERATE_APPS_TXT:-0}"
volumes:
- sites:/home/frappe/frappe-bench/sites
networks:
- bench-network
create-site:
<<: *custom_image
@@ -221,6 +237,8 @@ services:
DB_PORT: "${DB_PORT:-3306}"
DB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
INSTALL_APP_ARGS: ${INSTALL_APP_ARGS}
networks:
- bench-network
migration:
<<: *custom_image
@@ -240,6 +258,8 @@ services:
bench --site all set-config -p pause_scheduler 0;
volumes:
- sites:/home/frappe/frappe-bench/sites
networks:
- bench-network
db:
image: mariadb:10.6
@@ -262,6 +282,8 @@ services:
- MARIADB_ROOT_PASSWORD=${DB_ROOT_PASSWORD}
volumes:
- db-data:/var/lib/mysql
networks:
- bench-network
redis-cache:
deploy:
@@ -270,6 +292,8 @@ services:
image: redis:6.2-alpine
volumes:
- redis-cache-data:/data
networks:
- bench-network
healthcheck:
test:
- CMD
@@ -286,6 +310,8 @@ services:
image: redis:6.2-alpine
volumes:
- redis-queue-data:/data
networks:
- bench-network
healthcheck:
test:
- CMD
@@ -302,6 +328,8 @@ services:
image: redis:6.2-alpine
volumes:
- redis-socketio-data:/data
networks:
- bench-network
healthcheck:
test:
- CMD
@@ -321,3 +349,6 @@ volumes:
type: "${SITE_VOLUME_TYPE}"
o: "${SITE_VOLUME_OPTS}"
device: "${SITE_VOLUME_DEV}"
networks:
bench-network:
-1
View File
@@ -1,4 +1,3 @@
# dokploy: allow-host-ports — Lodestone hosts game servers (Minecraft et al.) on 25565-25590 (raw TCP) and the dashboard talks to the core agent on 16662 directly by server address; neither is routable through Traefik.
version: '3.8'
services:
+2 -2
View File
@@ -2,8 +2,8 @@ services:
mailpit:
image: axllent/mailpit:v1.22.3
restart: unless-stopped
expose:
- 1025 # SMTP — other services reach it over the internal Docker network (mailpit:1025)
ports:
- '1025:1025'
volumes:
- 'mailpit-data:/data'
environment:
-1
View File
@@ -1,4 +1,3 @@
# dokploy: allow-host-ports — mail protocols (SMTP 25, SMTPS 465, Submission 587, IMAPS 993) are not HTTP; mail servers and clients must reach them directly on the host.
version: "3.8"
# Shared Mailu configuration (equivalent to the upstream mailu.env file)
-205
View File
@@ -1,205 +0,0 @@
version: "3.8"
services:
redis:
image: redis:7-alpine
restart: unless-stopped
command: redis-server --appendonly yes
volumes:
- novu-redis:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
mongodb:
image: mongo:8.0.17
restart: unless-stopped
environment:
MONGO_INITDB_ROOT_USERNAME: ${MONGO_INITDB_ROOT_USERNAME}
MONGO_INITDB_ROOT_PASSWORD: ${MONGO_INITDB_ROOT_PASSWORD}
volumes:
- novu-mongodb:/data/db
healthcheck:
test:
[
"CMD",
"mongosh",
"--quiet",
"--username",
"${MONGO_INITDB_ROOT_USERNAME}",
"--password",
"${MONGO_INITDB_ROOT_PASSWORD}",
"--eval",
"db.adminCommand('ping').ok",
]
interval: 20s
timeout: 5s
retries: 5
start_period: 20s
api:
image: ghcr.io/novuhq/novu/api:3.18.0
restart: unless-stopped
depends_on:
mongodb:
condition: service_healthy
redis:
condition: service_healthy
environment:
NODE_ENV: ${NODE_ENV}
API_ROOT_URL: ${API_ROOT_URL}
PORT: ${API_PORT}
FRONT_BASE_URL: ${FRONT_BASE_URL}
MONGO_URL: ${MONGO_URL}
MONGO_MIN_POOL_SIZE: ${MONGO_MIN_POOL_SIZE}
MONGO_MAX_POOL_SIZE: ${MONGO_MAX_POOL_SIZE}
MONGO_AUTO_CREATE_INDEXES: ${MONGO_AUTO_CREATE_INDEXES}
REDIS_HOST: ${REDIS_HOST}
REDIS_PORT: ${REDIS_PORT}
REDIS_PASSWORD: ${REDIS_PASSWORD}
REDIS_DB_INDEX: 2
REDIS_CACHE_SERVICE_HOST: ${REDIS_CACHE_SERVICE_HOST}
REDIS_CACHE_SERVICE_PORT: ${REDIS_CACHE_SERVICE_PORT}
S3_LOCAL_STACK: ${S3_LOCAL_STACK}
S3_BUCKET_NAME: ${S3_BUCKET_NAME}
S3_REGION: ${S3_REGION}
AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID}
AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY}
JWT_SECRET: ${JWT_SECRET}
STORE_ENCRYPTION_KEY: ${STORE_ENCRYPTION_KEY}
NOVU_SECRET_KEY: ${NOVU_SECRET_KEY}
SUBSCRIBER_WIDGET_JWT_EXPIRATION_TIME: ${SUBSCRIBER_WIDGET_JWT_EXPIRATION_TIME}
SENTRY_DSN: ${SENTRY_DSN}
NEW_RELIC_ENABLED: ${NEW_RELIC_ENABLED}
NEW_RELIC_APP_NAME: ${NEW_RELIC_APP_NAME}
NEW_RELIC_LICENSE_KEY: ${NEW_RELIC_LICENSE_KEY}
API_CONTEXT_PATH: ${API_CONTEXT_PATH:-}
IS_API_IDEMPOTENCY_ENABLED: ${IS_API_IDEMPOTENCY_ENABLED}
IS_API_RATE_LIMITING_ENABLED: ${IS_API_RATE_LIMITING_ENABLED}
IS_NEW_MESSAGES_API_RESPONSE_ENABLED: ${IS_NEW_MESSAGES_API_RESPONSE_ENABLED}
IS_V2_ENABLED: ${IS_V2_ENABLED}
IS_SELF_HOSTED: ${IS_SELF_HOSTED}
expose:
- "3000"
healthcheck:
test:
[
"CMD-SHELL",
"wget --no-verbose --tries=1 --spider http://localhost:$${PORT}/v1/health-check || exit 1",
]
interval: 20s
timeout: 10s
retries: 3
start_period: 40s
worker:
image: ghcr.io/novuhq/novu/worker:3.18.0
restart: unless-stopped
depends_on:
mongodb:
condition: service_healthy
redis:
condition: service_healthy
environment:
NODE_ENV: ${NODE_ENV}
PORT: ${WORKER_PORT:-3004}
MONGO_URL: ${MONGO_URL}
MONGO_MIN_POOL_SIZE: ${MONGO_MIN_POOL_SIZE}
MONGO_MAX_POOL_SIZE: ${MONGO_MAX_POOL_SIZE}
REDIS_HOST: ${REDIS_HOST}
REDIS_PORT: ${REDIS_PORT}
REDIS_PASSWORD: ${REDIS_PASSWORD}
REDIS_DB_INDEX: 2
REDIS_CACHE_SERVICE_HOST: ${REDIS_CACHE_SERVICE_HOST}
REDIS_CACHE_SERVICE_PORT: ${REDIS_CACHE_SERVICE_PORT}
S3_LOCAL_STACK: ${S3_LOCAL_STACK}
S3_BUCKET_NAME: ${S3_BUCKET_NAME}
S3_REGION: ${S3_REGION}
AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID}
AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY}
STORE_ENCRYPTION_KEY: ${STORE_ENCRYPTION_KEY}
SUBSCRIBER_WIDGET_JWT_EXPIRATION_TIME: ${SUBSCRIBER_WIDGET_JWT_EXPIRATION_TIME}
SENTRY_DSN: ${SENTRY_DSN}
NEW_RELIC_ENABLED: ${NEW_RELIC_ENABLED}
NEW_RELIC_APP_NAME: ${NEW_RELIC_APP_NAME}
NEW_RELIC_LICENSE_KEY: ${NEW_RELIC_LICENSE_KEY}
BROADCAST_QUEUE_CHUNK_SIZE: ${BROADCAST_QUEUE_CHUNK_SIZE}
MULTICAST_QUEUE_CHUNK_SIZE: ${MULTICAST_QUEUE_CHUNK_SIZE}
API_ROOT_URL: http://api:${API_PORT}
IS_EMAIL_INLINE_CSS_DISABLED: ${IS_EMAIL_INLINE_CSS_DISABLED}
IS_USE_MERGED_DIGEST_ID_ENABLED: ${IS_USE_MERGED_DIGEST_ID_ENABLED}
healthcheck:
test:
[
"CMD-SHELL",
"wget --no-verbose --tries=1 --spider http://localhost:$${PORT:-3004}/v1/health-check || exit 1",
]
interval: 20s
timeout: 10s
retries: 3
start_period: 20s
ws:
image: ghcr.io/novuhq/novu/ws:3.18.0
restart: unless-stopped
depends_on:
mongodb:
condition: service_healthy
redis:
condition: service_healthy
environment:
PORT: ${WS_PORT}
NODE_ENV: ${NODE_ENV}
MONGO_URL: ${MONGO_URL}
MONGO_MIN_POOL_SIZE: ${MONGO_MIN_POOL_SIZE}
MONGO_MAX_POOL_SIZE: ${MONGO_MAX_POOL_SIZE}
REDIS_HOST: ${REDIS_HOST}
REDIS_PORT: ${REDIS_PORT}
REDIS_PASSWORD: ${REDIS_PASSWORD}
JWT_SECRET: ${JWT_SECRET}
WS_CONTEXT_PATH: ${WS_CONTEXT_PATH:-}
NEW_RELIC_ENABLED: ${NEW_RELIC_ENABLED}
NEW_RELIC_APP_NAME: ${NEW_RELIC_APP_NAME}
NEW_RELIC_LICENSE_KEY: ${NEW_RELIC_LICENSE_KEY}
expose:
- "3002"
healthcheck:
test:
[
"CMD-SHELL",
"wget --no-verbose --tries=1 --spider http://localhost:$${PORT}/v1/health-check || exit 1",
]
interval: 20s
timeout: 10s
retries: 3
start_period: 40s
novu:
image: ghcr.io/novuhq/novu/dashboard:3.18.0
restart: unless-stopped
depends_on:
api:
condition: service_healthy
worker:
condition: service_healthy
environment:
VITE_API_HOSTNAME: ${VITE_API_HOSTNAME}
VITE_WEBSOCKET_HOSTNAME: ${VITE_WEBSOCKET_HOSTNAME}
expose:
- "4000"
healthcheck:
test:
[
"CMD-SHELL",
'node -e "const http = require(''http''); const req = http.get({hostname: ''localhost'', port: 4000, path: ''/'', timeout: 5000}, (res) => { process.exit(res.statusCode === 200 ? 0 : 1); }); req.on(''error'', () => process.exit(1)); req.on(''timeout'', () => { req.destroy(); process.exit(1); });"',
]
interval: 20s
timeout: 10s
retries: 3
start_period: 20s
volumes:
novu-mongodb:
novu-redis:
-21
View File
@@ -1,21 +0,0 @@
{
"id": "novu",
"name": "Novu",
"version": "3.18.0",
"description": "Open-source notification infrastructure for multi-channel workflows — in-app Inbox, email, SMS, push, and chat — with a unified API and dashboard.",
"logo": "novu.png",
"links": {
"github": "https://github.com/novuhq/novu",
"website": "https://novu.co/",
"docs": "https://docs.novu.co/community/self-hosting-novu/deploy-with-docker"
},
"tags": [
"notifications",
"email",
"sms",
"push",
"inbox",
"self-hosted",
"api"
]
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

-129
View File
@@ -1,129 +0,0 @@
[variables]
main_domain = "${domain}"
api_domain = "${domain}"
ws_domain = "${domain}"
jwt_secret = "${password:64}"
# STORE_ENCRYPTION_KEY must be exactly 32 characters
store_encryption_key = "${password:32}"
novu_secret_key = "${password:64}"
mongo_password = "${password:32}"
mongo_user = "root"
[config]
mounts = []
env = [
"###########################################",
"# Secrets",
"# JWT_SECRET / NOVU_SECRET_KEY: auto-generated — keep as-is unless rotating",
"# STORE_ENCRYPTION_KEY: must be exactly 32 characters",
"###########################################",
"JWT_SECRET=${jwt_secret}",
"STORE_ENCRYPTION_KEY=${store_encryption_key}",
"NOVU_SECRET_KEY=${novu_secret_key}",
"SUBSCRIBER_WIDGET_JWT_EXPIRATION_TIME=15d",
"",
"###########################################",
"# General / Feature Flags",
"###########################################",
"NODE_ENV=production",
"IS_SELF_HOSTED=true",
"IS_V2_ENABLED=true",
"IS_API_IDEMPOTENCY_ENABLED=false",
"IS_API_RATE_LIMITING_ENABLED=false",
"IS_NEW_MESSAGES_API_RESPONSE_ENABLED=true",
"IS_EMAIL_INLINE_CSS_DISABLED=false",
"IS_USE_MERGED_DIGEST_ID_ENABLED=false",
"",
"###########################################",
"# Public Service URLs",
"# Assign 3 domains in Dokploy Domains tab:",
"# FRONT_BASE_URL -> novu service (port 4000) — Dashboard",
"# API_ROOT_URL / VITE_* -> api service (port 3000) — REST API",
"# VITE_WEBSOCKET_HOSTNAME -> ws service (port 3002) — WebSocket",
"###########################################",
"FRONT_BASE_URL=https://${main_domain}",
"API_ROOT_URL=https://${api_domain}",
"VITE_API_HOSTNAME=https://${api_domain}",
"VITE_WEBSOCKET_HOSTNAME=https://${ws_domain}",
"",
"###########################################",
"# Ports (internal — do not change unless you know why)",
"###########################################",
"API_PORT=3000",
"WS_PORT=3002",
"WORKER_PORT=3004",
"",
"###########################################",
"# MongoDB",
"###########################################",
"MONGO_INITDB_ROOT_USERNAME=${mongo_user}",
"MONGO_INITDB_ROOT_PASSWORD=${mongo_password}",
"MONGO_URL=mongodb://${mongo_user}:${mongo_password}@mongodb:27017/novu-db?authSource=admin",
"MONGO_AUTO_CREATE_INDEXES=true",
"MONGO_MIN_POOL_SIZE=5",
"MONGO_MAX_POOL_SIZE=10",
"",
"###########################################",
"# Redis (queue + cache — shared for small deployments)",
"###########################################",
"REDIS_HOST=redis",
"REDIS_PORT=6379",
"REDIS_PASSWORD=",
"REDIS_CACHE_SERVICE_HOST=redis",
"REDIS_CACHE_SERVICE_PORT=6379",
"",
"###########################################",
"# S3 / Object Storage (optional)",
"# NOT local disk — Novu has no built-in filesystem storage.",
"# S3_LOCAL_STACK = your S3/MinIO endpoint URL (Novu's official env name).",
"# Example MinIO: S3_LOCAL_STACK=https://minio.yourdomain.com",
"# Example LocalStack: S3_LOCAL_STACK=http://localhost:4566",
"# Leave empty + test keys for basic deploy (dashboard/API still work).",
"# When you need uploads, set real endpoint + bucket + AWS_* credentials.",
"###########################################",
"S3_LOCAL_STACK=",
"S3_BUCKET_NAME=novu-local",
"S3_REGION=us-east-1",
"AWS_ACCESS_KEY_ID=test",
"AWS_SECRET_ACCESS_KEY=test",
"",
"###########################################",
"# Context Paths (path-based reverse proxy only)",
"# Leave empty for normal subdomain routing in Dokploy",
"###########################################",
"API_CONTEXT_PATH=",
"WS_CONTEXT_PATH=",
"",
"###########################################",
"# Analytics / Observability (disabled by default)",
"###########################################",
"SENTRY_DSN=",
"NEW_RELIC_ENABLED=false",
"NEW_RELIC_APP_NAME=",
"NEW_RELIC_LICENSE_KEY=",
"",
"###########################################",
"# Worker Tuning",
"###########################################",
"BROADCAST_QUEUE_CHUNK_SIZE=100",
"MULTICAST_QUEUE_CHUNK_SIZE=100",
]
# Dashboard UI
[[config.domains]]
serviceName = "novu"
port = 4_000
host = "${main_domain}"
# REST API
[[config.domains]]
serviceName = "api"
port = 3_000
host = "${api_domain}"
# WebSocket service (Inbox / real-time)
[[config.domains]]
serviceName = "ws"
port = 3_002
host = "${ws_domain}"
-19
View File
@@ -1,19 +0,0 @@
# Open Design
Local-first, open-source design tool with native desktop apps, a large library of
design systems, and an extensible plugin ecosystem.
## Notes
- **Access / security.** This template sets `OD_DISABLE_API_AUTH=1`. The Open Design
daemon token-gates its API when bound to a non-loopback address, and a browser
cannot supply that bearer token — so disabling it is required for the web UI to
load. As a result the instance is **reachable by anyone who has the URL**. If it is
internet-facing, put an authenticating layer in front (for example Dokploy/Traefik
basic-auth) and enable an HTTPS certificate on the domain.
- **AI features.** The image intentionally does not bundle an AI agent CLI. To
generate designs, either **Sign in to Open Design** (cloud) or choose **Bring your
own key** and provide a provider API key (e.g. `ANTHROPIC_API_KEY`,
`OPENAI_API_KEY`). A "vela binary not found" notice on the sign-in screen is
expected and only affects the cloud-agent path.
-29
View File
@@ -1,29 +0,0 @@
version: "3.8"
services:
open-design:
image: ghcr.io/nexu-io/od:0.16.1
restart: unless-stopped
environment:
NODE_ENV: production
NODE_OPTIONS: --max-old-space-size=192
OD_BIND_HOST: 0.0.0.0
OD_PORT: 7456
OD_API_TOKEN: ${OD_API_TOKEN}
OD_ALLOWED_ORIGINS: ${OD_ALLOWED_ORIGINS}
# The daemon token-gates its API when bound to 0.0.0.0, and a browser
# cannot present that token, so the web UI needs API auth disabled to
# load. The instance is then reachable by anyone with the URL — front it
# with auth/HTTPS if it is internet-facing (see README.md).
OD_DISABLE_API_AUTH: "1"
volumes:
- open_design_data:/app/.od
healthcheck:
test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:7456/api/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"]
interval: 30s
timeout: 5s
retries: 3
start_period: 20s
volumes:
open_design_data: {}
-16
View File
@@ -1,16 +0,0 @@
{
"id": "open-design",
"name": "Open Design",
"version": "0.16.1",
"description": "Open Design is a local-first, open-source design tool with native desktop apps, a large library of design systems, and an extensible plugin ecosystem that runs across many coding agents.",
"logo": "open-design.svg",
"links": {
"github": "https://github.com/nexu-io/open-design",
"website": "https://open-design.ai",
"docs": "https://open-design.ai"
},
"tags": [
"design",
"self-hosted"
]
}
-3
View File
@@ -1,3 +0,0 @@
<svg width="82" height="82" viewBox="0 0.726562 82 82" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M41 0.726562C76.5753 0.726562 82 6.15121 82 41.7266C82 77.3019 76.5753 82.7266 41 82.7266C5.42465 82.7266 0 77.3019 0 41.7266C0 6.15121 5.42465 0.726562 41 0.726562ZM40.8906 16.4258C26.9164 16.4258 15.5879 27.7543 15.5879 41.7285C15.5879 46.7757 15.5879 58.0219 15.5879 63.665C15.588 65.5281 17.091 67.0312 18.9541 67.0312H40.8906C54.8647 67.0311 66.1932 55.7026 66.1934 41.7285C66.1934 27.7544 54.8647 16.4259 40.8906 16.4258ZM40.8906 21.4863C52.0699 21.4864 61.1328 30.5492 61.1328 41.7285C61.1327 52.9078 52.0699 61.9706 40.8906 61.9707C29.7113 61.9707 20.6485 52.9078 20.6484 41.7285C20.6484 30.5491 29.7113 21.4863 40.8906 21.4863ZM32.6445 32.2549C31.9921 32.0027 31.3503 32.6469 31.5996 33.3037L39.3145 53.6045C39.6345 54.4468 40.877 54.2162 40.877 53.3145V41.6836H52.665C53.5605 41.6836 53.7908 40.4368 52.9551 40.1133L32.6445 32.2549Z" fill="#26251E"/>
</svg>

Before

Width:  |  Height:  |  Size: 980 B

-15
View File
@@ -1,15 +0,0 @@
[variables]
main_domain = "${domain}"
api_token = "${password:32}"
[config]
env = [
"OD_API_TOKEN=${api_token}",
"OD_ALLOWED_ORIGINS=https://${main_domain},http://${main_domain}",
]
mounts = []
[[config.domains]]
serviceName = "open-design"
port = 7456
host = "${main_domain}"
-1
View File
@@ -1,4 +1,3 @@
# dokploy: allow-host-ports — RTMP (1935/tcp), WebRTC (8000/udp) and SRT (10080/udp) are streaming protocols Traefik cannot route; they must be published on the host.
version: "3.8"
services:
oryx:
-1
View File
@@ -1,4 +1,3 @@
# dokploy: allow-host-ports — mail protocols (SMTP 25/465/587, POP3 110/995, IMAP 143/993, Sieve 4190) are not HTTP; mail servers and clients must reach them directly on the host.
version: "3.8"
services:
mailserver:
@@ -1,4 +1,3 @@
# dokploy: allow-container-names — frozen legacy template (pre-Dokploy 0.22.5). Supabase functionally depends on container names: Kong routes Realtime via its container DNS name and Vector derives log routing from container names. The ${CONTAINER_PREFIX} per-deploy hash prevents name collisions.
# Usage
# Start: docker compose up
# With helpers: docker compose -f docker-compose.yml -f ./dev/docker-compose.dev.yml up
@@ -38,6 +38,12 @@ services:
MYSQL_ROOT_PASSWORD:
DB_CONNECTION: "mysql"
networks:
default:
ipam:
config:
- subnet: 172.20.0.0/16
volumes:
pterodb:
pterovar:
+1 -2
View File
@@ -1,6 +1,5 @@
# dokploy: allow-host-ports — BitTorrent peer connections (6881 TCP/UDP) must reach the host directly; the peering protocol is not HTTP, so Traefik cannot route it.
# docker-compose.yml
#
#
# IMPORTANT: First-time setup information
# - Default username: admin
# - Password: Check container logs for temporary password on first startup
+10
View File
@@ -20,6 +20,8 @@ services:
- MARIADB_AUTO_UPGRADE=1
volumes:
- seafile-mysql-db:/var/lib/mysql"
networks:
- seafile-net
healthcheck:
test:
[
@@ -37,6 +39,8 @@ services:
memcached:
image: memcached:1.6.29
entrypoint: memcached -m 256
networks:
- seafile-net
healthcheck:
test:
[
@@ -74,12 +78,18 @@ services:
condition: service_healthy
memcached:
condition: service_started
networks:
- seafile-net
healthcheck:
test: ["CMD", "curl", "-f", "http://127.0.0.1:80/api2/ping"]
interval: 20s
timeout: 5s
retries: 10
networks:
seafile-net:
name: seafile-net
volumes:
seafile-mysql-db:
seafile-data:
+3 -1
View File
@@ -27,7 +27,7 @@ services:
retries: 5
senddock:
image: ghcr.io/arkhe-systems/senddock:latest
image: ghcr.io/arkhe-systems/senddock:0.6.5.1
restart: unless-stopped
depends_on:
postgres:
@@ -40,6 +40,8 @@ services:
- 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
+1 -1
View File
@@ -1,7 +1,7 @@
{
"id": "senddock",
"name": "SendDock",
"version": "0.8.0",
"version": "0.6.5.1",
"description": "Open-source, self-hosted email marketing platform with BYO SMTP. Manage subscribers, templates, broadcasts, and scheduled campaigns from one place.",
"logo": "senddock.svg",
"links": {
+2 -1
View File
@@ -7,7 +7,8 @@ jwt_secret = "${password:64}"
env = [
"POSTGRES_PASSWORD=${postgres_password}",
"JWT_SECRET=${jwt_secret}",
"PUBLIC_URL=https://${main_domain}"
"PUBLIC_URL=https://${main_domain}",
"SENDDOCK_LICENSE_KEY="
]
[[config.domains]]
+1 -3
View File
@@ -13,10 +13,8 @@ services:
- "110" # POP3
- "995" # POP3S
volumes:
- stalwart_etc:/etc/stalwart
- stalwart_data:/var/lib/stalwart
- stalwart_data:/opt/stalwart-mail
restart: unless-stopped
volumes:
stalwart_etc:
stalwart_data:
+81 -21
View File
@@ -11,7 +11,7 @@ name: supabase
services:
studio:
image: supabase/studio:2026.08.03-sha-022b374
image: supabase/studio:2026.06.03-sha-0bca601
restart: unless-stopped
healthcheck:
test:
@@ -23,6 +23,9 @@ services:
interval: 5s
retries: 5
start_period: 30s
depends_on:
analytics:
condition: service_healthy
environment:
HOSTNAME: "0.0.0.0"
@@ -32,9 +35,6 @@ services:
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
# See: https://supabase.com/docs/guides/self-hosting/remove-superuser-access
POSTGRES_USER_READ_WRITE: postgres
PG_META_CRYPTO_KEY: ${PG_META_CRYPTO_KEY}
PGRST_DB_SCHEMAS: ${PGRST_DB_SCHEMAS}
PGRST_DB_MAX_ROWS: ${PGRST_DB_MAX_ROWS:-1000}
@@ -49,12 +49,14 @@ services:
SUPABASE_ANON_KEY: ${ANON_KEY}
SUPABASE_SERVICE_KEY: ${SERVICE_ROLE_KEY}
AUTH_JWT_SECRET: ${JWT_SECRET}
SUPABASE_PUBLISHABLE_KEY: ${SUPABASE_PUBLISHABLE_KEY:-}
SUPABASE_SECRET_KEY: ${SUPABASE_SECRET_KEY:-}
# Analytics (Logflare) was removed from the upstream self-hosted stack
ENABLED_FEATURES_LOGS_ALL: "false"
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"
NEXT_ANALYTICS_BACKEND_PROVIDER: postgres
SNIPPETS_MANAGEMENT_FOLDER: /app/snippets
EDGE_FUNCTIONS_MANAGEMENT_FOLDER: /app/edge-functions
volumes:
@@ -62,7 +64,7 @@ services:
- ../files/volumes/functions:/app/edge-functions:Z
kong:
image: kong/kong:3.9.3
image: kong/kong:3.9.1
restart: unless-stopped
healthcheck:
test: ["CMD", "kong", "health"]
@@ -136,7 +138,6 @@ services:
GOTRUE_JWT_EXP: ${JWT_EXPIRY}
GOTRUE_JWT_SECRET: ${JWT_SECRET}
GOTRUE_JWT_KEYS: ${JWT_KEYS:-[]}
GOTRUE_JWT_ISSUER: ${API_EXTERNAL_URL}
GOTRUE_EXTERNAL_EMAIL_ENABLED: ${ENABLE_EMAIL_SIGNUP}
GOTRUE_EXTERNAL_ANONYMOUS_USERS_ENABLED: ${ENABLE_ANONYMOUS_USERS}
@@ -162,19 +163,12 @@ services:
depends_on:
db:
condition: service_healthy
healthcheck:
test: [ "CMD", "postgrest", "--ready" ]
interval: 5s
timeout: 5s
retries: 3
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_ADMIN_SERVER_PORT: 3001
PGRST_ADMIN_SERVER_HOST: localhost
PGRST_JWT_SECRET: ${JWT_SECRET}
PGRST_DB_USE_LEGACY_GUCS: "false"
PGRST_APP_SETTINGS_JWT_SECRET: ${JWT_SECRET}
@@ -298,8 +292,7 @@ services:
PG_META_DB_HOST: ${POSTGRES_HOST}
PG_META_DB_PORT: ${POSTGRES_PORT}
PG_META_DB_NAME: ${POSTGRES_DB}
# See: https://supabase.com/docs/guides/self-hosting/remove-superuser-access
PG_META_DB_USER: postgres
PG_META_DB_USER: supabase_admin
PG_META_DB_PASSWORD: ${POSTGRES_PASSWORD}
CRYPTO_KEY: ${PG_META_CRYPTO_KEY}
@@ -329,9 +322,43 @@ services:
"/home/deno/functions/main"
]
analytics:
image: supabase/logflare:1.36.1
restart: unless-stopped
expose:
- 4000
# First boot: Logflare seeds _analytics in Postgres; allow extra time before marking unhealthy.
healthcheck:
test:
[
"CMD-SHELL",
"curl -sSfL -o /dev/null http://localhost:4000/health"
]
timeout: 10s
interval: 5s
retries: 15
start_period: 90s
depends_on:
db:
condition: service_healthy
environment:
LOGFLARE_NODE_HOST: 127.0.0.1
DB_USERNAME: supabase_admin
DB_DATABASE: _supabase
DB_HOSTNAME: ${POSTGRES_HOST}
DB_PORT: ${POSTGRES_PORT}
DB_PASSWORD: ${POSTGRES_PASSWORD}
DB_SCHEMA: _analytics
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
POSTGRES_BACKEND_URL: postgresql://supabase_admin:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/_supabase
POSTGRES_BACKEND_SCHEMA: _analytics
LOGFLARE_FEATURE_FLAG_OVERRIDE: multibackend=true
db:
# Major upgrade from Postgres 15 requires a dump/restore for existing installs.
# See: https://github.com/orgs/supabase/discussions/46080
image: supabase/postgres:17.6.1.136
restart: unless-stopped
volumes:
@@ -358,6 +385,9 @@ services:
timeout: 5s
retries: 15
start_period: 60s
depends_on:
vector:
condition: service_healthy
environment:
POSTGRES_HOST: /var/run/postgresql
PGPORT: ${POSTGRES_PORT}
@@ -377,6 +407,36 @@ services:
"log_min_messages=fatal"
]
vector:
image: timberio/vector:0.53.0-alpine
restart: unless-stopped
volumes:
- ../files/volumes/logs/vector.yml:/etc/vector/vector.yml:ro,z
- ${DOCKER_SOCKET_LOCATION}:/var/run/docker.sock:ro,z
healthcheck:
test:
[
"CMD",
"wget",
"--no-verbose",
"--tries=1",
"--spider",
"http://vector:9001/health"
]
timeout: 5s
interval: 5s
retries: 5
start_period: 10s
environment:
LOGFLARE_PUBLIC_ACCESS_TOKEN: ${LOGFLARE_PUBLIC_ACCESS_TOKEN}
command:
[
"--config",
"/etc/vector/vector.yml"
]
security_opt:
- "label=disable"
supavisor:
image: supabase/supavisor:2.9.5
restart: unless-stopped
+1 -1
View File
@@ -1,7 +1,7 @@
{
"id": "supabase",
"name": "SupaBase",
"version": "2026.08.03 / dokploy >= 0.22.5",
"version": "2026.06.03 / dokploy >= 0.22.5",
"description": "The open source Firebase alternative. Supabase gives you a dedicated Postgres database to build your web, mobile, and AI applications. This require at least version 0.22.5 of dokploy.",
"links": {
"github": "https://github.com/supabase/supabase",
+289 -1
View File
@@ -2,6 +2,8 @@
main_domain = "${domain}"
postgres_password = "${password:32}"
dashboard_password = "${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}"
@@ -57,6 +59,8 @@ env = [
'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}',
'',
'',
'############',
@@ -160,7 +164,19 @@ env = [
'# Functions - Configuration for Functions',
'############',
'# NOTE: VERIFY_JWT applies to all functions. Per-function VERIFY_JWT is not supported yet.',
'FUNCTIONS_VERIFY_JWT=false']
'FUNCTIONS_VERIFY_JWT=false',
'',
'',
'############',
'# Logs - Configuration for Logflare',
'############',
'',
'# Docker socket location - this value will differ depending on your OS',
'DOCKER_SOCKET_LOCATION=/var/run/docker.sock',
'',
'# Google Cloud Project details',
'GOOGLE_PROJECT_ID=GOOGLE_PROJECT_ID',
'GOOGLE_PROJECT_NUMBER=GOOGLE_PROJECT_NUMBER']
[[config.mounts]]
filePath = "/volumes/api/kong-entrypoint.sh"
@@ -991,6 +1007,278 @@ Deno.serve(async (req: Request) => {
})
"""
[[config.mounts]]
filePath = "/volumes/logs/vector.yml"
content = """api:
enabled: true
address: 0.0.0.0:9001
sources:
docker_host:
type: docker_logs
transforms:
project_logs:
type: remap
inputs:
- docker_host
source: |-
.project = "default"
.event_message = del(.message)
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)
del(.stream)
del(.label)
del(.image)
del(.host)
del(.stream)
router:
type: route
inputs:
- project_logs
route:
kong: '.appname == "supabase-kong" || .appname == "supabase-envoy"'
auth: '.appname == "supabase-auth"'
rest: '.appname == "supabase-rest"'
realtime: '.appname == "supabase-realtime"'
storage: '.appname == "supabase-storage"'
functions: '.appname == "supabase-functions"'
db: '.appname == "supabase-db"'
# Ignores non nginx errors since they are related with kong booting up
kong_logs:
type: remap
inputs:
- router.kong
source: |-
req, err = parse_nginx_log(.event_message, "combined")
if err == null {
.timestamp = req.timestamp
.metadata.request.headers.referer = req.referer
.metadata.request.headers.user_agent = req.agent
.metadata.request.headers.cf_connecting_ip = req.client
.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
}
kong_err:
type: remap
inputs:
- router.kong
source: |-
.metadata.request.method = "GET"
.metadata.response.status_code = 200
parsed, err = parse_nginx_log(.event_message, "error")
if err == null {
.timestamp = parsed.timestamp
.severity = parsed.severity
.metadata.request.host = parsed.host
.metadata.request.headers.cf_connecting_ip = parsed.client
url, err = split(parsed.request, " ")
if err == null {
.metadata.request.method = url[0]
.metadata.request.path = url[1]
.metadata.request.protocol = url[2]
}
}
if err != null {
abort
}
# Gotrue logs are structured json strings which frontend parses directly. But we keep metadata for consistency.
auth_logs:
type: remap
inputs:
- router.auth
source: |-
parsed, err = parse_json(.event_message)
if err == null {
.metadata.timestamp = parsed.time
.metadata = merge!(.metadata, parsed)
}
# PostgREST logs are structured so we separate timestamp from message using regex
rest_logs:
type: remap
inputs:
- router.rest
source: |-
parsed, err = parse_regex(.event_message, r'^(?P<time>.*): (?P<msg>.*)$')
if err == null {
.event_message = parsed.msg
.timestamp = parse_timestamp!(value: parsed.time,format: "%d/%b/%Y:%H:%M:%S %z")
.metadata.host = .project
}
realtime_logs_filtered:
type: filter
inputs:
- router.realtime
condition: '!contains(string!(.event_message), "/health")'
realtime_logs:
type: remap
inputs:
- realtime_logs_filtered
source: |-
.metadata.project = del(.project)
.metadata.external_id = .metadata.project
parsed, err = parse_regex(.event_message, r'^(?P<time>\\d+:\\d+:\\d+\\.\\d+) \\[(?P<level>\\w+)\\] (?P<msg>.*)$')
if err == null {
.event_message = parsed.msg
.metadata.level = parsed.level
}
functions_logs:
type: remap
inputs:
- router.functions
source: |-
.metadata.project_ref = del(.project)
# Storage logs may contain json objects so we parse them for completeness
storage_logs:
type: remap
inputs:
- router.storage
source: |-
.metadata.project = del(.project)
.metadata.tenantId = .metadata.project
parsed, err = parse_json(.event_message)
if err == null {
.event_message = parsed.msg
.metadata.level = parsed.level
.metadata.timestamp = parsed.time
.metadata.context[0].host = parsed.hostname
.metadata.context[0].pid = parsed.pid
}
# Postgres logs some messages to stderr which we map to warning severity level
db_logs:
type: remap
inputs:
- router.db
source: |-
.metadata.host = "db-default"
.metadata.parsed.timestamp = .timestamp
parsed, err = parse_regex(.event_message, r'.*(?P<level>INFO|NOTICE|WARNING|ERROR|LOG|FATAL|PANIC?):.*', numeric_groups: true)
if err != null || parsed == null {
.metadata.parsed.error_severity = "info"
}
if parsed.level != null {
.metadata.parsed.error_severity = parsed.level
}
if .metadata.parsed.error_severity == "info" {
.metadata.parsed.error_severity = "log"
}
.metadata.parsed.error_severity = upcase!(.metadata.parsed.error_severity)
sinks:
logflare_auth:
type: 'http'
inputs:
- auth_logs
encoding:
codec: 'json'
method: 'post'
request:
retry_max_duration_secs: 30
retry_initial_backoff_secs: 1
headers:
x-api-key: ${LOGFLARE_PUBLIC_ACCESS_TOKEN?LOGFLARE_PUBLIC_ACCESS_TOKEN is required}
uri: 'http://analytics:4000/api/logs?source_name=gotrue.logs.prod'
logflare_realtime:
type: 'http'
inputs:
- realtime_logs
encoding:
codec: 'json'
method: 'post'
request:
retry_max_duration_secs: 30
retry_initial_backoff_secs: 1
headers:
x-api-key: ${LOGFLARE_PUBLIC_ACCESS_TOKEN?LOGFLARE_PUBLIC_ACCESS_TOKEN is required}
uri: 'http://analytics:4000/api/logs?source_name=realtime.logs.prod'
logflare_rest:
type: 'http'
inputs:
- rest_logs
encoding:
codec: 'json'
method: 'post'
request:
retry_max_duration_secs: 30
retry_initial_backoff_secs: 1
headers:
x-api-key: ${LOGFLARE_PUBLIC_ACCESS_TOKEN?LOGFLARE_PUBLIC_ACCESS_TOKEN is required}
uri: 'http://analytics:4000/api/logs?source_name=postgREST.logs.prod'
logflare_db:
type: 'http'
inputs:
- db_logs
encoding:
codec: 'json'
method: 'post'
request:
retry_max_duration_secs: 30
retry_initial_backoff_secs: 1
headers:
x-api-key: ${LOGFLARE_PUBLIC_ACCESS_TOKEN?LOGFLARE_PUBLIC_ACCESS_TOKEN is required}
uri: 'http://analytics:4000/api/logs?source_name=postgres.logs'
logflare_functions:
type: 'http'
inputs:
- functions_logs
encoding:
codec: 'json'
method: 'post'
request:
retry_max_duration_secs: 30
retry_initial_backoff_secs: 1
headers:
x-api-key: ${LOGFLARE_PUBLIC_ACCESS_TOKEN?LOGFLARE_PUBLIC_ACCESS_TOKEN is required}
uri: 'http://analytics:4000/api/logs?source_name=deno-relay-logs'
logflare_storage:
type: 'http'
inputs:
- storage_logs
encoding:
codec: 'json'
method: 'post'
request:
retry_max_duration_secs: 30
retry_initial_backoff_secs: 1
headers:
x-api-key: ${LOGFLARE_PUBLIC_ACCESS_TOKEN?LOGFLARE_PUBLIC_ACCESS_TOKEN is required}
uri: 'http://analytics:4000/api/logs?source_name=storage.logs.prod.2'
logflare_kong:
type: 'http'
inputs:
- kong_logs
- kong_err
encoding:
codec: 'json'
method: 'post'
request:
retry_max_duration_secs: 30
retry_initial_backoff_secs: 1
headers:
x-api-key: ${LOGFLARE_PUBLIC_ACCESS_TOKEN?LOGFLARE_PUBLIC_ACCESS_TOKEN is required}
uri: 'http://analytics:4000/api/logs?source_name=cloudflare.logs.prod'
"""
[[config.mounts]]
filePath = "/volumes/pooler/pooler.exs"
content = """{:ok, _} = Application.ensure_all_started(:supavisor)
@@ -14,6 +14,9 @@ volumes:
postgres-data:
redis-data:
networks:
webapp:
services:
webapp:
image: ghcr.io/triggerdotdev/trigger.dev:${TRIGGER_IMAGE_TAG:-v3}
@@ -27,6 +30,8 @@ services:
depends_on:
- postgres
- redis
networks:
- webapp
postgres:
image: postgres:${POSTGRES_IMAGE_TAG:-16}
@@ -35,6 +40,8 @@ services:
- postgres-data:/var/lib/postgresql/data/
env_file:
- .env
networks:
- webapp
expose:
- 5432
command:
@@ -46,6 +53,8 @@ services:
restart: ${RESTART_POLICY:-unless-stopped}
volumes:
- redis-data:/data
networks:
- webapp
expose:
- 6379
docker-provider:
@@ -54,6 +63,8 @@ services:
volumes:
- /var/run/docker.sock:/var/run/docker.sock
user: root
networks:
- webapp
depends_on:
- webapp
expose:
@@ -70,6 +81,8 @@ services:
volumes:
- /var/run/docker.sock:/var/run/docker.sock
user: root
networks:
- webapp
depends_on:
- webapp
expose:
@@ -85,6 +98,8 @@ services:
restart: ${RESTART_POLICY:-unless-stopped}
environment:
DATABASE_URL: ${DATABASE_URL}?sslmode=disable
networks:
- webapp
depends_on:
- postgres
expose:
-1
View File
@@ -1,4 +1,3 @@
# dokploy: allow-host-ports — the UniFi controller serves its portal over HTTPS with a self-signed certificate on 8443 and this template defines no Traefik domain; users and UniFi devices reach the controller directly on the host.
services:
unifi-network-application:
image: lscr.io/linuxserver/unifi-network-application:latest
+2 -3
View File
@@ -1,4 +1,3 @@
# dokploy: allow-host-ports — WireGuard VPN traffic is raw UDP on 51820; Traefik cannot route it, so the port must be published on the host.
volumes:
etc_wireguard:
@@ -13,13 +12,13 @@ services:
- INIT_DNS=1.1.1.1,8.8.8.8
- PORT=51821
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"
expose:
- 51821 # web UI — routed through Traefik via the template domain
- "51821:51821/tcp"
restart: unless-stopped
cap_add:
- NET_ADMIN
-46
View File
@@ -1,46 +0,0 @@
services:
whatomate:
image: shridh0r/whatomate:0.1.1-beta-0.16.1
restart: unless-stopped
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
environment:
- TZ=Etc/UTC
volumes:
- ../files/config.toml:/app/config.toml:ro
- whatomate-uploads:/app/uploads
command: ["server", "-migrate", "-config", "/app/config.toml"]
db:
image: postgres:17-alpine
restart: unless-stopped
environment:
- POSTGRES_USER=whatomate
- POSTGRES_PASSWORD=whatomate
- POSTGRES_DB=whatomate
healthcheck:
test: ["CMD-SHELL", "pg_isready -U whatomate -d whatomate"]
interval: 10s
timeout: 5s
retries: 6
volumes:
- whatomate-postgres-data:/var/lib/postgresql/data
redis:
image: redis:7-alpine
restart: unless-stopped
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
volumes:
- whatomate-redis-data:/data
volumes:
whatomate-uploads:
whatomate-postgres-data:
whatomate-redis-data:
-14
View File
@@ -1,14 +0,0 @@
# Whatomate
## Getting started
1. Deploy the template and open the app domain.
2. Log in with the default admin credentials: **admin@admin.com** / **admin**. Change the password right after the first login.
3. Connect your WhatsApp Business account: go to **Settings → WhatsApp Accounts** and add your Meta Cloud API credentials (phone number ID, access token). See the [configuration docs](https://shridarpatil.github.io/whatomate/getting-started/configuration/).
4. Point your Meta webhook to `https://<your-domain>/webhook` and use the `webhook_verify_token` from the generated `config.toml` mount (Dokploy → your service → Advanced → Mounts).
## Notes
- The full application configuration lives in the `config.toml` file mount (JWT secret, encryption key and webhook verify token are auto-generated per deployment). Edit it and redeploy to change settings.
- Uploads are persisted in the `whatomate-uploads` volume; PostgreSQL and Redis data in `whatomate-postgres-data` and `whatomate-redis-data`.
- Voice calling / IVR requires extra WebRTC configuration (UDP ports, public IP or TURN server). See the [calling docs](https://shridarpatil.github.io/whatomate/features/calling/).
-17
View File
@@ -1,17 +0,0 @@
{
"id": "whatomate",
"name": "Whatomate",
"version": "0.1.1-beta-0.16.1",
"description": "Modern, open-source WhatsApp Business Platform with real-time chat, chatbot automation, bulk campaigns, template management, and voice calling via Meta's Cloud API.",
"logo": "whatomate.svg",
"links": {
"github": "https://github.com/shridarpatil/whatomate",
"website": "https://whatomate.io/",
"docs": "https://shridarpatil.github.io/whatomate/"
},
"tags": [
"communication",
"automation",
"crm"
]
}
-67
View File
@@ -1,67 +0,0 @@
[variables]
main_domain = "${domain}"
jwt_secret = "${password:64}"
encryption_key = "${password:32}"
webhook_verify_token = "${password:32}"
[config]
[[config.domains]]
serviceName = "whatomate"
port = 8_080
host = "${main_domain}"
[[config.mounts]]
filePath = "config.toml"
content = """
[app]
name = "Whatomate"
environment = "staging"
debug = false
encryption_key = "${encryption_key}"
[server]
host = "0.0.0.0"
port = 8080
read_timeout = 30
write_timeout = 30
base_path = ""
allowed_origins = ""
[database]
host = "db"
port = 5432
user = "whatomate"
password = "whatomate"
name = "whatomate"
ssl_mode = "disable"
max_open_conns = 25
max_idle_conns = 5
conn_max_lifetime = 300
[redis]
host = "redis"
port = 6379
username = ""
password = ""
db = 0
tls = false
[jwt]
secret = "${jwt_secret}"
access_expiry_mins = 15
refresh_expiry_days = 1
[storage]
type = "local"
local_path = "./uploads"
[whatsapp]
webhook_verify_token = "${webhook_verify_token}"
api_version = "v24.0"
base_url = "https://graph.facebook.com"
[default_admin]
email = "admin@admin.com"
password = "admin"
full_name = "Admin"
"""
-5
View File
@@ -1,5 +0,0 @@
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="20" cy="20" r="18" fill="#25D366"/>
<path d="M20 8C13.373 8 8 13.373 8 20C8 22.385 8.632 24.615 9.745 26.545L8 32L13.655 30.295C15.515 31.295 17.685 31.87 20 31.87C26.627 31.87 32 26.497 32 19.87C32 13.373 26.627 8 20 8Z" fill="white"/>
<path d="M26.5 23.5C26.2 24.5 24.8 25.3 23.7 25.5C22.9 25.6 21.9 25.7 18.5 24.3C14.3 22.5 11.6 18.2 11.4 17.9C11.2 17.6 9.5 15.4 9.5 13.1C9.5 10.8 10.7 9.7 11.2 9.2C11.6 8.8 12.2 8.6 12.7 8.6C12.9 8.6 13.1 8.6 13.2 8.6C13.7 8.6 14 8.7 14.3 9.4C14.7 10.3 15.5 12.6 15.6 12.8C15.7 13 15.8 13.3 15.6 13.6C15.5 13.9 15.4 14.1 15.2 14.3C15 14.5 14.8 14.8 14.6 15C14.4 15.2 14.2 15.4 14.4 15.8C14.6 16.2 15.4 17.5 16.6 18.6C18.1 19.9 19.4 20.4 19.9 20.6C20.4 20.8 20.7 20.8 21 20.5C21.3 20.2 22 19.4 22.3 19C22.6 18.6 23 18.5 23.4 18.7C23.8 18.8 26.1 19.9 26.5 20.1C26.9 20.3 27.2 20.4 27.3 20.6C27.4 20.9 27.4 21.8 26.5 23.5Z" fill="#25D366"/>
</svg>

Before

Width:  |  Height:  |  Size: 997 B

-32
View File
@@ -1,32 +0,0 @@
services:
yuvomi:
image: ghcr.io/ulsklyc/yuvomi:1.85.0
restart: unless-stopped
environment:
NODE_ENV: production
DB_PATH: /data/yuvomi.db
BACKUP_DIR: /backups
DOCUMENT_STORAGE_LOCAL_ENABLED: ${DOCUMENT_STORAGE_LOCAL_ENABLED}
DOCUMENT_STORAGE_LOCAL_PATH: /documents
SESSION_SECURE: "true"
TRUST_PROXY: "1"
SESSION_SECRET: ${SESSION_SECRET}
volumes:
- yuvomi-data:/data
- yuvomi-backups:/backups
- yuvomi-modules:/app/modules
- yuvomi-documents:/documents
expose:
- 3000
healthcheck:
test: ["CMD", "node", "-e", "require('http').get('http://localhost:3000/health', r => process.exit(r.statusCode === 200 ? 0 : 1))"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
volumes:
yuvomi-data:
yuvomi-backups:
yuvomi-modules:
yuvomi-documents:
-19
View File
@@ -1,19 +0,0 @@
{
"id": "yuvomi",
"name": "Yuvomi",
"version": "1.85.0",
"description": "Privacy-first, self-hosted family planner. Tasks, shopping, meals, calendar sync, budget — one private home for everything your household runs on. No cloud, no subscriptions.",
"logo": "yuvomi.svg",
"links": {
"github": "https://github.com/ulsklyc/yuvomi",
"website": "https://yuvomi.cloud/",
"docs": "https://github.com/ulsklyc/yuvomi#readme"
},
"tags": [
"open-source",
"family",
"productivity",
"calendar",
"tasks"
]
}
-17
View File
@@ -1,17 +0,0 @@
[variables]
main_domain = "${domain}"
session_secret = "${password:64}"
[config]
mounts = []
[[config.domains]]
serviceName = "yuvomi"
port = 3000
host = "${main_domain}"
[config.env]
SESSION_SECRET = "${session_secret}"
SESSION_SECURE = "true"
TRUST_PROXY = "1"
DOCUMENT_STORAGE_LOCAL_ENABLED = "false"
-20
View File
@@ -1,20 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 160" fill="none">
<defs>
<linearGradient id="bg" x1="0" y1="0" x2="160" y2="160" gradientUnits="userSpaceOnUse">
<stop offset="0%" stop-color="#8b5cf6"/>
<stop offset="100%" stop-color="#6c3aed"/>
</linearGradient>
<linearGradient id="sheen" x1="0" y1="0" x2="0" y2="160" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#ffffff" stop-opacity="0.14"/>
<stop offset="0.55" stop-color="#ffffff" stop-opacity="0"/>
</linearGradient>
</defs>
<rect width="160" height="160" rx="36" fill="url(#bg)"/>
<rect width="160" height="160" rx="36" fill="url(#sheen)"/>
<!-- Three translucent, overlapping circles (family); overlaps read as brighter lenses -->
<g fill="#ffffff" fill-opacity="0.82">
<circle cx="64" cy="72" r="27"/>
<circle cx="100" cy="78" r="25"/>
<circle cx="80" cy="106" r="24"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 933 B

+3 -15
View File
@@ -26,7 +26,6 @@ type LogLevel = "info" | "success" | "warning" | "error" | "debug";
class DockerComposeValidator {
private allowHostPorts = false;
private allowContainerNames = false;
private options: Required<DockerComposeValidatorOptions>;
private errors: string[] = [];
private warnings: string[] = [];
@@ -78,11 +77,6 @@ class DockerComposeValidator {
// Opt-out marker for templates whose protocols require host-published ports
// (mail/SMTP, game servers, streaming, VPN, remote-desktop relays...).
this.allowHostPorts = /^#\s*dokploy:\s*allow-host-ports\b/m.test(content);
// Opt-out marker for templates that functionally depend on container_name
// (e.g. legacy Supabase: Kong routes Realtime via its container DNS name and
// Vector derives log routing from container names). Only use it when the
// names are deployment-unique (e.g. include a per-deploy hash/prefix).
this.allowContainerNames = /^#\s*dokploy:\s*allow-container-names\b/m.test(content);
const compose = yaml.parse(content) as ComposeSpecification;
if (!compose || typeof compose !== "object") {
@@ -113,15 +107,9 @@ class DockerComposeValidator {
private validateNoContainerName(services: Record<string, DefinitionsService>): void {
Object.entries(services).forEach(([serviceName, service]) => {
if (service.container_name) {
if (this.allowContainerNames) {
this.warning(
`Service '${serviceName}': uses 'container_name' (allowed by '# dokploy: allow-container-names' marker)`
);
} else {
this.error(
`Service '${serviceName}': Found 'container_name' field. According to README, container_name should not be used. Dokploy manages container names automatically.`
);
}
this.error(
`Service '${serviceName}': Found 'container_name' field. According to README, container_name should not be used. Dokploy manages container names automatically.`
);
}
});
}