diff --git a/Docker/Dockerfile b/Docker/Dockerfile new file mode 100644 index 000000000..59a422226 --- /dev/null +++ b/Docker/Dockerfile @@ -0,0 +1,37 @@ +FROM golang:1.14-alpine as builder + +RUN apk --update --no-cache add \ + build-base \ + git \ + && rm -rf /tmp/* /var/cache/apk/* + +WORKDIR ~ +RUN git clone https://github.com/AdguardTeam/dnsproxy + +WORKDIR dnsproxy/ + +RUN go build -mod=vendor -v + +FROM alpine:3.12 +LABEL maintainer="coolquasar@gmail.com" + +RUN apk update && \ + apk add bash supervisor certbot procps net-tools && \ + rm -rf /tmp/* /var/cache/apk/* + +COPY --from=builder /go/~/dnsproxy/dnsproxy /usr/bin + +COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf + +COPY letsencrypt-wrapper.sh /srv/ +COPY dnsproxy.sh /srv/ +COPY start.sh /srv/ + +VOLUME ["/var/log", "/etc/letsencrypt"] + +EXPOSE "80" +EXPOSE "443" +EXPOSE "784"/udp +EXPOSE "853" + +ENTRYPOINT ["/srv/start.sh"] diff --git a/Docker/README.md b/Docker/README.md new file mode 100644 index 000000000..b421ef006 --- /dev/null +++ b/Docker/README.md @@ -0,0 +1,61 @@ +## dnsproxy - Docker + +This part of the project is to run dnsproxy in docker as server or client. The docker image pulls the current dnsproxy code, builds it and creates an alpine based docker image + +Default version of docker-compose runs dnsproxy as quic server with upstream 1.1.1..1 + 1. Current version of dnsproxy docker supports `DNS-over-TLS, `DNS-over-HTTPS`, `DNSCrypt`, and `DNS-over-QUIC` + 2. Moreover, it can work as a `DNS-over-HTTPS`, `DNS-over-TLS` or `DNS-over-QUIC` server, or a simple passthrough server in a defined port + +Create the docker image +``` +# cd dnsproxy/Docker +# docker build -t dnsproxy/AdguardHome:latest $PWD +``` + +Functionalities supported by the docker image will be sub-set of the functionalities supported by dnsproxy current code + +### To start the dnsproxy as `DNS-over-TLS`, `DNS-over-HTTPS` and `DNS-over-QUIC` server +``` +# cd dnsproxy/Docker/server +# docker volume create dns_cert_keys +# docker-compose up -d +``` + +If dnsproxy server creation fails, run this command, and chances are it will be okay +``` +# docker-compose up -d --force-recreate +``` + +### To start the dnsproxy as client, with upstream to Adguard `DNS-over-TLS, `DNS-over-HTTPS` and `DNS-over-QUIC` server +``` +# cd dnsproxy/Docker/client +# docker-compose up -d +``` + +### Following changes required in server/docker-compose.yml. to start dnsproxy as `DNS-over-HTTPS` +``` +SRVPORT: "443" +MODE: "server" +PROTO: "https" +``` + +### Following changes required in server/docker-compose.yml. to start dnsproxy as `DNS-over-QUIC` +``` +SRVPORT: "784" +MODE: "server" +PROTO: "quic" +``` + +### Following changes required in server/docker-compose.yml. to start dnsproxy as `DNS-over-TLS` +``` +SRVPORT: "853" +MODE: "server" +PROTO: "tls" +``` +### Following changes required in client/docker-compose.yml. to start dnsproxy as `client` +``` +MODE: "client" +LOCALPORT: "1234" # Any local port number +``` + +Remove EDNS flag in docker-compose.yml, if EDNS support is not required diff --git a/Docker/client/docker-compose.yml b/Docker/client/docker-compose.yml new file mode 100644 index 000000000..c7e41ead0 --- /dev/null +++ b/Docker/client/docker-compose.yml @@ -0,0 +1,46 @@ +version: '3' + +services: + dnsproxy_quic_client: + image: dnsproxy/AdguardHome:latest + container_name: dnsproxy_quic_client + restart: always + environment: + UPSTREAM_ADDR: "quic://dns-unfiltered.adguard.com:784" # change it to your prefered quic server + RATELIMIT: "30" + EDNS: "ON" + LOCALPORT: "1111" # Any local port # + MODE: "client" + PROTO: "quic" + ports: + - 1112:1111/udp + dnsproxy_https_client: + image: dnsproxy/AdguardHome:latest + container_name: dnsproxy_https_client + restart: always + environment: + UPSTREAM_ADDR: "https://dns.adguard.com/dns-query" # change it to your prefered https server + RATELIMIT: "30" + EDNS: "ON" + LOCALPORT: "1111" # Any local port # + MODE: "client" + ports: + - 1113:1111/udp + dnsproxy_tls_client: + image: dnsproxy/AdguardHome:latest + container_name: dnsproxy_tls_client + restart: always + environment: + UPSTREAM_ADDR: "tls://dns.adguard.com" # change it to your prefered tls server + RATELIMIT: "30" + EDNS: "ON" + LOCALPORT: "1111" # Any local port # + MODE: "client" + ports: + - 1114:1111/udp +networks: + default: + driver: bridge + ipam: + config: + - subnet: 172.16.57.0/24 diff --git a/Docker/dnsproxy.sh b/Docker/dnsproxy.sh new file mode 100755 index 000000000..5cb0bf350 --- /dev/null +++ b/Docker/dnsproxy.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +COMMAND="dnsproxy" +LISTENADDR=$LISTEN +SRVPORT=$SRVPORT +CERTPATH=/etc/letsencrypt/live/$DOMAIN/fullchain.pem +KEYPATH=/etc/letsencrypt/live/$DOMAIN/privkey.pem +UPSTREAM=$UPSTREAM_ADDR +RATELIMIT=$RATELIMIT +EDNSFLAG=$EDNS +EDNSIP=$EDNSIP +PORT=$LOCALPORT +PROTOCOL=$PROTO + +case $PROTOCOL in + "quic") SWITCHPORT="-q $SRVPORT --tls-crt=$CERTPATH --tls-key=$KEYPATH";; + "tls") SWITCHPORT="-t $SRVPORT --tls-crt=$CERTPATH --tls-key=$KEYPATH";; + "https") SWITCHPORT="--https-port $SRVPORT --tls-crt=$CERTPATH --tls-key=$KEYPATH";; + "dnscrypt") SWITCHPORT="-y $SRVPORT --tls-crt=$CERTPATH --tls-key=$KEYPATH";; +esac + +case $MODE in + "server") LISTENSWITCH="-l $LISTENADDR"; + if [[ ! -f $CERTPATH ]] + then + echo "Waiting for letsencrypt cert to be created" + sleep 8; + fi;; + + "client") LISTENSWITCH=" "; + SWITCHPORT=" ";; +esac + +if [[ $EDNSFLAG == "" ]] +then + $COMMAND $LISTENSWITCH $SWITCHPORT -u $UPSTREAM -r $RATELIMIT -p $PORT +else + $COMMAND $LISTENSWITCH $SWITCHPORT -u $UPSTREAM -r $RATELIMIT --edns -p $PORT +fi + +#dnsproxy -l 0.0.0.0 -q 785 --tls-crt=/etc/letsencrypt/live/$DOMAIN/fullchain.pem --tls-key=/etc/letsencrypt/live/$DOMAIN/privkey.pem -u 192.168.2.1:53 -r 100 --edns -p $PORT diff --git a/Docker/letsencrypt-wrapper.sh b/Docker/letsencrypt-wrapper.sh new file mode 100755 index 000000000..425552379 --- /dev/null +++ b/Docker/letsencrypt-wrapper.sh @@ -0,0 +1,85 @@ +#!/bin/bash + +if [[ $DEBUG ]]; then + set -x +fi + +logger() { + echo "[letsencrypt] :: $(date +%x-%X) :: $@" | tee -a /var/log/letsencrypt-wrapper.log +} + +get_first_time() { + local d=$1 + if certbot certonly $DRYRUN --agree-tos --email $EMAIL \ + -n --standalone -w /etc/letsencrypt -d $d + then + logger "First certificate got for $d" + else + logger "ERROR on first time certificate for $d" + exit 2 + fi +} + +renew_certs() { + certbot renew $DRYRUN -n --standalone -w /etc/letsencrypt -d "${1}" +} + +check_env() { + if ! [[ $DOMAIN ]]; then + logger "ERROR! Missing domains to be used! Set DOMAIN environment variable." + exit 1 + fi + if ! [[ $EMAIL ]]; then + logger "ERROR! Missing email address to use to register the domain(s) certificates." + fi +} + +should_force() { + if ! [[ -f "/etc/letsencrypt/live/${1}/.doh-force" ]]; then + return 0 + fi + logger "Not skipping - found file /etc/letsencrypt/live/${1}/.doh-force" + return 1 +} + +le_vol_mounted() { + if grep "/etc/letsencrypt/live/${1}" <(mount) > /dev/null; then + logger "A letsencrypt volume is mounted for domain ${1}" + should_force $1 && return 0 + elif grep "/etc/letsencrypt" <(mount) > /dev/null; then + logger "The whole /etc/letsencrypt is mounted" + if [[ -d "/etc/letsencrypt/live/${1}" ]]; then + should_force $1 && return 0 + fi + fi + return 1 +} + +main() { + check_env + for d in $DOMAIN; do + if le_vol_mounted ${d}; then + # Assuming that if the volume is mounted from the host + # creation and renewal is in charge of others, + # except if the .doh-force file il present in the + # directory of the certificates. In such case, the container + # will take care of renewing them. + logger "Skipping domain ${1}" + continue + fi + if [[ -f /etc/letsencrypt/live/$d/privkey.pem ]]; then + logger "Renewing certificate for $d" + renew_certs $d + else + logger "Getting first time certificates for $d" + get_first_time $d + fi + done + logger "All done, sleeping for ${WAIT_TIME:-"1d"}." + sleep ${WAIT_TIME:-"1d"} +} + +while true +do + main +done diff --git a/Docker/server/docker-compose.yml b/Docker/server/docker-compose.yml new file mode 100644 index 000000000..c43c623f7 --- /dev/null +++ b/Docker/server/docker-compose.yml @@ -0,0 +1,74 @@ +version: '3' + +services: + dnsproxy_https: + image: dnsproxy/AdguardHome:latest + container_name: dnsproxy_https + restart: always + volumes: + - dns_cert_keys:/etc/letsencrypt + environment: + LISTEN: "0.0.0.0" + SRVPORT: "443" + DOMAIN: "example.org" + EMAIL: "email@example.org" + UPSTREAM_ADDR: "1.1.1.1:53" + RATELIMIT: "100" + EDNS: "ON" + LOCALPORT: "1111" # Any local port # + MODE: "server" + PROTO: "https" + ports: + - 80:80 # Port 80 is mandatory for letsencrypt to generate cert/keys successfully + - 443:443 + - 1114:1111/udp + dnsproxy_quic: + image: dnsproxy/AdguardHome:latest + container_name: dnsproxy_quic + restart: always + depends_on: + - dnsproxy_https + volumes: + - dns_cert_keys:/etc/letsencrypt + environment: + LISTEN: "0.0.0.0" + SRVPORT: "784" + DOMAIN: "jiteuhub.ddns.net" + EMAIL: "email@example.org" + UPSTREAM_ADDR: "1.1.1.1:53" + RATELIMIT: "100" + EDNS: "ON" + LOCALPORT: "1111" # Any local port # + MODE: "server" + PROTO: "quic" + ports: + - 784:784/udp + - 1112:1111/udp + dnsproxy_tls: + image: dnsproxy/AdguardHome:latest + container_name: dnsproxy_tls + restart: always + depends_on: + - dnsproxy_https + volumes: + - dns_cert_keys:/etc/letsencrypt # Uncomment this line to reuse existing cert and key + environment: + LISTEN: "0.0.0.0" + SRVPORT: "853" + DOMAIN: "jiteuhub.ddns.net" + EMAIL: "email@example.org" + UPSTREAM_ADDR: "1.1.1.1:53" + RATELIMIT: "100" + EDNS: "ON" + LOCALPORT: "1111" # Any local port # + MODE: "server" + PROTO: "tls" + ports: + - 853:853 + - 1113:1111/udp + + # Create this volume by running "docker volume create dns_cert_keys" command +volumes: + dns_cert_keys: + external: + name: dns_cert_keys diff --git a/Docker/start.sh b/Docker/start.sh new file mode 100755 index 000000000..274baf031 --- /dev/null +++ b/Docker/start.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +/usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf diff --git a/Docker/supervisord.conf b/Docker/supervisord.conf new file mode 100644 index 000000000..dbb834039 --- /dev/null +++ b/Docker/supervisord.conf @@ -0,0 +1,20 @@ +[supervisord] +nodaemon=true + +[program:letsencrypt] +command=/srv/letsencrypt-wrapper.sh +stdout_logfile=/dev/fd/1 +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/fd/2 +stderr_logfile_maxbytes=0 +username=root +autorestart=false + +[program:dnsproxy] +command=/srv/dnsproxy.sh +stdout_logfile=/dev/fd/1 +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/fd/2 +stderr_logfile_maxbytes=0 +username=root +autorestart=true