Add Pi-hole with AdGuard DOH/DOT integration, reorganize swarm stacks, add DNS/n8n docs
This commit is contained in:
@@ -9,7 +9,7 @@ volumes:
|
||||
|
||||
services:
|
||||
openwebui:
|
||||
image: ghcr.io/open-webui/open-webui:0.3.32
|
||||
image: ghcr.io/open-webui/open-webui:main
|
||||
volumes:
|
||||
- openwebui_data:/app/backend/data
|
||||
networks:
|
||||
@@ -41,15 +41,15 @@ services:
|
||||
failure_action: rollback
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.openwebui.rule=Host(`ai.sj98.duckdns.org`)"
|
||||
- "traefik.http.routers.openwebui.rule=Host(`ai.sterl.xyz`)"
|
||||
- "traefik.http.routers.openwebui.entrypoints=websecure"
|
||||
- "traefik.http.routers.openwebui.tls.certresolver=leresolver"
|
||||
- "traefik.http.routers.openwebui.tls.certresolver=cfresolver"
|
||||
- "traefik.http.services.openwebui.loadbalancer.server.port=8080"
|
||||
- "traefik.docker.network=traefik-public"
|
||||
- "traefik.swarm.network=traefik-public"
|
||||
- "tsdproxy.enable=true"
|
||||
- "tsdproxy.name=openwebui"
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
@@ -17,8 +17,7 @@ volumes:
|
||||
secrets:
|
||||
paperless_db_password:
|
||||
external: true
|
||||
paperless_secret_key:
|
||||
external: true
|
||||
|
||||
|
||||
services:
|
||||
paperless-redis:
|
||||
@@ -47,11 +46,11 @@ services:
|
||||
condition: on-failure
|
||||
delay: 5s
|
||||
max_attempts: 3
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
|
||||
paperless-db:
|
||||
image: postgres:15-alpine
|
||||
@@ -85,14 +84,14 @@ services:
|
||||
condition: on-failure
|
||||
delay: 5s
|
||||
max_attempts: 3
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
|
||||
paperless:
|
||||
image: ghcr.io/paperless-ngx/paperless-ngx:2.19.3
|
||||
image: ghcr.io/paperless-ngx/paperless-ngx:latest
|
||||
volumes:
|
||||
- paperless_data:/usr/src/paperless/data
|
||||
- paperless_media:/usr/src/paperless/media
|
||||
@@ -102,12 +101,12 @@ services:
|
||||
- PAPERLESS_DBNAME=paperless
|
||||
- PAPERLESS_DBUSER=paperless
|
||||
- PAPERLESS_DBPASS_FILE=/run/secrets/paperless_db_password
|
||||
- PAPERLESS_URL=https://paperless.sj98.duckdns.org
|
||||
- PAPERLESS_SECRET_KEY_FILE=/run/secrets/paperless_secret_key
|
||||
- PAPERLESS_URL=https://paperless.sterl.xyz
|
||||
- PAPERLESS_SECRET_KEY=e83bed4e4604e760c0429188e1781b0a8f89de936336a53609340f6b3e2182b8
|
||||
- TZ=America/Chicago
|
||||
secrets:
|
||||
- paperless_db_password
|
||||
- paperless_secret_key
|
||||
|
||||
depends_on:
|
||||
- paperless-redis
|
||||
- paperless-db
|
||||
@@ -141,21 +140,22 @@ services:
|
||||
failure_action: rollback
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.paperless.rule=Host(`paperless.sj98.duckdns.org`)"
|
||||
- "traefik.http.routers.paperless.rule=Host(`paperless.sterl.xyz`)"
|
||||
- "traefik.http.routers.paperless.entrypoints=websecure"
|
||||
- "traefik.http.routers.paperless.tls.certresolver=leresolver"
|
||||
- "traefik.http.routers.paperless.tls.certresolver=cfresolver"
|
||||
- "traefik.http.services.paperless.loadbalancer.server.port=8000"
|
||||
- "traefik.docker.network=traefik-public"
|
||||
- "traefik.swarm.network=traefik-public"
|
||||
- "tsdproxy.enable=true"
|
||||
- "tsdproxy.name=paperless"
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
- "tsdproxy.container_port=8000"
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
|
||||
stirling-pdf:
|
||||
image: frooodle/s-pdf:0.18.1
|
||||
image: stirlingtools/stirling-pdf:latest
|
||||
volumes:
|
||||
- stirling_pdf_data:/configs
|
||||
environment:
|
||||
@@ -191,25 +191,26 @@ services:
|
||||
failure_action: rollback
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.pdf.rule=Host(`pdf.sj98.duckdns.org`)"
|
||||
- "traefik.http.routers.pdf.rule=Host(`pdf.sterl.xyz`)"
|
||||
- "traefik.http.routers.pdf.entrypoints=websecure"
|
||||
- "traefik.http.routers.pdf.tls.certresolver=leresolver"
|
||||
- "traefik.http.routers.pdf.tls.certresolver=cfresolver"
|
||||
- "traefik.http.services.pdf.loadbalancer.server.port=8080"
|
||||
- "traefik.docker.network=traefik-public"
|
||||
- "traefik.swarm.network=traefik-public"
|
||||
- "tsdproxy.enable=true"
|
||||
- "tsdproxy.name=pdf"
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
- "tsdproxy.container_port=8080"
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
|
||||
searxng:
|
||||
image: searxng/searxng:2024.11.20-e9f6095cc
|
||||
image: searxng/searxng:latest
|
||||
volumes:
|
||||
- searxng_data:/etc/searxng
|
||||
environment:
|
||||
- SEARXNG_BASE_URL=https://search.sj98.duckdns.org/
|
||||
- SEARXNG_BASE_URL=https://search.sterl.xyz/
|
||||
networks:
|
||||
- traefik-public
|
||||
healthcheck:
|
||||
@@ -239,15 +240,16 @@ services:
|
||||
failure_action: rollback
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.searxng.rule=Host(`search.sj98.duckdns.org`)"
|
||||
- "traefik.http.routers.searxng.rule=Host(`search.sterl.xyz`)"
|
||||
- "traefik.http.routers.searxng.entrypoints=websecure"
|
||||
- "traefik.http.routers.searxng.tls.certresolver=leresolver"
|
||||
- "traefik.http.routers.searxng.tls.certresolver=cfresolver"
|
||||
- "traefik.http.services.searxng.loadbalancer.server.port=8080"
|
||||
- "traefik.docker.network=traefik-public"
|
||||
- "traefik.swarm.network=traefik-public"
|
||||
- "tsdproxy.enable=true"
|
||||
- "tsdproxy.name=search"
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
- "tsdproxy.container_port=8080"
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
@@ -30,11 +30,36 @@ services:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
networks:
|
||||
- traefik-public
|
||||
extra_hosts:
|
||||
- "gateway:192.168.1.1"
|
||||
- "proxmox:192.168.1.57"
|
||||
- "omv:192.168.1.70"
|
||||
- "swarm-manager:192.168.1.196"
|
||||
- "swarm-leader:192.168.1.245"
|
||||
- "swarm-worker-light:192.168.1.62"
|
||||
- "lm-studio:192.168.1.81"
|
||||
- "fedora:192.168.1.81"
|
||||
- "n8n.sj98.duckdns.org:192.168.1.196"
|
||||
environment:
|
||||
- N8N_HOST=n8n.sj98.duckdns.org
|
||||
- N8N_PROTOCOL=https
|
||||
- NODE_ENV=production
|
||||
- WEBHOOK_URL=https://n8n.sj98.duckdns.org/
|
||||
- N8N_EDITOR_BASE_URL=https://n8n.sj98.duckdns.org/
|
||||
- N8N_PUSH_BACKEND=websocket
|
||||
# Fix X-Forwarded-For validation errors (trust Traefik proxy)
|
||||
- N8N_PROXY_HOPS=1
|
||||
- N8N_SECURE_COOKIE=false
|
||||
- N8N_METRICS=false
|
||||
- N8N_SKIP_WEBHOOK_CSRF_CHECK=true
|
||||
- N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=true
|
||||
# Database configuration (fix deprecation warning)
|
||||
- DB_SQLITE_POOL_SIZE=10
|
||||
# Task runners (fix deprecation warning)
|
||||
- N8N_RUNNERS_ENABLED=true
|
||||
# Security settings (fix deprecation warnings)
|
||||
- N8N_BLOCK_ENV_ACCESS_IN_NODE=false
|
||||
- N8N_GIT_NODE_DISABLE_BARE_REPOS=true
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "wget -q --spider http://localhost:5678/healthz || exit 1"]
|
||||
interval: 30s
|
||||
@@ -46,11 +71,11 @@ services:
|
||||
- node.role == manager
|
||||
resources:
|
||||
limits:
|
||||
memory: 1G
|
||||
cpus: '0.5'
|
||||
memory: 4G
|
||||
cpus: '2.0'
|
||||
reservations:
|
||||
memory: 256M
|
||||
cpus: '0.1'
|
||||
memory: 512M
|
||||
cpus: '0.5'
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
delay: 5s
|
||||
@@ -61,7 +86,10 @@ services:
|
||||
- "traefik.http.routers.n8n.entrypoints=websecure"
|
||||
- "traefik.http.routers.n8n.tls.certresolver=leresolver"
|
||||
- "traefik.http.services.n8n.loadbalancer.server.port=5678"
|
||||
- "traefik.docker.network=traefik-public"
|
||||
- "traefik.http.services.n8n.loadbalancer.sticky.cookie=true"
|
||||
- "traefik.http.services.n8n.loadbalancer.sticky.cookie.name=n8n_sticky"
|
||||
- "traefik.http.services.n8n.loadbalancer.sticky.cookie.secure=true"
|
||||
- "traefik.swarm.network=traefik-public"
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
@@ -105,7 +133,7 @@ services:
|
||||
- "traefik.http.routers.openwebui.entrypoints=websecure"
|
||||
- "traefik.http.routers.openwebui.tls.certresolver=leresolver"
|
||||
- "traefik.http.services.openwebui.loadbalancer.server.port=8080"
|
||||
- "traefik.docker.network=traefik-public"
|
||||
- "traefik.swarm.network=traefik-public"
|
||||
- "tsdproxy.enable=true"
|
||||
- "tsdproxy.name=openwebui"
|
||||
logging:
|
||||
@@ -238,7 +266,7 @@ services:
|
||||
- "traefik.http.routers.paperless.entrypoints=websecure"
|
||||
- "traefik.http.routers.paperless.tls.certresolver=leresolver"
|
||||
- "traefik.http.services.paperless.loadbalancer.server.port=8000"
|
||||
- "traefik.docker.network=traefik-public"
|
||||
- "traefik.swarm.network=traefik-public"
|
||||
- "tsdproxy.enable=true"
|
||||
- "tsdproxy.name=paperless"
|
||||
logging:
|
||||
@@ -288,7 +316,7 @@ services:
|
||||
- "traefik.http.routers.pdf.entrypoints=websecure"
|
||||
- "traefik.http.routers.pdf.tls.certresolver=leresolver"
|
||||
- "traefik.http.services.pdf.loadbalancer.server.port=8080"
|
||||
- "traefik.docker.network=traefik-public"
|
||||
- "traefik.swarm.network=traefik-public"
|
||||
- "tsdproxy.enable=true"
|
||||
- "tsdproxy.name=pdf"
|
||||
logging:
|
||||
@@ -336,7 +364,7 @@ services:
|
||||
- "traefik.http.routers.searxng.entrypoints=websecure"
|
||||
- "traefik.http.routers.searxng.tls.certresolver=leresolver"
|
||||
- "traefik.http.services.searxng.loadbalancer.server.port=8080"
|
||||
- "traefik.docker.network=traefik-public"
|
||||
- "traefik.swarm.network=traefik-public"
|
||||
- "tsdproxy.enable=true"
|
||||
- "tsdproxy.name=search"
|
||||
logging:
|
||||
@@ -399,7 +427,7 @@ services:
|
||||
- "traefik.http.routers.tsdproxy.entrypoints=websecure"
|
||||
- "traefik.http.routers.tsdproxy.tls.certresolver=leresolver"
|
||||
- "traefik.http.services.tsdproxy.loadbalancer.server.port=8080"
|
||||
- "traefik.docker.network=traefik-public"
|
||||
- "traefik.swarm.network=traefik-public"
|
||||
- "tsdproxy.enable=true"
|
||||
- "tsdproxy.name=tsdproxy"
|
||||
logging:
|
||||
@@ -7,11 +7,22 @@ networks:
|
||||
volumes:
|
||||
tsdproxydata:
|
||||
|
||||
configs:
|
||||
tsdproxy-config:
|
||||
external: true
|
||||
name: tsdproxy.yaml
|
||||
|
||||
services:
|
||||
tsdproxy:
|
||||
image: almeidapaulopt/tsdproxy:latest
|
||||
image: almeidapaulopt/tsdproxy:1.1.0
|
||||
configs:
|
||||
- source: tsdproxy-config
|
||||
target: /config/tsdproxy.yaml
|
||||
uid: "0"
|
||||
gid: "0"
|
||||
mode: 0444
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
- tsdproxydata:/data
|
||||
environment:
|
||||
- TSDPROXY_AUTHKEY=${TSDPROXY_AUTHKEY}
|
||||
@@ -26,7 +37,7 @@ services:
|
||||
- node.role == manager
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.tsdproxy.rule=Host(`proxy.sj98.duckdns.org`)"
|
||||
- "traefik.http.routers.tsdproxy.rule=Host(`proxy.sterl.xyz`)"
|
||||
- "traefik.http.routers.tsdproxy.entrypoints=websecure"
|
||||
- "traefik.http.routers.tsdproxy.tls.certresolver=leresolver"
|
||||
- "traefik.http.routers.tsdproxy.tls.certresolver=cfresolver"
|
||||
- "traefik.http.services.tsdproxy.loadbalancer.server.port=8080"
|
||||
@@ -68,11 +68,11 @@ services:
|
||||
max_attempts: 3
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.komodo.rule=Host(`komodo.sj98.duckdns.org`)"
|
||||
- "traefik.http.routers.komodo.rule=Host(`komodo.sterl.xyz`)"
|
||||
- "traefik.http.routers.komodo.entrypoints=websecure"
|
||||
- "traefik.http.routers.komodo.tls.certresolver=leresolver"
|
||||
- "traefik.http.routers.komodo.tls.certresolver=cfresolver"
|
||||
- "traefik.http.services.komodo.loadbalancer.server.port=9120"
|
||||
- "traefik.docker.network=traefik-public"
|
||||
- "traefik.swarm.network=traefik-public"
|
||||
- "tsdproxy.enable=true"
|
||||
- "tsdproxy.name=komodo"
|
||||
logging:
|
||||
@@ -156,11 +156,11 @@ services:
|
||||
max_attempts: 3
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.tsdproxy.rule=Host(`tsdproxy.sj98.duckdns.org`)"
|
||||
- "traefik.http.routers.tsdproxy.rule=Host(`tsdproxy.sterl.xyz`)"
|
||||
- "traefik.http.routers.tsdproxy.entrypoints=websecure"
|
||||
- "traefik.http.routers.tsdproxy.tls.certresolver=leresolver"
|
||||
- "traefik.http.routers.tsdproxy.tls.certresolver=cfresolver"
|
||||
- "traefik.http.services.tsdproxy.loadbalancer.server.port=8080"
|
||||
- "traefik.docker.network=traefik-public"
|
||||
- "traefik.swarm.network=traefik-public"
|
||||
- "tsdproxy.enable=true"
|
||||
- "tsdproxy.name=tsdproxy"
|
||||
logging:
|
||||
@@ -5,6 +5,7 @@ networks:
|
||||
external: true
|
||||
media-backend:
|
||||
driver: overlay
|
||||
attachable: true
|
||||
|
||||
volumes:
|
||||
plex_config:
|
||||
@@ -16,8 +17,12 @@ volumes:
|
||||
homarr_config:
|
||||
|
||||
services:
|
||||
|
||||
############################################
|
||||
# HOMARR
|
||||
############################################
|
||||
homarr:
|
||||
image: ghcr.io/homarr-labs/homarr:1.43.0
|
||||
image: ghcr.io/ajnart/homarr:latest
|
||||
networks:
|
||||
- traefik-public
|
||||
- media-backend
|
||||
@@ -29,26 +34,28 @@ services:
|
||||
deploy:
|
||||
placement:
|
||||
constraints:
|
||||
- node.labels.leader == true
|
||||
- node.role == manager
|
||||
- node.labels.leader == true
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.homarr-router.rule=Host(`homarr.sj98.duckdns.org`)"
|
||||
- "traefik.http.routers.homarr-router.entrypoints=websecure"
|
||||
- "traefik.http.routers.homarr-router.tls.certresolver=leresolver"
|
||||
- "traefik.http.services.homarr.loadbalancer.server.port=7575"
|
||||
- "traefik.docker.network=traefik-public"
|
||||
resources:
|
||||
limits:
|
||||
memory: 512M
|
||||
cpus: '1.0'
|
||||
reservations:
|
||||
memory: 128M
|
||||
cpus: '0.2'
|
||||
- "traefik.swarm.network=traefik-public"
|
||||
|
||||
- "traefik.http.routers.homarr.rule=Host(`homarr.sterl.xyz`)"
|
||||
- "traefik.http.routers.homarr.entrypoints=websecure"
|
||||
- "traefik.http.routers.homarr.tls.certresolver=cfresolver"
|
||||
|
||||
- "traefik.http.services.homarr-svc.loadbalancer.server.port=7575"
|
||||
- "tsdproxy.enable=true"
|
||||
- "tsdproxy.name=homarr"
|
||||
- "tsdproxy.container_port=7575"
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
max_attempts: 3
|
||||
|
||||
|
||||
############################################
|
||||
# PLEX
|
||||
############################################
|
||||
plex:
|
||||
image: plexinc/pms-docker:latest
|
||||
hostname: plex
|
||||
@@ -60,7 +67,7 @@ services:
|
||||
- /mnt/media:/media:ro
|
||||
environment:
|
||||
- TZ=America/Chicago
|
||||
- PLEX_CLAIM=${PLEX_CLAIM}
|
||||
- PLEX_CLAIM=claim-xxxxxxxxxxxx
|
||||
- ADVERTISE_IP=http://192.168.1.196:32400/
|
||||
deploy:
|
||||
placement:
|
||||
@@ -68,22 +75,24 @@ services:
|
||||
- node.role == manager
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.plex-router.rule=Host(`plex.sj98.duckdns.org`)"
|
||||
- "traefik.http.routers.plex-router.entrypoints=websecure"
|
||||
- "traefik.http.routers.plex-router.tls.certresolver=leresolver"
|
||||
- "traefik.http.services.plex.loadbalancer.server.port=32400"
|
||||
- "traefik.docker.network=traefik-public"
|
||||
resources:
|
||||
limits:
|
||||
memory: 1G
|
||||
cpus: '2.0'
|
||||
reservations:
|
||||
memory: 512M
|
||||
cpus: '0.5'
|
||||
- "traefik.swarm.network=traefik-public"
|
||||
|
||||
- "traefik.http.routers.plex.rule=Host(`plex.sterl.xyz`)"
|
||||
- "traefik.http.routers.plex.entrypoints=websecure"
|
||||
- "traefik.http.routers.plex.tls.certresolver=cfresolver"
|
||||
|
||||
- "traefik.http.services.plex-svc.loadbalancer.server.port=32400"
|
||||
- "tsdproxy.enable=true"
|
||||
- "tsdproxy.name=plex"
|
||||
- "tsdproxy.container_port=32400"
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
max_attempts: 3
|
||||
|
||||
|
||||
############################################
|
||||
# JELLYFIN
|
||||
############################################
|
||||
jellyfin:
|
||||
image: jellyfin/jellyfin:latest
|
||||
networks:
|
||||
@@ -100,22 +109,24 @@ services:
|
||||
- node.role == manager
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.jellyfin-router.rule=Host(`jellyfin.sj98.duckdns.org`)"
|
||||
- "traefik.http.routers.jellyfin-router.entrypoints=websecure"
|
||||
- "traefik.http.routers.jellyfin-router.tls.certresolver=leresolver"
|
||||
- "traefik.http.services.jellyfin.loadbalancer.server.port=8096"
|
||||
- "traefik.docker.network=traefik-public"
|
||||
resources:
|
||||
limits:
|
||||
memory: 1G
|
||||
cpus: '2.0'
|
||||
reservations:
|
||||
memory: 512M
|
||||
cpus: '0.5'
|
||||
- "traefik.swarm.network=traefik-public"
|
||||
|
||||
- "traefik.http.routers.jellyfin.rule=Host(`jellyfin.sterl.xyz`)"
|
||||
- "traefik.http.routers.jellyfin.entrypoints=websecure"
|
||||
- "traefik.http.routers.jellyfin.tls.certresolver=cfresolver"
|
||||
|
||||
- "traefik.http.services.jellyfin-svc.loadbalancer.server.port=8096"
|
||||
- "tsdproxy.enable=true"
|
||||
- "tsdproxy.name=jellyfin"
|
||||
- "tsdproxy.container_port=8096"
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
max_attempts: 3
|
||||
|
||||
|
||||
############################################
|
||||
# IMMICH SERVER
|
||||
############################################
|
||||
immich-server:
|
||||
image: ghcr.io/immich-app/immich-server:release
|
||||
networks:
|
||||
@@ -142,26 +153,27 @@ services:
|
||||
- node.role == manager
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.immich-server-router.rule=Host(`immich.sj98.duckdns.org`)"
|
||||
- "traefik.http.routers.immich-server-router.entrypoints=websecure"
|
||||
- "traefik.http.routers.immich-server-router.tls.certresolver=leresolver"
|
||||
- "traefik.http.services.immich-server.loadbalancer.server.port=2283"
|
||||
- "traefik.docker.network=traefik-public"
|
||||
# Immich-specific headers and settings
|
||||
- "traefik.http.routers.immich-server-router.middlewares=immich-headers"
|
||||
- "traefik.swarm.network=traefik-public"
|
||||
|
||||
- "traefik.http.routers.immich.rule=Host(`immich.sterl.xyz`)"
|
||||
- "traefik.http.routers.immich.entrypoints=websecure"
|
||||
- "traefik.http.routers.immich.tls.certresolver=cfresolver"
|
||||
|
||||
- "traefik.http.services.immich-svc.loadbalancer.server.port=2283"
|
||||
- "tsdproxy.enable=true"
|
||||
- "tsdproxy.name=immich"
|
||||
- "tsdproxy.container_port=2283"
|
||||
- "traefik.http.routers.immich.middlewares=immich-headers"
|
||||
- "traefik.http.middlewares.immich-headers.headers.customrequestheaders.X-Forwarded-Proto=https"
|
||||
- "traefik.http.services.immich-server.loadbalancer.passhostheader=true"
|
||||
resources:
|
||||
limits:
|
||||
memory: 2G
|
||||
cpus: '2.0'
|
||||
reservations:
|
||||
memory: 1G
|
||||
cpus: '0.5'
|
||||
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
max_attempts: 3
|
||||
|
||||
|
||||
############################################
|
||||
# IMMICH MACHINE LEARNING
|
||||
############################################
|
||||
immich-machine-learning:
|
||||
image: ghcr.io/immich-app/immich-machine-learning:release
|
||||
networks:
|
||||
@@ -175,19 +187,16 @@ services:
|
||||
deploy:
|
||||
placement:
|
||||
constraints:
|
||||
- node.labels.heavy == true
|
||||
- node.labels.ai == true
|
||||
resources:
|
||||
limits:
|
||||
memory: 4G
|
||||
cpus: '4.0'
|
||||
reservations:
|
||||
memory: 2G
|
||||
cpus: '2.0'
|
||||
- node.labels.heavy == true
|
||||
- node.labels.ai == true
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
max_attempts: 3
|
||||
|
||||
|
||||
############################################
|
||||
# IMMICH REDIS
|
||||
############################################
|
||||
immich-redis:
|
||||
image: redis:7-alpine
|
||||
networks:
|
||||
@@ -198,17 +207,14 @@ services:
|
||||
placement:
|
||||
constraints:
|
||||
- node.role == manager
|
||||
resources:
|
||||
limits:
|
||||
memory: 256M
|
||||
cpus: '0.5'
|
||||
reservations:
|
||||
memory: 64M
|
||||
cpus: '0.1'
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
max_attempts: 3
|
||||
|
||||
|
||||
############################################
|
||||
# IMMICH DATABASE
|
||||
############################################
|
||||
immich-db:
|
||||
image: tensorchord/pgvecto-rs:pg14-v0.2.0
|
||||
networks:
|
||||
@@ -223,13 +229,6 @@ services:
|
||||
placement:
|
||||
constraints:
|
||||
- node.role == manager
|
||||
resources:
|
||||
limits:
|
||||
memory: 512M
|
||||
cpus: '1.0'
|
||||
reservations:
|
||||
memory: 256M
|
||||
cpus: '0.25'
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
max_attempts: 3
|
||||
14
services/swarm/stacks/monitoring/alertmanager.yml
Normal file
14
services/swarm/stacks/monitoring/alertmanager.yml
Normal file
@@ -0,0 +1,14 @@
|
||||
global:
|
||||
resolve_timeout: 5m
|
||||
|
||||
route:
|
||||
group_by: ['alertname']
|
||||
group_wait: 10s
|
||||
group_interval: 10s
|
||||
repeat_interval: 1h
|
||||
receiver: 'web.hook'
|
||||
|
||||
receivers:
|
||||
- name: 'web.hook'
|
||||
webhook_configs:
|
||||
- url: 'http://127.0.0.1:5001/'
|
||||
@@ -19,10 +19,13 @@ configs:
|
||||
prometheus_config:
|
||||
external: true
|
||||
name: prometheus.yml
|
||||
alertmanager_config:
|
||||
external: true
|
||||
name: alertmanager.yml
|
||||
|
||||
services:
|
||||
prometheus:
|
||||
image: prom/prometheus:v3.0.1
|
||||
image: prom/prometheus:latest
|
||||
volumes:
|
||||
- prometheus_data:/prometheus
|
||||
configs:
|
||||
@@ -58,23 +61,26 @@ services:
|
||||
failure_action: rollback
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.prometheus.rule=Host(`prometheus.sj98.duckdns.org`)"
|
||||
- "traefik.http.routers.prometheus.rule=Host(`prometheus.sterl.xyz`)"
|
||||
- "traefik.http.routers.prometheus.entrypoints=websecure"
|
||||
- "traefik.http.routers.prometheus.tls.certresolver=leresolver"
|
||||
- "traefik.http.routers.prometheus.tls.certresolver=cfresolver"
|
||||
- "traefik.http.services.prometheus.loadbalancer.server.port=9090"
|
||||
- "traefik.docker.network=traefik-public"
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
- "traefik.swarm.network=traefik-public"
|
||||
- "tsdproxy.enable=true"
|
||||
- "tsdproxy.name=prometheus"
|
||||
- "tsdproxy.container_port=9090"
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
|
||||
grafana:
|
||||
image: grafana/grafana:11.3.1
|
||||
image: grafana/grafana:latest
|
||||
volumes:
|
||||
- grafana_data:/var/lib/grafana
|
||||
environment:
|
||||
- GF_SERVER_ROOT_URL=https://grafana.sj98.duckdns.org
|
||||
- GF_SERVER_ROOT_URL=https://grafana.sterl.xyz
|
||||
- GF_SECURITY_ADMIN_PASSWORD__FILE=/run/secrets/grafana_admin_password
|
||||
secrets:
|
||||
- grafana_admin_password
|
||||
@@ -108,21 +114,27 @@ services:
|
||||
failure_action: rollback
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.grafana.rule=Host(`grafana.sj98.duckdns.org`)"
|
||||
- "traefik.http.routers.grafana.rule=Host(`grafana.sterl.xyz`)"
|
||||
- "traefik.http.routers.grafana.entrypoints=websecure"
|
||||
- "traefik.http.routers.grafana.tls.certresolver=leresolver"
|
||||
- "traefik.http.routers.grafana.tls.certresolver=cfresolver"
|
||||
- "traefik.http.services.grafana.loadbalancer.server.port=3000"
|
||||
- "traefik.docker.network=traefik-public"
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
- "traefik.swarm.network=traefik-public"
|
||||
- "tsdproxy.enable=true"
|
||||
- "tsdproxy.name=grafana"
|
||||
- "tsdproxy.container_port=3000"
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
|
||||
alertmanager:
|
||||
image: prom/alertmanager:v0.27.0
|
||||
image: prom/alertmanager:latest
|
||||
volumes:
|
||||
- alertmanager_data:/alertmanager
|
||||
configs:
|
||||
- source: alertmanager_config
|
||||
target: /etc/alertmanager/config.yml
|
||||
command:
|
||||
- '--config.file=/etc/alertmanager/config.yml'
|
||||
- '--storage.path=/alertmanager'
|
||||
@@ -152,19 +164,22 @@ services:
|
||||
max_attempts: 3
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.alertmanager.rule=Host(`alertmanager.sj98.duckdns.org`)"
|
||||
- "traefik.http.routers.alertmanager.rule=Host(`alertmanager.sterl.xyz`)"
|
||||
- "traefik.http.routers.alertmanager.entrypoints=websecure"
|
||||
- "traefik.http.routers.alertmanager.tls.certresolver=leresolver"
|
||||
- "traefik.http.routers.alertmanager.tls.certresolver=cfresolver"
|
||||
- "traefik.http.services.alertmanager.loadbalancer.server.port=9093"
|
||||
- "traefik.docker.network=traefik-public"
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
- "traefik.swarm.network=traefik-public"
|
||||
- "tsdproxy.enable=true"
|
||||
- "tsdproxy.name=alertmanager"
|
||||
- "tsdproxy.container_port=9093"
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
|
||||
node-exporter:
|
||||
image: prom/node-exporter:v1.8.2
|
||||
image: prom/node-exporter:latest
|
||||
volumes:
|
||||
- /proc:/host/proc:ro
|
||||
- /sys:/host/sys:ro
|
||||
@@ -189,14 +204,14 @@ services:
|
||||
condition: on-failure
|
||||
delay: 5s
|
||||
max_attempts: 3
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "5m"
|
||||
max-file: "2"
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "5m"
|
||||
max-file: "2"
|
||||
|
||||
cadvisor:
|
||||
image: gcr.io/cadvisor/cadvisor:v0.50.0
|
||||
image: gcr.io/cadvisor/cadvisor:latest
|
||||
volumes:
|
||||
- /:/rootfs:ro
|
||||
- /var/run:/var/run:ro
|
||||
@@ -226,8 +241,8 @@ services:
|
||||
condition: on-failure
|
||||
delay: 5s
|
||||
max_attempts: 3
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "5m"
|
||||
max-file: "2"
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "5m"
|
||||
max-file: "2"
|
||||
@@ -31,8 +31,8 @@ services:
|
||||
condition: on-failure
|
||||
delay: 5s
|
||||
max_attempts: 3
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "5m"
|
||||
max-file: "2"
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "5m"
|
||||
max-file: "2"
|
||||
@@ -1,54 +0,0 @@
|
||||
version: '3.8'
|
||||
|
||||
networks:
|
||||
traefik-public:
|
||||
external: true
|
||||
|
||||
volumes:
|
||||
n8n_data:
|
||||
|
||||
services:
|
||||
n8n:
|
||||
image: n8nio/n8n:latest
|
||||
volumes:
|
||||
- n8n_data:/home/node/.n8n
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
networks:
|
||||
- traefik-public
|
||||
environment:
|
||||
- N8N_HOST=n8n.sj98.duckdns.org
|
||||
- N8N_PROTOCOL=https
|
||||
- NODE_ENV=production
|
||||
- WEBHOOK_URL=https://n8n.sj98.duckdns.org/
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "wget -q --spider http://localhost:5678/healthz || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
deploy:
|
||||
placement:
|
||||
constraints:
|
||||
- node.role == manager
|
||||
resources:
|
||||
limits:
|
||||
memory: 1G
|
||||
cpus: '0.5'
|
||||
reservations:
|
||||
memory: 256M
|
||||
cpus: '0.1'
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
delay: 5s
|
||||
max_attempts: 3
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.n8n.rule=Host(`n8n.sj98.duckdns.org`)"
|
||||
- "traefik.http.routers.n8n.entrypoints=websecure"
|
||||
- "traefik.http.routers.n8n.tls.certresolver=leresolver"
|
||||
- "traefik.http.services.n8n.loadbalancer.server.port=5678"
|
||||
- "traefik.docker.network=traefik-public"
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
@@ -1,110 +0,0 @@
|
||||
version: '3.8'
|
||||
|
||||
networks:
|
||||
traefik-public:
|
||||
external: true
|
||||
|
||||
secrets:
|
||||
duckdns_token:
|
||||
external: true
|
||||
|
||||
volumes:
|
||||
traefik_letsencrypt:
|
||||
external: true
|
||||
|
||||
configs:
|
||||
traefik_yml:
|
||||
external: true
|
||||
name: traefik.yml
|
||||
|
||||
services:
|
||||
traefik:
|
||||
image: traefik:v3.2.3
|
||||
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
- traefik_letsencrypt:/letsencrypt
|
||||
networks:
|
||||
- traefik-public
|
||||
secrets:
|
||||
- duckdns_token
|
||||
configs:
|
||||
- source: traefik_yml
|
||||
target: /etc/traefik/traefik.yml
|
||||
healthcheck:
|
||||
test: ["CMD", "traefik", "healthcheck", "--ping"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
deploy:
|
||||
mode: replicated
|
||||
replicas: 2
|
||||
placement:
|
||||
constraints:
|
||||
- node.role == manager
|
||||
resources:
|
||||
limits:
|
||||
memory: 512M
|
||||
cpus: '0.5'
|
||||
reservations:
|
||||
memory: 128M
|
||||
cpus: '0.1'
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
delay: 5s
|
||||
max_attempts: 3
|
||||
update_config:
|
||||
parallelism: 1
|
||||
delay: 10s
|
||||
failure_action: rollback
|
||||
order: start-first
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.traefik.rule=Host(`traefik.sj98.duckdns.org`)"
|
||||
- "traefik.http.routers.traefik.entrypoints=websecure"
|
||||
- "traefik.http.routers.traefik.tls.certresolver=leresolver"
|
||||
- "traefik.http.routers.traefik.service=api@internal"
|
||||
- "traefik.http.services.traefik.loadbalancer.server.port=8080"
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
|
||||
whoami:
|
||||
image: traefik/whoami:v1.10
|
||||
networks:
|
||||
- traefik-public
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:80/health"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 64M
|
||||
cpus: '0.1'
|
||||
reservations:
|
||||
memory: 16M
|
||||
cpus: '0.01'
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
delay: 5s
|
||||
max_attempts: 3
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.whoami.rule=Host(`whoami.sj98.duckdns.org`)"
|
||||
- "traefik.http.routers.whoami.entrypoints=websecure"
|
||||
- "traefik.http.routers.whoami.tls.certresolver=leresolver"
|
||||
- "traefik.http.services.whoami.loadbalancer.server.port=80"
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "5m"
|
||||
max-file: "2"
|
||||
151
services/swarm/stacks/networking/networking-stack.yml
Normal file
151
services/swarm/stacks/networking/networking-stack.yml
Normal file
@@ -0,0 +1,151 @@
|
||||
version: '3.8'
|
||||
|
||||
networks:
|
||||
traefik-public:
|
||||
external: true
|
||||
|
||||
volumes:
|
||||
traefik_letsencrypt:
|
||||
external: true
|
||||
tsdproxydata:
|
||||
external: true
|
||||
|
||||
configs:
|
||||
traefik_dynamic:
|
||||
external: true
|
||||
tsdproxy-config:
|
||||
external: true
|
||||
name: tsdproxy.yaml
|
||||
|
||||
secrets:
|
||||
cf_api_token:
|
||||
external: true
|
||||
tsdproxy_authkey:
|
||||
external: true
|
||||
|
||||
services:
|
||||
traefik:
|
||||
image: traefik:latest
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
- traefik_letsencrypt:/letsencrypt
|
||||
networks:
|
||||
- traefik-public
|
||||
secrets:
|
||||
- cf_api_token
|
||||
environment:
|
||||
# Cloudflare API Token (with DNS edit permissions for your domain)
|
||||
- CF_DNS_API_TOKEN_FILE=/run/secrets/cf_api_token
|
||||
- CF_ZONE_API_TOKEN_FILE=/run/secrets/cf_api_token
|
||||
|
||||
# Optional: your Pi-hole DNS can stay
|
||||
dns:
|
||||
- 192.168.1.196
|
||||
- 192.168.1.245
|
||||
- 1.1.1.1
|
||||
|
||||
command:
|
||||
# Entrypoints
|
||||
- "--entrypoints.web.address=:80"
|
||||
- "--entrypoints.websecure.address=:443"
|
||||
|
||||
# SWARM Provider
|
||||
- "--providers.swarm=true"
|
||||
- "--providers.swarm.network=traefik-public"
|
||||
- "--providers.swarm.exposedbydefault=false"
|
||||
|
||||
# File Provider (Dynamic Config)
|
||||
- "--providers.file.filename=/dynamic.yml"
|
||||
- "--providers.file.watch=true"
|
||||
|
||||
# Dashboard
|
||||
- "--api.dashboard=true"
|
||||
- "--api.insecure=false"
|
||||
|
||||
# HTTP -> HTTPS
|
||||
- "--entrypoints.web.http.redirections.entrypoint.to=websecure"
|
||||
- "--entrypoints.web.http.redirections.entrypoint.scheme=https"
|
||||
|
||||
# Let's Encrypt / ACME Cloudflare DNS Challenge
|
||||
- "--certificatesresolvers.cfresolver.acme.email=sterlenjohnson6@gmail.com"
|
||||
- "--certificatesresolvers.cfresolver.acme.storage=/letsencrypt/acme.json"
|
||||
- "--certificatesresolvers.cfresolver.acme.dnschallenge=true"
|
||||
- "--certificatesresolvers.cfresolver.acme.dnschallenge.provider=cloudflare"
|
||||
|
||||
# Optional: increase delay for propagation
|
||||
- "--certificatesresolvers.cfresolver.acme.dnschallenge.propagation.delayBeforeChecks=60"
|
||||
# Logging
|
||||
- "--log.level=INFO"
|
||||
|
||||
deploy:
|
||||
placement:
|
||||
constraints:
|
||||
- node.role == manager
|
||||
labels:
|
||||
# Dashboard Router
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.traefik.rule=Host(`traefik.sterl.xyz`)"
|
||||
- "traefik.http.routers.traefik.entrypoints=websecure"
|
||||
- "traefik.http.routers.traefik.tls.certresolver=cfresolver"
|
||||
- "traefik.http.services.traefik.loadbalancer.server.port=8080"
|
||||
- "traefik.http.routers.traefik.service=api@internal"
|
||||
|
||||
whoami:
|
||||
image: traefik/whoami
|
||||
networks:
|
||||
- traefik-public
|
||||
deploy:
|
||||
labels:
|
||||
# Whoami Router
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.whoami.rule=Host(`whoami.sterl.xyz`)"
|
||||
- "traefik.http.routers.whoami.entrypoints=websecure"
|
||||
- "traefik.http.routers.whoami.tls.certresolver=cfresolver"
|
||||
- "traefik.http.services.whoami.loadbalancer.server.port=80"
|
||||
|
||||
tsdproxy:
|
||||
image: almeidapaulopt/tsdproxy:1.1.0
|
||||
networks:
|
||||
- traefik-public
|
||||
configs:
|
||||
- source: tsdproxy-config
|
||||
target: /config/tsdproxy.yaml
|
||||
uid: "0"
|
||||
gid: "0"
|
||||
mode: 0444
|
||||
secrets:
|
||||
- tsdproxy_authkey
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
- tsdproxydata:/data
|
||||
environment:
|
||||
- TSDPROXY_AUTHKEYFILE=/run/secrets/tsdproxy_authkey
|
||||
- DOCKER_HOST=unix:///var/run/docker.sock
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 20s
|
||||
deploy:
|
||||
placement:
|
||||
constraints:
|
||||
- node.labels.leader == true
|
||||
resources:
|
||||
limits:
|
||||
memory: 512M
|
||||
reservations:
|
||||
memory: 256M
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.tsdproxy.rule=Host(`tsdproxy.sterl.xyz`)"
|
||||
- "traefik.http.routers.tsdproxy.entrypoints=websecure"
|
||||
- "traefik.http.routers.tsdproxy.tls.certresolver=cfresolver"
|
||||
- "traefik.http.services.tsdproxy.loadbalancer.server.port=8080"
|
||||
- "traefik.swarm.network=traefik-public"
|
||||
- "tsdproxy.enable=true"
|
||||
- "tsdproxy.name=tsdproxy"
|
||||
1
services/swarm/stacks/networking/secrets/cf_api_token
Normal file
1
services/swarm/stacks/networking/secrets/cf_api_token
Normal file
@@ -0,0 +1 @@
|
||||
vxrT1xXkioj3Iw3D-emU0I_FcaMb-PeYs_TLiOma
|
||||
77
services/swarm/stacks/productivity/n8n-stack.yml
Normal file
77
services/swarm/stacks/productivity/n8n-stack.yml
Normal file
@@ -0,0 +1,77 @@
|
||||
version: '3.8'
|
||||
|
||||
networks:
|
||||
traefik-public:
|
||||
external: true
|
||||
|
||||
volumes:
|
||||
n8n_data:
|
||||
|
||||
services:
|
||||
n8n:
|
||||
image: n8nio/n8n:latest
|
||||
volumes:
|
||||
- n8n_data:/home/node/.n8n
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
networks:
|
||||
- traefik-public
|
||||
extra_hosts:
|
||||
- "gateway:192.168.1.1"
|
||||
- "proxmox:192.168.1.57"
|
||||
- "omv:192.168.1.70"
|
||||
- "swarm-manager:192.168.1.196"
|
||||
- "swarm-leader:192.168.1.245"
|
||||
- "swarm-worker-light:192.168.1.62"
|
||||
- "lm-studio:192.168.1.81"
|
||||
- "fedora:192.168.1.81"
|
||||
- "n8n.sterl.xyz:192.168.1.196"
|
||||
environment:
|
||||
- N8N_HOST=n8n.sterl.xyz
|
||||
- N8N_PROTOCOL=https
|
||||
- NODE_ENV=production
|
||||
- WEBHOOK_URL=https://n8n.sterl.xyz/
|
||||
- N8N_EDITOR_BASE_URL=https://n8n.sterl.xyz/
|
||||
- N8N_PUSH_BACKEND=websocket
|
||||
- N8N_PROXY_HOPS=1
|
||||
- N8N_SECURE_COOKIE=false
|
||||
- N8N_METRICS=false
|
||||
- N8N_SKIP_WEBHOOK_CSRF_CHECK=true
|
||||
- N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=true
|
||||
# Database configuration (fix deprecation warning)
|
||||
- DB_SQLITE_POOL_SIZE=10
|
||||
# Task runners (fix deprecation warning)
|
||||
- N8N_RUNNERS_ENABLED=true
|
||||
# Security settings (fix deprecation warnings)
|
||||
- N8N_BLOCK_ENV_ACCESS_IN_NODE=false
|
||||
- N8N_GIT_NODE_DISABLE_BARE_REPOS=true
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "wget -q --spider http://localhost:5678/healthz || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
deploy:
|
||||
placement:
|
||||
constraints:
|
||||
- node.role == manager
|
||||
resources:
|
||||
limits:
|
||||
memory: 4G
|
||||
cpus: '2.0'
|
||||
reservations:
|
||||
memory: 512M
|
||||
cpus: '0.5'
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
delay: 5s
|
||||
max_attempts: 3
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.n8n.rule=Host(`n8n.sterl.xyz`)"
|
||||
- "traefik.http.routers.n8n.entrypoints=websecure"
|
||||
- "traefik.http.routers.n8n.tls.certresolver=cfresolver"
|
||||
- "traefik.http.services.n8n.loadbalancer.server.port=5678"
|
||||
- "traefik.http.services.n8n.loadbalancer.sticky.cookie=true"
|
||||
- "traefik.http.services.n8n.loadbalancer.sticky.cookie.name=n8n_sticky"
|
||||
- "traefik.http.services.n8n.loadbalancer.sticky.cookie.secure=true"
|
||||
- "traefik.swarm.network=traefik-public"
|
||||
|
||||
@@ -57,7 +57,7 @@ services:
|
||||
condition: on-failure
|
||||
|
||||
nextcloud:
|
||||
image: nextcloud:30.0.8
|
||||
image: nextcloud:latest
|
||||
volumes:
|
||||
- nextcloud_data:/var/www/html
|
||||
environment:
|
||||
@@ -68,9 +68,9 @@ services:
|
||||
- REDIS_HOST=nextcloud-redis
|
||||
- NEXTCLOUD_ADMIN_USER=${NEXTCLOUD_ADMIN_USER} # Replace with your desired admin username
|
||||
- NEXTCLOUD_ADMIN_PASSWORD=${NEXTCLOUD_ADMIN_PASSWORD} # Replace with a secure password
|
||||
- NEXTCLOUD_TRUSTED_DOMAINS=nextcloud.sj98.duckdns.org
|
||||
- NEXTCLOUD_TRUSTED_DOMAINS=nextcloud.sterl.xyz
|
||||
- OVERWRITEPROTOCOL=https
|
||||
- OVERWRITEHOST=nextcloud.sj98.duckdns.org
|
||||
- OVERWRITEHOST=nextcloud.sterl.xyz
|
||||
- TRUSTED_PROXIES=172.16.0.0/12
|
||||
depends_on:
|
||||
- nextcloud-db
|
||||
@@ -91,11 +91,11 @@ services:
|
||||
condition: on-failure
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.nextcloud.rule=Host(`nextcloud.sj98.duckdns.org`)"
|
||||
- "traefik.http.routers.nextcloud.rule=Host(`nextcloud.sterl.xyz`)"
|
||||
- "traefik.http.routers.nextcloud.entrypoints=websecure"
|
||||
- "traefik.http.routers.nextcloud.tls.certresolver=leresolver"
|
||||
- "traefik.http.routers.nextcloud.tls.certresolver=cfresolver"
|
||||
- "traefik.http.services.nextcloud.loadbalancer.server.port=80"
|
||||
- "traefik.docker.network=traefik-public"
|
||||
- "traefik.swarm.network=traefik-public"
|
||||
# Nextcloud-specific middlewares
|
||||
- "traefik.http.routers.nextcloud.middlewares=nextcloud-chain"
|
||||
- "traefik.http.middlewares.nextcloud-chain.chain.middlewares=nextcloud-caldav,nextcloud-headers"
|
||||
@@ -109,4 +109,7 @@ services:
|
||||
- "traefik.http.middlewares.nextcloud-headers.headers.stsPreload=true"
|
||||
- "traefik.http.middlewares.nextcloud-headers.headers.forceSTSHeader=true"
|
||||
- "traefik.http.middlewares.nextcloud-headers.headers.customFrameOptionsValue=SAMEORIGIN"
|
||||
- "traefik.http.middlewares.nextcloud-headers.headers.customResponseHeaders.X-Robots-Tag=noindex,nofollow"
|
||||
- "traefik.http.middlewares.nextcloud-headers.headers.customResponseHeaders.X-Robots-Tag=noindex,nofollow"
|
||||
- "tsdproxy.enable=true"
|
||||
- "tsdproxy.name=nextcloud"
|
||||
- "tsdproxy.container_port=80"
|
||||
@@ -1,45 +0,0 @@
|
||||
version: '3.8'
|
||||
|
||||
networks:
|
||||
traefik-public:
|
||||
external: true
|
||||
|
||||
services:
|
||||
dozzle:
|
||||
image: amir20/dozzle:v8.14.6
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
networks:
|
||||
- traefik-public
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/healthcheck"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
deploy:
|
||||
placement:
|
||||
constraints:
|
||||
- node.role == manager
|
||||
resources:
|
||||
limits:
|
||||
memory: 256M
|
||||
cpus: '0.25'
|
||||
reservations:
|
||||
memory: 64M
|
||||
cpus: '0.05'
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
delay: 5s
|
||||
max_attempts: 3
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.dozzle.rule=Host(`dozzle.sj98.duckdns.org`)"
|
||||
- "traefik.http.routers.dozzle.entrypoints=websecure"
|
||||
- "traefik.http.routers.dozzle.tls.certresolver=leresolver"
|
||||
- "traefik.http.services.dozzle.loadbalancer.server.port=8080"
|
||||
- "traefik.docker.network=traefik-public"
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "5m"
|
||||
max-file: "2"
|
||||
@@ -33,9 +33,9 @@ services:
|
||||
- GITEA__database__NAME=gitea
|
||||
- GITEA__database__USER=gitea
|
||||
- GITEA__database__PASSWD_FILE=/run/secrets/gitea_db_password
|
||||
- GITEA__server__DOMAIN=git.sj98.duckdns.org
|
||||
- GITEA__server__ROOT_URL=https://git.sj98.duckdns.org
|
||||
- GITEA__server__SSH_DOMAIN=git.sj98.duckdns.org
|
||||
- GITEA__server__DOMAIN=git.sterl.xyz
|
||||
- GITEA__server__ROOT_URL=https://git.sterl.xyz
|
||||
- GITEA__server__SSH_DOMAIN=git.sterl.xyz
|
||||
- GITEA__server__SSH_PORT=2222
|
||||
- GITEA__service__DISABLE_REGISTRATION=false
|
||||
secrets:
|
||||
@@ -64,11 +64,14 @@ services:
|
||||
max_attempts: 3
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.gitea.rule=Host(`git.sj98.duckdns.org`)"
|
||||
- "traefik.http.routers.gitea.rule=Host(`git.sterl.xyz`)"
|
||||
- "traefik.http.routers.gitea.entrypoints=websecure"
|
||||
- "traefik.http.routers.gitea.tls.certresolver=leresolver"
|
||||
- "traefik.http.routers.gitea.tls.certresolver=cfresolver"
|
||||
- "traefik.http.services.gitea.loadbalancer.server.port=3000"
|
||||
- "traefik.docker.network=traefik-public"
|
||||
- "traefik.swarm.network=traefik-public"
|
||||
- "tsdproxy.enable=true"
|
||||
- "tsdproxy.name=gitea"
|
||||
- "tsdproxy.container_port=3000"
|
||||
|
||||
gitea-db:
|
||||
image: postgres:15-alpine
|
||||
@@ -12,8 +12,11 @@ volumes:
|
||||
|
||||
services:
|
||||
portainer:
|
||||
image: portainer/portainer-ce:2.21.4
|
||||
command: -H tcp://tasks.agent:9001 --tlsskipverify
|
||||
image: portainer/portainer-ce:latest
|
||||
command:
|
||||
- "-H"
|
||||
- "tcp://tasks.agent:9001"
|
||||
- "--tlsskipverify"
|
||||
ports:
|
||||
- "9000:9000"
|
||||
- "9443:9443"
|
||||
@@ -51,20 +54,27 @@ services:
|
||||
failure_action: rollback
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.portainer.rule=Host(`portainer.sj98.duckdns.org`)"
|
||||
- "traefik.http.routers.portainer.rule=Host(`portainer.sterl.xyz`)"
|
||||
- "traefik.http.routers.portainer.entrypoints=websecure"
|
||||
- "traefik.http.routers.portainer.tls.certresolver=leresolver"
|
||||
- "traefik.http.routers.portainer.tls.certresolver=cfresolver"
|
||||
- "traefik.http.routers.portainer.service=portainer"
|
||||
- "traefik.http.routers.portainer.tls=true"
|
||||
- "traefik.http.services.portainer.loadbalancer.server.port=9000"
|
||||
- "traefik.http.services.portainer.loadbalancer.sticky.cookie=true"
|
||||
- "traefik.swarm.network=traefik-public"
|
||||
- "traefik.docker.network=traefik-public"
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
- "tsdproxy.enable=true"
|
||||
- "tsdproxy.name=portainer"
|
||||
- "tsdproxy.container_port=9000"
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
|
||||
# Linux agent
|
||||
agent:
|
||||
image: portainer/agent:2.21.4
|
||||
image: portainer/agent:latest
|
||||
environment:
|
||||
AGENT_CLUSTER_ADDR: tasks.agent
|
||||
volumes:
|
||||
@@ -88,15 +98,15 @@ services:
|
||||
condition: on-failure
|
||||
delay: 5s
|
||||
max_attempts: 3
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "5m"
|
||||
max-file: "2"
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "5m"
|
||||
max-file: "2"
|
||||
|
||||
# Windows agent (optional - only deploys if Windows node exists)
|
||||
agent-windows:
|
||||
image: portainer/agent:2.21.4
|
||||
image: portainer/agent:latest
|
||||
environment:
|
||||
AGENT_CLUSTER_ADDR: tasks.agent
|
||||
volumes:
|
||||
@@ -126,8 +136,8 @@ services:
|
||||
condition: on-failure
|
||||
delay: 5s
|
||||
max_attempts: 3
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "5m"
|
||||
max-file: "2"
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "5m"
|
||||
max-file: "2"
|
||||
52
services/swarm/stacks/tools/tools-stack.yml
Normal file
52
services/swarm/stacks/tools/tools-stack.yml
Normal file
@@ -0,0 +1,52 @@
|
||||
version: '3.8'
|
||||
|
||||
networks:
|
||||
traefik-public:
|
||||
external: true
|
||||
|
||||
services:
|
||||
dozzle:
|
||||
image: amir20/dozzle:latest
|
||||
user: "0:0"
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
networks:
|
||||
- traefik-public
|
||||
environment:
|
||||
- DOZZLE_MODE=swarm
|
||||
- DOZZLE_LEVEL=debug
|
||||
- DOZZLE_NO_ANALYTICS=true
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "5m"
|
||||
max-file: "2"
|
||||
deploy:
|
||||
mode: global
|
||||
resources:
|
||||
limits:
|
||||
memory: 256M
|
||||
cpus: '0.25'
|
||||
reservations:
|
||||
memory: 64M
|
||||
cpus: '0.05'
|
||||
restart_policy:
|
||||
condition: any
|
||||
delay: 5s
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.dozzle.rule=Host(`dozzle.sterl.xyz`)"
|
||||
- "traefik.http.routers.dozzle.entrypoints=websecure"
|
||||
- "traefik.http.routers.dozzle.tls.certresolver=cfresolver"
|
||||
- "traefik.http.services.dozzle.loadbalancer.server.port=8080"
|
||||
- "traefik.swarm.network=traefik-public"
|
||||
- "tsdproxy.enable=true"
|
||||
- "tsdproxy.name=logs"
|
||||
- "tsdproxy.container_port=8080"
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "if [ -S /var/run/docker.sock ]; then exit 0; else exit 1; fi"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
|
||||
Reference in New Issue
Block a user