diff --git a/Readme.md b/Readme.md index 5349f12..916950e 100644 --- a/Readme.md +++ b/Readme.md @@ -4,68 +4,66 @@ DNS-over-HTTPS Client and server software to query DNS over HTTPS, using [Google DNS-over-HTTPS protocol](https://developers.google.com/speed/public-dns/docs/dns-over-https) and [IETF DNS-over-HTTPS (RFC 8484)](https://www.rfc-editor.org/rfc/rfc8484.txt). -## Guide +## Guides -[Tutorial to setup your own DNS-over-HTTPS (DoH) server](https://www.aaflalo.me/2018/10/tutorial-setup-dns-over-https-server/). (Thanks to Antoine Aflalo) +- [Tutorial: Setup your own DNS-over-HTTPS (DoH) server](https://www.aaflalo.me/2018/10/tutorial-setup-dns-over-https-server/). (Thanks to Antoine Aflalo) +- [Tutorial: Setup your own Docker based DNS-over-HTTPS (DoH) server](https://github.com/satishweb/docker-doh/blob/master/README.md). (Thanks to Satish Gaikwad) ## Installing ### From Source -Install [Go](https://golang.org), at least version 1.10. +- Install [Go](https://golang.org), at least version 1.10. +> Note for Debian/Ubuntu users: You need to set `$GOROOT` if you could not get your new version of Go selected by the Makefile.) -(Note for Debian/Ubuntu users: You need to set `$GOROOT` if you could not get your new version of Go selected by the Makefile.) - -First create an empty directory, used for `$GOPATH`: - - mkdir ~/gopath - export GOPATH=~/gopath - -To build the program, type: - - make - -To install DNS-over-HTTPS as Systemd services, type: - - sudo make install - -By default, [Google DNS over HTTPS](https://dns.google.com) is used. It should +- First create an empty directory, used for `$GOPATH`: +```bash +mkdir ~/gopath +export GOPATH=~/gopath +``` +- To build the program, type: +```bash +make +``` +- To install DNS-over-HTTPS as Systemd services, type: +```bash +sudo make install +``` +- By default, [Google DNS over HTTPS](https://dns.google.com) is used. It should work for most users (except for People's Republic of China). If you need to modify the default settings, type: +```bash +sudoedit /etc/dns-over-https/doh-client.conf +``` +- To automatically start DNS-over-HTTPS client as a system service, type: +```bash +sudo systemctl start doh-client.service +sudo systemctl enable doh-client.service +``` +- Then, modify your DNS settings (usually with NetworkManager) to 127.0.0.1. - sudoedit /etc/dns-over-https/doh-client.conf - -To automatically start DNS-over-HTTPS client as a system service, type: - - sudo systemctl start doh-client.service - sudo systemctl enable doh-client.service - -Then, modify your DNS settings (usually with NetworkManager) to 127.0.0.1. - -To test your configuration, type: - - dig www.google.com - -If it is OK, you will see: - - ;; SERVER: 127.0.0.1#53(127.0.0.1) - +- To test your configuration, type: +```bash +dig www.google.com +Output: +;; SERVER: 127.0.0.1#53(127.0.0.1) +``` #### Uninstall -To uninstall, type: - - sudo make uninstall - -The configuration files are kept at `/etc/dns-over-https`. Remove them manually if you want. +- To uninstall, type: +```bash +sudo make uninstall +``` +> Note: The configuration files are kept at `/etc/dns-over-https`. Remove them manually if you want. ### Using docker image -``` +```bash docker run -itd --name doh-server \ - -p 8053:8053 \ - -e UPSTREAM_DNS_SERVER="udp:8.8.8.8:53" \ - -e DOH_HTTP_PREFIX="/dns-query" - -e DOH_SERVER_LISTEN=":8053" - -e DOH_SERVER_TIMEOUT="10" - -e DOH_SERVER_TRIES="3" - -e DOH_SERVER_VERBOSE="false" + -p 8053:8053 \ + -e UPSTREAM_DNS_SERVER="udp:8.8.8.8:53" \ + -e DOH_HTTP_PREFIX="/dns-query" + -e DOH_SERVER_LISTEN=":8053" + -e DOH_SERVER_TIMEOUT="10" + -e DOH_SERVER_TRIES="3" + -e DOH_SERVER_VERBOSE="false" satishweb/doh-server ``` @@ -104,200 +102,186 @@ upstream_selector = "random" ``` ### Example configuration: Apache +```bash +SSLProtocol TLSv1.2 +SSLHonorCipherOrder On +SSLCipherSuite ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+3DES:!aNULL:!MD5:!DSS:!eNULL:!EXP:!LOW:!MD5 +SSLUseStapling on +SSLStaplingCache shmcb:/var/lib/apache2/stapling_cache(512000) - SSLProtocol TLSv1.2 - SSLHonorCipherOrder On - SSLCipherSuite ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+3DES:!aNULL:!MD5:!DSS:!eNULL:!EXP:!LOW:!MD5 - SSLUseStapling on - SSLStaplingCache shmcb:/var/lib/apache2/stapling_cache(512000) - - - ServerName MY_SERVER_NAME - Protocols h2 http/1.1 - ProxyPass /dns-query http://[::1]:8053/dns-query - ProxyPassReverse /dns-query http://[::1]:8053/dns-query - - + + ServerName MY_SERVER_NAME + Protocols h2 http/1.1 + ProxyPass /dns-query http://[::1]:8053/dns-query + ProxyPassReverse /dns-query http://[::1]:8053/dns-query + +``` (Credit: [Joan Moreau](https://github.com/m13253/dns-over-https/issues/51#issuecomment-526820884)) ### Example configuration: Nginx +```bash +server { + listen 443 ssl http2 default_server; + listen [::]:443 ssl http2 default_server; + server_name MY_SERVER_NAME; - server { - listen 443 ssl http2 default_server; - listen [::]:443 ssl http2 default_server; - server_name MY_SERVER_NAME; - - server_tokens off; - - ssl_protocols TLSv1.2 TLSv1.3; # TLS 1.3 requires nginx >= 1.13.0 - ssl_prefer_server_ciphers on; - ssl_dhparam /etc/nginx/dhparam.pem; # openssl dhparam -dsaparam -out /etc/nginx/dhparam.pem 4096 - ssl_ciphers EECDH+AESGCM:EDH+AESGCM; - ssl_ecdh_curve secp384r1; # Requires nginx >= 1.1.0 - ssl_session_timeout 10m; - ssl_session_cache shared:SSL:10m; - ssl_session_tickets off; # Requires nginx >= 1.5.9 - ssl_stapling on; # Requires nginx >= 1.3.7 - ssl_stapling_verify on; # Requires nginx => 1.3.7 - ssl_early_data off; # 0-RTT, enable if desired - Requires nginx >= 1.15.4 - resolver 1.1.1.1 valid=300s; # Replace with your local resolver - resolver_timeout 5s; - # HTTP Security Headers - add_header X-Frame-Options DENY; - add_header X-Content-Type-Options nosniff; - add_header X-XSS-Protection "1; mode=block"; - add_header Strict-Transport-Security "max-age=63072000"; - ssl_certificate /path/to/your/server/certificates/fullchain.pem; - ssl_certificate_key /path/to/your/server/certificates/privkey.pem; - location /dns-query { - proxy_pass http://localhost:8053/dns-query; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - } - } + server_tokens off; + ssl_protocols TLSv1.2 TLSv1.3; # TLS 1.3 requires nginx >= 1.13.0 + ssl_prefer_server_ciphers on; + ssl_dhparam /etc/nginx/dhparam.pem; # openssl dhparam -dsaparam -out /etc/nginx/dhparam.pem 4096 + ssl_ciphers EECDH+AESGCM:EDH+AESGCM; + ssl_ecdh_curve secp384r1; # Requires nginx >= 1.1.0 + ssl_session_timeout 10m; + ssl_session_cache shared:SSL:10m; + ssl_session_tickets off; # Requires nginx >= 1.5.9 + ssl_stapling on; # Requires nginx >= 1.3.7 + ssl_stapling_verify on; # Requires nginx => 1.3.7 + ssl_early_data off; # 0-RTT, enable if desired - Requires nginx >= 1.15.4 + resolver 1.1.1.1 valid=300s; # Replace with your local resolver + resolver_timeout 5s; + # HTTP Security Headers + add_header X-Frame-Options DENY; + add_header X-Content-Type-Options nosniff; + add_header X-XSS-Protection "1; mode=block"; + add_header Strict-Transport-Security "max-age=63072000"; + ssl_certificate /path/to/your/server/certificates/fullchain.pem; + ssl_certificate_key /path/to/your/server/certificates/privkey.pem; + location /dns-query { + proxy_pass http://localhost:8053/dns-query; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + } +} +``` (Credit: [Cipherli.st](https://cipherli.st/)) ### Example configuration: Caddy - - https://MY_SERVER_NAME { - log / syslog "{remote} - {user} [{when}] \"{method} {scheme}://{host}{uri} {proto}\" {status} {size} \"{>Referer}\" \"{>User-Agent}\" {>X-Forwarded-For}" - errors syslog - gzip - proxy /dns-query http://[::1]:18053 { - header_upstream Host {host} - header_upstream X-Real-IP {remote} - header_upstream X-Forwarded-For {>X-Forwarded-For},{remote} - header_upstream X-Forwarded-Proto {scheme} - } - root /var/www - tls { - ciphers ECDHE-ECDSA-WITH-CHACHA20-POLY1305 ECDHE-RSA-WITH-CHACHA20-POLY1305 ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-RSA-AES256-GCM-SHA384 ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE-RSA-AES128-GCM-SHA256 - curves X25519 p384 p521 - must_staple - } - } - -### Example configuration: Docker Flow Proxy + Docker Swarm - +```bash +https://MY_SERVER_NAME { + log / syslog "{remote} - {user} [{when}] \"{method} {scheme}://{host}{uri} {proto}\" {status} {size} \"{>Referer}\" \"{>User-Agent}\" {>X-Forwarded-For}" + errors syslog + gzip + proxy /dns-query http://[::1]:18053 { + header_upstream Host {host} + header_upstream X-Real-IP {remote} + header_upstream X-Forwarded-For {>X-Forwarded-For},{remote} + header_upstream X-Forwarded-Proto {scheme} + } + root /var/www + tls { + ciphers ECDHE-ECDSA-WITH-CHACHA20-POLY1305 ECDHE-RSA-WITH-CHACHA20-POLY1305 ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-RSA-AES256-GCM-SHA384 ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE-RSA-AES128-GCM-SHA256 + curves X25519 p384 p521 + must_staple + } +} ``` -version: '3.7' +### Example configuration: Docker Compose + Traefik + Unbound + +```yaml +version: '2.2' networks: default: - driver: overlay - attachable: true - external: false - proxy: - external: true services: - swarm-listener: - image: dockerflow/docker-flow-swarm-listener:latest - hostname: swarm-listener - init: true - networks: - - default - - proxy - volumes: - - /var/run/docker.sock:/var/run/docker.sock - environment: - - DF_NOTIFY_CREATE_SERVICE_URL=http://proxy:8080/v1/docker-flow-proxy/reconfigure - - DF_NOTIFY_REMOVE_SERVICE_URL=http://proxy:8080/v1/docker-flow-proxy/remove - deploy: - placement: - constraints: - - node.role==manager - restart_policy: - condition: any - delay: 10s - max_attempts: 99 - window: 180s - healthcheck: - test: [ "CMD", "wget", "http://localhost:8080/v1/docker-flow-swarm-listener/ping", "-O", "/dev/null" ] - interval: 2m - timeout: 1m - retries: 3 proxy: - image: dockerflow/docker-flow-proxy:latest + # The official v2 Traefik docker image + image: traefik:v2.2 hostname: proxy - init: true networks: - default - - proxy - ports: - - 80:80 - - 443:443 - volumes: - - ./data/proxy/certs:/certs environment: - TINI_SUBREAPER: 1 - LISTENER_ADDRESS: swarm-listener - MODE: swarm - COMPRESSION_ALGO: gzip - COMPRESSION_TYPE: text/css text/html text/javascript application/javascript text/plain text/xml application/json - CONNECTION_MODE: http-keep-alive - DEBUG: "true" - HTTPS_ONLY: "true" - STATS_URI: /stats - EXTRA_FRONTEND: http-request set-log-level debug,http-response set-log-level debug,capture request header User-Agent len 64,acl is_vd path -i /dns-admin,http-request redirect scheme https drop-query append-slash if is_vd,http-response set-header X-Frame-Options DENY,http-response set-header X-Content-Type-Options nosniff, - EXTRA_GLOBAL: - SSL_BIND_OPTIONS: no-sslv3 no-tls-tickets no-tlsv10 no-tlsv11 - SSL_BIND_CIPHERS: EECDH+AESGCM:EDH+AESGCM - deploy: - replicas: 1 - restart_policy: - condition: any - delay: 10s - max_attempts: 99 - window: 180s - healthcheck: - test: [ "CMD", "sh", "-c", "/usr/local/bin/check.sh"] - interval: 2m - timeout: 1m - retries: 3 - + TRAEFIK_ACCESSLOG: "true" + TRAEFIK_API: "true" + TRAEFIK_PROVIDERS_DOCKER: "true" + TRAEFIK_API_INSECURE: "true" + TRAEFIK_PROVIDERS_DOCKER_NETWORK: "${STACK}_default" + # DNS provider specific environment variables for DNS Challenge using route53 (AWS) + AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID} + AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY} + AWS_REGION: ${AWS_REGION} + AWS_HOSTED_ZONE_ID: ${AWS_HOSTED_ZONE_ID} + ports: + # The HTTP port + - "80:80" + # The HTTPS port + - "443:443" + # The Web UI (enabled by --api.insecure=true) + - "8080:8080" + command: + #- "--log.level=DEBUG" + - "--providers.docker.exposedbydefault=false" + - "--entrypoints.web.address=:80" + - "--entrypoints.websecure.address=:443" + - "--certificatesresolvers.letsencrypt.acme.dnschallenge=true" + # Providers list: + # https://docs.traefik.io/https/acme/#providers + # https://go-acme.github.io/lego/dns/ + - "--certificatesresolvers.letsencrypt.acme.dnschallenge.provider=route53" + # Enable below line to use staging letsencrypt server. + #- "--certificatesresolvers.letsencrypt.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory" + - "--certificatesresolvers.letsencrypt.acme.email=${EMAIL}" + - "--certificatesresolvers.letsencrypt.acme.storage=/certs/acme.json" + volumes: + # So that Traefik can listen to the Docker events + - /var/run/docker.sock:/var/run/docker.sock + - ./data/proxy/certs:/certs doh-server: - image: satishweb/doh-server - # Docker Image based on https://github.com/m13253/dns-over-https + image: satishweb/doh-server:latest hostname: doh-server networks: - default environment: - DEBUG: "0" - UPSTREAM_DNS_SERVER: "udp:YOUR-DNS-SERVER-IP:53" - DOH_HTTP_PREFIX: "/dns-query" - DOH_SERVER_LISTEN: ":8053" + # Enable below line to see more logs + # DEBUG: "1" + UPSTREAM_DNS_SERVER: "udp:unbound:53" + DOH_HTTP_PREFIX: "${DOH_HTTP_PREFIX}" + DOH_SERVER_LISTEN: ":${DOH_SERVER_LISTEN}" DOH_SERVER_TIMEOUT: "10" DOH_SERVER_TRIES: "3" - DOH_SERVER_VERBOSE: "true" - # You can add more variables here or as docker secret and entrypoint - # script will replace them inside doh-server.conf file - # Entrypoint script source is at https://github.com/satishweb/docker-doh - volumes: - # If you want to use your custom doh-server.conf, use below volume mount. + DOH_SERVER_VERBOSE: "false" + #volumes: # - ./doh-server.conf:/server/doh-server.conf - # Mount app-config script with your customizations # - ./app-config:/app-config - deploy: - replicas: 1 - restart_policy: - condition: any - delay: 10s - max_attempts: 99 - window: 180s - labels: - - com.df.notify=true - - com.df.distribute=true - - com.df.servicePath='/dns-query' - - com.df.port=8053 + depends_on: + - unbound + labels: + - "traefik.enable=true" + - "traefik.http.routers.doh-server.rule=Host(`${SUBDOMAIN}.${DOMAIN}`) && Path(`${DOH_HTTP_PREFIX}`)" + - "traefik.http.services.doh-server.loadbalancer.server.port=${DOH_SERVER_LISTEN}" + - "traefik.http.middlewares.mw-doh-compression.compress=true" + - "traefik.http.routers.doh-server.tls=true" + - "traefik.http.middlewares.mw-doh-tls.headers.sslredirect=true" + - "traefik.http.middlewares.mw-doh-tls.headers.sslforcehost=true" + - "traefik.http.routers.doh-server.tls.certresolver=letsencrypt" + - "traefik.http.routers.doh-server.tls.domains[0].main=${DOMAIN}" + - "traefik.http.routers.doh-server.tls.domains[0].sans=${SUBDOMAIN}.${DOMAIN}" + # Protection from requests flood + - "traefik.http.middlewares.mw-doh-ratelimit.ratelimit.average=100" + - "traefik.http.middlewares.mw-doh-ratelimit.ratelimit.burst=50" + - "traefik.http.middlewares.mw-doh-ratelimit.ratelimit.period=10s" + unbound: + image: satishweb/unbound:latest + hostname: unbound + networks: + - default + ports: + # Disable these ports if DOH server is the only client + - 53:53/tcp + - 53:53/udp + volumes: + - ./unbound.sample.conf:/templates/unbound.sample.conf + - ./data/unbound/custom:/etc/unbound/custom + # Keep your custom.hosts file inside custom folder + #environment: + # DEBUG: "1" ```` -> Above example needs you to add your chained SSL certificate in folder: ./data/proxy/certs and configure upstream DNS server address. -> Complete Docker Stack with DFProxy + Lets Encrypt SSL: https://github.com/satishweb/docker-doh - -> Docker Flow Proxy: https://github.com/docker-flow/docker-flow-proxy +> Complete Guide available at: https://github.com/satishweb/docker-doh > No IPV6 Support: Docker Swarm does not support IPV6 as of yet. Issue is logged [here](https://github.com/moby/moby/issues/24379) +> IPV6 Support for Docker Compose based configuration TBA + ## DNSSEC DNS-over-HTTPS is compatible with DNSSEC, and requests DNSSEC signatures by