Sign inSign up

andelink/tailscale-split-dns:exp-with-env-ts-test

Manifest digest

sha256:1ff5fbfaf274dad5cf90ef2678c8425f4c1e2da6cc43380e7b61a780aab01ae0

Last pushed

3 months by andelink

Type

Compose

Manifest digest

sha256:1ff5fbfaf274dad5cf90ef2678c8425f4c1e2da6cc43380e7b61a780aab01ae0

Compose file content

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 commands

docker compose -f oci://andelink/tailscale-split-dns:exp-with-env-ts-test up

Use the above command to pull and run the Compose file. Learn more.

Images used

Image + 1 more

Traefik, The Cloud Native Edge Router


Pulls

1B+

Stars

3663

Last Updated

6 days

Image

Connect your devices and users together in your own secure virtual private network.


Pulls

100M+

Stars

365

Last Updated

6 days

Image


Pulls

1M+

Stars

23

Last Updated

3 days

Compose + 1 more


Pulls

1.3K

Stars

0

Last Updated

2 months