Files
technitium-console/docs/compose.shnt.example.yaml
T
DenozordecandClaude Opus 5.5 6acd2d656d Hub stage 2: install, update and uninstall apps on several servers
Writes use only <ID>_ADMIN_TOKEN and need the apps.write capability.
Store URLs are resolved from each server's own listing. The config is saved
to history before an uninstall. Zip uploads are fanned out to the servers.
Every target's result is audited. The console gets a row menu on the
matrix, a target picker, a results dialog with Retry failed, the store and
install from file in All servers mode, and single-server actions for writers.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-31 16:11:40 +07:00

222 lines
9.5 KiB
YAML

version: "3.8"
services:
traefik:
image: traefik:v3
container_name: traefik
restart: unless-stopped
command:
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--providers.docker.network=dns-net"
- "--providers.file.directory=/etc/traefik/dynamic"
- "--providers.file.watch=true"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--entrypoints.websecure.http3"
- "--entrypoints.dot.address=:853"
- "--entrypoints.doq.address=:853/udp"
- "--entrypoints.cluster.address=:53443"
- "--certificatesresolvers.myresolver.acme.dnschallenge=true"
- "--certificatesresolvers.myresolver.acme.dnschallenge.provider=cloudflare"
- "--certificatesresolvers.myresolver.acme.dnschallenge.resolvers=1.1.1.1:53,8.8.8.8:53"
- "--certificatesresolvers.myresolver.acme.dnschallenge.delaybeforecheck=60s"
- "[email protected]"
- "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"
environment:
- CF_DNS_API_TOKEN=${CF_DNS_API_TOKEN}
ports:
- target: 80
published: 80
protocol: tcp
mode: host
- target: 443
published: 443
protocol: tcp
mode: host
- target: 443
published: 443
protocol: udp
mode: host
- target: 853
published: 853
protocol: tcp
mode: host
- target: 853
published: 853
protocol: udp
mode: host
- target: 53443
published: 53443
protocol: tcp
mode: host
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./letsencrypt:/letsencrypt
- ./traefik/dynamic:/etc/traefik/dynamic:ro
networks:
- dns-net
technitium-smart:
image: technitium/dns-server:latest
container_name: technitium-smart
restart: unless-stopped
networks:
- dns-net
cap_add:
- NET_ADMIN
- NET_RAW
- NET_BIND_SERVICE
environment:
- DNS_SERVER_ADMIN_PASSWORD=${DNS_SERVER_ADMIN_PASSWORD}
- DNS_SERVER_ENABLE_DNS_OVER_HTTP=true
- DNS_SERVER_ENABLE_DNS_OVER_TLS=false
- DNS_SERVER_WEB_SERVICE_ENABLE_HTTPS=true
- DNS_SERVER_WEB_SERVICE_HTTPS_PORT=53443
- DNS_SERVER_WEB_SERVICE_USE_SELF_SIGNED_CERT=true
# Новая консоль: папку со статикой отдаёт том technitium-console (нужен Technitium 15.5+)
- DNS_SERVER_WEB_SERVICE_WWW_FOLDER_PATH=/opt/technitium-console
- TZ=Asia/Novosibirsk
- ASPNETCORE_FORWARDEDHEADERS_ENABLED=true
- DOTNET_SYSTEM_NET_SOCKETS_INLINE_RECEIVE=1
volumes:
- technitium-data:/etc/dns
- technitium-console:/opt/technitium-console:ro
# AXFR зоны кластера (TLSA). Если 53 уже слушает не этот контейнер, удалите блок.
# Файрволом пускайте TCP/53 только с IP соседних нод.
# ports:
# - target: 53
# published: 53
# protocol: tcp
# mode: host
# - target: 53
# published: 53
# protocol: udp
# mode: host
labels:
- "traefik.enable=true"
- "traefik.docker.network=dns-net"
- "traefik.http.middlewares.old-panel-headers.headers.customrequestheaders.X-Forwarded-Proto=https"
- "traefik.http.middlewares.old-panel-headers.headers.customrequestheaders.X-Forwarded-Host=old.dns.shnt.top"
# DoH
- "traefik.http.routers.doh.rule=(Host(`dns.shnt.top`) || HostRegexp(`^[a-z0-9-]+\\.dns\\.shnt\\.top$`) || Host(`ndns.shnt.top`) || HostRegexp(`^[a-z0-9-]+\\.ndns\\.shnt\\.top$`)) && PathPrefix(`/dns-query`)"
- "traefik.http.routers.doh.entrypoints=websecure"
- "traefik.http.routers.doh.tls.certresolver=myresolver"
- "traefik.http.routers.doh.tls.domains[0].main=dns.shnt.top"
- "traefik.http.routers.doh.tls.domains[0].sans=*.dns.shnt.top"
- "traefik.http.routers.doh.tls.domains[1].main=ndns.shnt.top"
- "traefik.http.routers.doh.tls.domains[1].sans=*.ndns.shnt.top"
- "traefik.http.routers.doh.priority=1000"
- "traefik.http.routers.doh.service=doh-svc"
- "traefik.http.services.doh-svc.loadbalancer.server.port=8080"
- "traefik.http.services.doh-svc.loadbalancer.server.scheme=http"
# Панель
- "traefik.http.routers.panel-old.rule=Host(`dns.shnt.top`) || Host(`old.dns.shnt.top`) || Host(`ndns.shnt.top`) || HostRegexp(`^[a-z0-9-]+\\.ndns\\.shnt\\.top$`)"
- "traefik.http.routers.panel-old.entrypoints=websecure"
- "traefik.http.routers.panel-old.tls.certresolver=myresolver"
- "traefik.http.routers.panel-old.tls.domains[0].main=dns.shnt.top"
- "traefik.http.routers.panel-old.tls.domains[0].sans=*.dns.shnt.top"
- "traefik.http.routers.panel-old.tls.domains[1].main=ndns.shnt.top"
- "traefik.http.routers.panel-old.tls.domains[1].sans=*.ndns.shnt.top"
- "traefik.http.routers.panel-old.priority=10"
- "traefik.http.routers.panel-old.middlewares=old-panel-headers"
- "traefik.http.routers.panel-old.service=panel-old-svc"
- "traefik.http.services.panel-old-svc.loadbalancer.server.port=5380"
# DoT
- "traefik.tcp.routers.dot.rule=HostSNI(`dns.shnt.top`) || HostSNIRegexp(`^.+\\.dns\\.shnt\\.top$`) || HostSNI(`ndns.shnt.top`) || HostSNIRegexp(`^.+\\.ndns\\.shnt\\.top$`)"
- "traefik.tcp.routers.dot.entrypoints=dot"
- "traefik.tcp.routers.dot.tls=true"
- "traefik.tcp.routers.dot.tls.certresolver=myresolver"
- "traefik.tcp.routers.dot.tls.domains[0].main=dns.shnt.top"
- "traefik.tcp.routers.dot.tls.domains[0].sans=*.dns.shnt.top"
- "traefik.tcp.routers.dot.tls.domains[1].main=ndns.shnt.top"
- "traefik.tcp.routers.dot.tls.domains[1].sans=*.ndns.shnt.top"
- "traefik.tcp.routers.dot.tls.options=dot@file"
- "traefik.tcp.routers.dot.service=dot-svc"
- "traefik.tcp.services.dot-svc.loadbalancer.server.port=538"
- "traefik.tcp.services.dot-svc.loadbalancer.proxyprotocol.version=2"
# DoQ
- "traefik.udp.routers.doq.entrypoints=doq"
- "traefik.udp.routers.doq.service=doq-svc"
- "traefik.udp.services.doq-svc.loadbalancer.server.port=8530"
# Кластер: TLS passthrough на Technitium :53443 (без certresolver и Proxy Protocol)
- "traefik.tcp.routers.cluster.rule=HostSNI(`ndns.shnt.top`) || HostSNIRegexp(`^.+\\.ndns\\.shnt\\.top$`) || HostSNI(`dns.shnt.top`) || HostSNIRegexp(`^.+\\.dns\\.shnt\\.top$`)"
- "traefik.tcp.routers.cluster.entrypoints=cluster"
- "traefik.tcp.routers.cluster.tls.passthrough=true"
- "traefik.tcp.routers.cluster.service=cluster-svc"
- "traefik.tcp.services.cluster-svc.loadbalancer.server.port=53443"
# Копирует новую консоль в том technitium-console и завершается.
# Без labels Traefik: наружу этот контейнер ничего не отдаёт.
# Обновление: docker compose pull technitium-console && docker compose up -d technitium-console
technitium-console:
image: git.shx.one/denozord/technitium-console:latest
container_name: technitium-console
restart: "no"
volumes:
- technitium-console:/target
networks:
- dns-net
# Хаб: одна консоль со статистикой обоих серверов на https://dnss.shnt.top
# (docs/hub-deploy.md). Только чтение. Токены и вход хаба берутся из .env:
# MDNS_TOKEN, NDNS_TOKEN (пользователь hub-reader на каждом сервере), HUB_USER, HUB_PASSWORD.
# Обновление: docker compose pull technitium-hub && docker compose up -d technitium-hub
technitium-hub:
image: git.shx.one/denozord/technitium-hub:latest
container_name: technitium-hub
restart: unless-stopped
networks:
- dns-net
volumes:
- technitium-hub-data:/data
environment:
# id=адрес по порядку; токен каждого из <ID>_TOKEN. Сервер на ЭТОМ же хосте можно
# указать изнутри сети, мимо Traefik: ndns=http://technitium-smart:5380
- HUB_SERVERS=mdns=https://mdns.shnt.top,ndns=https://ndns.shnt.top
- MDNS_TOKEN=${MDNS_TOKEN}
- NDNS_TOKEN=${NDNS_TOKEN}
# Токены hub-admin: без них хаб только читает. Нужны для установки и обновления приложений
- MDNS_ADMIN_TOKEN=${MDNS_ADMIN_TOKEN}
- NDNS_ADMIN_TOKEN=${NDNS_ADMIN_TOKEN}
# Только пока нет /data/users.json; потом пользователи создаются через users-cli (docs/hub-deploy.md)
- HUB_USER=${HUB_USER}
- HUB_PASSWORD=${HUB_PASSWORD}
- HUB_DATA=/data
# За Traefik: брать адрес клиента из X-Forwarded-For (для ограничения попыток входа и журнала)
- HUB_TRUST_PROXY=1
- HUB_DOMAIN=dnss.shnt.top
- TZ=Asia/Novosibirsk
labels:
- "traefik.enable=true"
- "traefik.docker.network=dns-net"
- "traefik.http.routers.hub.rule=Host(`dnss.shnt.top`)"
- "traefik.http.routers.hub.entrypoints=websecure"
- "traefik.http.routers.hub.tls.certresolver=myresolver"
- "traefik.http.routers.hub.service=hub-svc"
- "traefik.http.services.hub-svc.loadbalancer.server.port=8080"
networks:
dns-net:
driver: bridge
name: dns-net
volumes:
technitium-data:
technitium-console:
technitium-hub-data: