sha256:1ff5fbfaf274dad5cf90ef2678c8425f4c1e2da6cc43380e7b61a780aab01ae0
Last pushed
3 months by andelink
Type
Compose
Manifest digest
sha256:1ff5fbfaf274dad5cf90ef2678c8425f4c1e2da6cc43380e7b61a780aab01ae0
services:
tailscale:
restart: unless-stopped
image: tailscale/tailscale:${TS_VERSION:-stable}
hostname: ${TS_HOSTNAME:-traefik}-${SPLIT_DNS_DOMAIN:-${LOGNAME}}${TEST:+-test}
environment:
TZ: ${TZ:-America/Los_Angeles}
PUID: ${PUID:-1000}
PGID: ${PGID:-1000}
TS_ENABLE_HEALTH_CHECK: true
TS_ENABLE_METRICS: true
TS_LOCAL_ADDR_PORT: 127.0.0.1:9002
TS_HOSTNAME: ${TS_HOSTNAME:-traefik}-${SPLIT_DNS_DOMAIN:-${LOGNAME}}${TEST:+-test}
TS_STATE_DIR: ${TS_STATE_DIR:-/var/lib/tailscale}
TS_ACCEPT_DNS: true
TS_AUTH_ONCE: false
TS_USERSPACE: false
TS_NO_LOGS_NO_SUPPORT: true
TS_TAILSCALED_EXTRA_ARGS: --no-logs-no-support --verbose=2
TS_EXTRA_ARGS: --accept-dns=true --accept-routes=true --advertise-tags=${TS_ADVERTISE_TAGS:-tag:container,tag:proxy} --auth-key=file:/run/secrets/ts-client-secret
ports:
- 80:80 # traefik web
- 443:443 # traefik websecure
- 8080:8080 # traefik dashboard
- 8082:8082 # dnscrypt ui
networks:
- frontend
secrets:
- ts-client-secret
volumes:
- ts-state:${TS_STATE_DIR:-/var/lib/tailscale}
- ts-binary:/usr/local/bin
- ts-socket:/tmp
devices:
- /dev/net/tun:/dev/net/tun
cap_add:
- net_admin
- net_raw
healthcheck:
test: ["CMD", "tailscale", "wait"]
start_period: 1m
volumes:
ts-state:
ts-socket:
ts-binary:
secrets:
ts-client-secret:
environment: TS_CLIENT_SECRET
networks:
frontend:
name: frontend
driver: bridge
attachable: true
driver_opts:
com.docker.network.bridge.host_binding_ipv4: 127.0.0.1
# May consider also using this to copy default traefik and dnscrypt configs into a volume to attach
# to their respective service, which would allow consumers to more easily apply custom settings via
# their own volumes or bind mounts.
# Also consider using the tailscale API to remove devices with the same TS_HOSTNAME.
services:
dnssplit:
network_mode: service:tailscale
restart: unless-stopped
image: ghcr.io/andelink/docker-tailnet-edge:latest
pull_policy: every_1h
build:
context: bin
dockerfile: Dockerfile
# labels:
# org.opencontainers.image.version: v0.0.1
# org.opencontainers.image.authors: [email protected]
# org.opencontainers.image.vendor: Emerald Oysters
# org.opencontainers.image.title: Tailscale Split DNS Sidecar
# org.opencontainers.image.url: https://github.com/andelink/docker-tailnet-edge
# tags:
# - ghcr.io/andelink/tailscale-split-dns:0.0.1
# - ghcr.io/andelink/tailscale-split-dns:v0.0.1
# - ghcr.io/andelink/tailscale-split-dns:latest
deploy:
resources:
limits:
cpus: 0.5
memory: 16M
environment:
TS_HOSTNAME: ${TS_HOSTNAME:-traefik}-${SPLIT_DNS_DOMAIN:-${LOGNAME}}${TEST:+-test}
SPLIT_DNS_DOMAIN: ${SPLIT_DNS_DOMAIN:-${LOGNAME}}${TEST:+.test} # e.g. "home" or, if TEST=1, "home.test"
SPLIT_DNS_NAMESERVER: ${SPLIT_DNS_NAMESERVER:-} # Default will auto-detect via local API
secrets:
- ts-client-secret
- ts-client-id
volumes:
- ts-socket:/var/run/tailscale
- ts-binary:/usr/local/bin
depends_on:
tailscale:
condition: service_healthy
secrets:
ts-client-id:
environment: TS_CLIENT_ID
services:
# Downstream can supply their own config/settings with
# command: ["-config", "/path/to/mounted/config.toml"]
dnscrypt:
image: klutchell/dnscrypt-proxy:${DNSCRYPT_VERSION:-latest}
restart: unless-stopped
network_mode: service:tailscale
depends_on:
tailscale:
condition: service_healthy
healthcheck:
test: ["CMD", "dnsprobe", "google.com", "0.0.0.0:53"]
start_period: 15s
interval: 5s
environment:
TZ: ${TZ:-America/Los_Angeles}
PUID: ${PUID:-1000}
PGID: ${PGID:-1000}
TS_HOSTNAME: ${TS_HOSTNAME:-traefik}-${SPLIT_DNS_DOMAIN:-${LOGNAME}}${TEST:+-test}
volumes:
- dnscrypt-config:/config
- /etc/localtime:/etc/localtime:ro
configs:
- source: dnscrypt-config
target: /config/dnscrypt-proxy.toml
- source: dnscrypt-cloaking
target: /config/cloaking-rules.txt
- source: dnscrypt-forwarding
target: /config/forwarding-rules.txt
labels:
traefik.enable: true
traefik.hostname: dnscrypt
traefik.http.services.dnscrypt.loadbalancer.server.port: 8082
traefik.http.routers.dnscrypt.tls.domains[0].main: "${TS_HOSTNAME:-traefik}-${SPLIT_DNS_DOMAIN:-${LOGNAME}}${TEST:+-test}.${TS_DOMAIN}"
traefik.http.routers.dnscrypt.tls.domains[0].sans: "*${TS_HOSTNAME:-traefik}-${SPLIT_DNS_DOMAIN:-${LOGNAME}}${TEST:+-test}.${TS_DOMAIN}"
volumes:
dnscrypt-config:
configs:
dnscrypt-forwarding:
content: |
ts.net 100.100.100.100
dnscrypt-cloaking:
content: |
*.${SPLIT_DNS_DOMAIN:-${LOGNAME}}${TEST:+.test} ${TS_HOSTNAME:-traefik}-${SPLIT_DNS_DOMAIN:-${LOGNAME}}${TEST:+-test}.${TS_DOMAIN}
dnscrypt-config:
content: |
listen_addresses = ['0.0.0.0:53', '0.0.0.0:5053']
cloaking_rules = '/config/cloaking-rules.txt'
forwarding_rules = '/config/forwarding-rules.txt'
ipv6_servers = false
dnscrypt_servers = true
doh_servers = true
require_nolog = true
require_dnssec = true
require_nofilter = true
log_file = '/config/dnscrypt.log'
log_level = ${DNSCRYPT_LOG_LEVEL:-1} # 0 verbose - 6 fatal only
log_file_latest = false
log_files_max_backups = 3
bootstrap_resolvers = ['9.9.9.11:53', '9.9.9.9:53']
[monitoring_ui]
enabled = true
username = ''
password = ''
enable_query_log = true
listen_address = '0.0.0.0:8082'
[query_log]
format = 'tsv'
ignored_qtypes = []
file = '/config/dnscrypt.query.log'
[nx_log]
file = '/config/dnscrypt.nx.log'
[allowed_names]
log_file = '/config/dnscrypt.allowed-names.log'
# allowed_names_file = '/config/allowed-names.txt'
[allowed_ips]
log_file = '/config/dnscrypt.allowed-ips.log'
# allowed_ips_file = '/config/allowed-ips.txt'
[blocked_names]
log_file = '/config/dnscrypt.blocked-names.log'
# blocked_names_file = '/config/blocked-names.txt'
[blocked_ips]
log_file = '/config/dnscrypt.blocked-ips.log'
# blocked_ips_file = '/config/blocked-ips.txt'
[sources.'public-resolvers']
urls = ['https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/v3/public-resolvers.md', 'https://download.dnscrypt.info/resolvers-list/v3/public-resolvers.md', 'https://cdn.jsdelivr.net/gh/DNSCrypt/dnscrypt-resolvers@master/v3/public-resolvers.md']
minisign_key = 'RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3'
cache_file = 'public-resolvers.md'
services:
traefik:
image: traefik:${TRAEFIK_VERSION:-v3.7}
restart: unless-stopped
network_mode: service:tailscale
security_opt:
- no-new-privileges=true
deploy:
resources:
limits:
cpus: 0.5
memory: 256M
depends_on:
tailscale:
condition: service_healthy
healthcheck:
test: ["CMD", "traefik", "healthcheck"]
start_period: 1m
environment:
TZ: ${TZ:-America/Los_Angeles}
PUID: ${PUID:-1000}
PGID: ${PGID:-1000}
TS_DOMAIN: ${TS_DOMAIN}
TS_HOSTNAME: ${TS_HOSTNAME:-traefik}-${SPLIT_DNS_DOMAIN:-${LOGNAME}}${TEST:+-test}
SPLIT_DNS_DOMAIN: ${SPLIT_DNS_DOMAIN:-${LOGNAME}}${TEST:+.test}
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- traefik-config:/etc/traefik
- traefik-dynamic:/etc/traefik/dynamic/dynamic.d
configs:
- source: traefik-static
target: /etc/traefik/traefik.yml
- source: traefik-dynamic
target: /etc/traefik/dynamic/services.yml
labels:
traefik.enable: true
traefik.hostname: traefik
traefik.http.routers.dashboard.service: api@internal
traefik.http.services.dashboard.loadbalancer.server.port: 8080
traefik.http.routers.dashboard.tls.domains[0].main: "${TS_HOSTNAME:-traefik}-${SPLIT_DNS_DOMAIN:-${LOGNAME}}${TEST:+-test}.${TS_DOMAIN}"
traefik.http.routers.dashboard.tls.domains[0].sans: "*${TS_HOSTNAME:-traefik}-${SPLIT_DNS_DOMAIN:-${LOGNAME}}${TEST:+-test}.${TS_DOMAIN}"
volumes:
traefik-config:
traefik-dynamic:
configs:
traefik-dynamic:
content: >-
http:
middlewares:
wwwremover:
redirectRegex:
regex: ^(https?)://(?:www\.)?(.+)
replacement: $${1}://$${2}
permanent: true
traefik-static:
content: >-
ping: {}
global:
checkNewVersion: false
sendAnonymousUsage: false
log:
filePath: /etc/traefik/traefik.log.json
format: json
level: ${TRAEFIK_LOG_LEVEL:-INFO}
compress: true
maxBackups: 30
maxAge: 7
accesslog:
format: json
filepath: /etc/traefik/traefik.access.log.json
dualOutput: true
bufferingSize: 10
addInternals: true
filters:
retryAttempts: true
minDuration: 10ms
fields:
defaultMode: keep
headers:
defaultMode: keep
names:
Authorization: drop
api:
dashboard: true
insecure: ${TRAEFIK_API_INSECURE:-true}
debug: ${TRAEFIK_API_DEBUG:-false}
disableDashboardAd: true
experimental:
fastProxy: {}
certificatesResolvers:
tsresolver:
tailscale: {}
entryPoints:
web:
address: ":80"
http:
redirections:
entryPoint:
to: websecure
scheme: https
permanent: true
websecure:
address: ":443"
http:
tls:
certResolver: tsresolver
middlewares:
- wwwremover@file
providers:
# I have an http provider running on my laptop here
http:
endpoint: http://host.docker.internal:8192
pollInterval: 5s
file:
directory: /etc/traefik/dynamic
watch: true
docker:
exposedByDefault: ${TRAEFIK_PROVIDERS_DOCKER_EXPOSEDBYDEFAULT:-${TRAEFIK_EXPOSEDBYDEFAULT:-false}}
defaultRule: >-
{{ $$x := without (splitList "-" (normalize .ContainerName | trimSuffix "-1")) "app" | uniq | join "-" -}}
{{ $$y := coalesce (index .Labels "traefik.hostname") $$x -}}
Host(`{{ $$y }}.{{ env "SPLIT_DNS_DOMAIN" }}`)
|| Host(`{{ $$y }}.localhost`)
|| Host(`www.{{ $$y }}.{{ env "SPLIT_DNS_DOMAIN" }}`)
|| Host(`www.{{ $$y }}.localhost`)
|| Host(`{{ env "TS_HOSTNAME" }}`)
|| Host(`{{ env "TS_HOSTNAME" }}.localhost`)
|| Host(`{{ env "TS_HOSTNAME" }}.{{ env "TS_DOMAIN" }}`)
|| Host(`www.{{ env "TS_HOSTNAME" }}.localhost`)
|| Host(`www.{{ env "TS_HOSTNAME" }}.{{ env "TS_DOMAIN" }}`)
docker compose -f oci://andelink/tailscale-split-dns:exp-with-env-ts-test upUse the above command to pull and run the Compose file. Learn more.
Traefik, The Cloud Native Edge Router
Pulls
1B+
Stars
3663
Last Updated
6 days
Connect your devices and users together in your own secure virtual private network.
Pulls
100M+
Stars
365
Last Updated
6 days