Files
technitium-console/docs/compose.shnt.example.yaml
T
DenozordecandClaude Opus 5.5 042cb116ea
CI / check (push) Successful in 2m39s
Hub / check (push) Successful in 41s
CI / image (push) Successful in 2m11s
Hub / image (push) Successful in 1m48s
Hub docs: the two servers are mdns.shnt.top and ndns.shnt.top, the hub is on dnss.shnt.top
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-30 21:53:53 +07:00

212 lines
8.9 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
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_USER=${HUB_USER}
- HUB_PASSWORD=${HUB_PASSWORD}
- 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: