1
1
mirror of https://github.com/dnscrypt/dnscrypt-server-docker synced 2024-11-22 19:42:03 +01:00

Initial import

This commit is contained in:
Frank Denis 2015-07-06 01:39:54 +02:00
parent a612deb89b
commit b3f33d2b6a
8 changed files with 515 additions and 0 deletions

153
Dockerfile Normal file

@ -0,0 +1,153 @@
FROM caleblloyd/phusion-baseimage-docker-15.04
MAINTAINER Frank Denis
ENV SERIAL 1
ENV BUILD_DEPS autoconf gcc libc-dev make pkg-config git
RUN set -x && \
apt-get update && apt-get install -y \
$BUILD_DEPS \
bsdmainutils \
ldnsutils \
--no-install-recommends
ENV LIBRESSL_VERSION 2.2.0
ENV LIBRESSL_SHA256 9690d8f38a5d48425395452eeb305b05bb0f560cd96e0ee30f370d4f16563040
ENV LIBRESSL_DOWNLOAD_URL http://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-${LIBRESSL_VERSION}.tar.gz
RUN set -x && \
mkdir -p /tmp/src && \
cd /tmp/src && \
curl -sSL $LIBRESSL_DOWNLOAD_URL -o libressl.tar.gz && \
echo "${LIBRESSL_SHA256} *libressl.tar.gz" | sha256sum -c - && \
tar xzf libressl.tar.gz && \
rm -f libressl.tar.gz && \
cd libressl-${LIBRESSL_VERSION} && \
./configure --disable-dependency-tracking --prefix=/opt/libressl && \
make check && make install && \
rm -fr /opt/libressl/share/man && \
echo /opt/libressl/lib > /etc/ld.so.conf.d/libressl.conf && ldconfig && \
rm -fr /tmp/*
ENV UNBOUND_VERSION 1.5.3
ENV UNBOUND_SHA256 76bdc875ed4d1d3f8e4cfe960e6df78ee5c6c7c18abac11331cf93a7ae129eca
ENV UNBOUND_DOWNLOAD_URL http://www.unbound.net/downloads/unbound-${UNBOUND_VERSION}.tar.gz
RUN set -x && \
apt-get update && \
apt-get install -y \
libevent-2.0 \
libevent-dev \
libexpat1 \
libexpat1-dev \
--no-install-recommends && \
mkdir -p /tmp/src && \
cd /tmp/src && \
curl -sSL $UNBOUND_DOWNLOAD_URL -o unbound.tar.gz && \
echo "${UNBOUND_SHA256} *unbound.tar.gz" | sha256sum -c - && \
tar xzf unbound.tar.gz && \
rm -f unbound.tar.gz && \
cd unbound-${UNBOUND_VERSION} && \
groupadd _unbound && \
useradd -g _unbound -s /etc -d /dev/null _unbound && \
./configure --disable-dependency-tracking --prefix=/opt/unbound --with-pthreads \
--with-username=_unbound --with-ssl=/opt/libressl --with-libevent \
--enable-event-api && \
make install && \
mv /opt/unbound/etc/unbound/unbound.conf /opt/unbound/etc/unbound/unbound.conf.example && \
rm -fr /opt/unbound/share/man && \
apt-get purge -y --auto-remove \
libexpat-dev \
libevent-dev && \
apt-get autoremove -y && apt-get clean && \
rm -fr /tmp/* /var/tmp/*
ENV LIBSODIUM_VERSION 1.0.3
ENV LIBSODIUM_SHA256 cbcfc63cc90c05d18a20f229a62c7e7054a73731d0aa858c0517152c549b1288
ENV LIBSODIUM_DOWNLOAD_URL https://download.libsodium.org/libsodium/releases/libsodium-${LIBSODIUM_VERSION}.tar.gz
RUN set -x && \
mkdir -p /tmp/src && \
cd /tmp/src && \
curl -sSL $LIBSODIUM_DOWNLOAD_URL -o libsodium.tar.gz && \
echo "${LIBSODIUM_SHA256} *libsodium.tar.gz" | sha256sum -c - && \
tar xzf libsodium.tar.gz && \
rm -f libsodium.tar.gz && \
cd libsodium-${LIBSODIUM_VERSION} && \
./configure --disable-dependency-tracking --enable-minimal --prefix=/opt/libsodium && \
make check && make install && \
echo /opt/libsodium/lib > /etc/ld.so.conf.d/libsodium.conf && ldconfig && \
rm -fr /tmp/*
ENV DNSCRYPT_PROXY_VERSION 1.5.0
ENV DNSCRYPT_PROXY_SHA256 b78c52efca2e6b26c68638493c1aa7733b41106363a8f2a3bec3b8da44aafcbb
ENV DNSCRYPT_PROXY_DOWNLOAD_URL http://download.dnscrypt.org/dnscrypt-proxy/dnscrypt-proxy-${DNSCRYPT_PROXY_VERSION}.tar.gz
RUN set -x && \
mkdir -p /tmp/src && \
cd /tmp/src && \
curl -sSL $DNSCRYPT_PROXY_DOWNLOAD_URL -o dnscrypt-proxy.tar.gz && \
echo "${DNSCRYPT_PROXY_SHA256} *dnscrypt-proxy.tar.gz" | sha256sum -c - && \
tar xvf dnscrypt-proxy.tar.gz && \
rm -f dnscrypt-proxy.tar.gz && \
cd dnscrypt-proxy-${DNSCRYPT_PROXY_VERSION} && \
mkdir -p /opt/dnscrypt-proxy/empty && \
groupadd _dnscrypt-proxy && \
useradd -g _dnscrypt-proxy -s /etc -d /opt/dnscrypt-proxy/empty _dnscrypt-proxy && \
env CPPFLAGS=-I/opt/libsodium/include LDFLAGS=-L/opt/libsodium/lib \
./configure --disable-dependency-tracking --prefix=/opt/dnscrypt-proxy && \
make install && \
rm -fr /opt/dnscrypt-proxy/share && \
rm -fr /tmp/* /var/tmp/*
ENV DNSCRYPT_WRAPPER_GIT_TAG stable
ENV DNSCRYPT_WRAPPER_GIT_REMOTE_URL https://github.com/jedisct1/dnscrypt-wrapper.git
RUN set -x && \
apt-get update && \
apt-get install -y \
libevent-2.0 \
libevent-dev \
--no-install-recommends && \
mkdir -p /tmp/src && \
cd /tmp/src && \
git clone "$DNSCRYPT_WRAPPER_GIT_REMOTE_URL" dnscrypt-wrapper && \
cd dnscrypt-wrapper && \
git checkout "$DNSCRYPT_WRAPPER_GIT_TAG" && \
mkdir -p /opt/dnscrypt-wrapper/empty && \
groupadd _dnscrypt-wrapper && \
useradd -g _dnscrypt-wrapper -s /etc -d /opt/dnscrypt-wrapper/empty _dnscrypt-wrapper && \
groupadd _dnscrypt-signer && \
useradd -g _dnscrypt-signer -G _dnscrypt-wrapper -s /etc -d /dev/null _dnscrypt-signer && \
make configure && \
./configure --prefix=/opt/dnscrypt-wrapper --with-sodium=/opt/libsodium && \
make install && \
apt-get purge -y --auto-remove libevent-dev && \
apt-get autoremove -y && apt-get clean && \
rm -fr /tmp/* /var/tmp/*
RUN set -x && \
apt-get purge -y --auto-remove $BUILD_DEPS && \
apt-get autoremove -y && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
RUN mkdir -p \
/etc/service/unbound \
/etc/service/watchdog
ADD entrypoint.sh /
ADD unbound.sh /etc/service/unbound/run
ADD unbound-check.sh /etc/service/unbound/check
ADD dnscrypt-wrapper.sh /etc/service/dnscrypt-wrapper/run
ADD key-rotation.sh /etc/service/key-rotation/run
ADD watchdog.sh /etc/service/watchdog/run
VOLUME ["/opt/dnscrypt-wrapper/etc/keys"]
EXPOSE 53/udp 53/tcp 443/udp 443/tcp
CMD ["start"]
ENTRYPOINT ["/entrypoint.sh"]

83
README.md Normal file

@ -0,0 +1,83 @@
DNSCrypt server Docker image
============================
Run your own caching, non-censoring, non-logging, DNSSEC-capable,
[DNSCrypt](http://dnscrypt.org)-enabled DNS resolver virtually anywhere!
If you are already familiar with Docker, it shouldn't take more than 5 minutes
to get your resolver up and running.
Installation
============
Download the Docker image source:
$ git clone https://github.com/jedisct1/dnscrypt-server-docker.git
Build the image:
$ docker build -t dnscrypt-server-image .
Think about a name. This is going to be part of your DNSCrypt provider name.
If you are planning to make your resolver publicly accessible, this name will
be public.
It has to look like a domain name (`example.com`), but it doesn't have to be
a registered domain either.
Let's pick `example.com` here.
Create and initialize the container, once and for all:
$ docker run --name=dnscrypt-server \
-p 443:443/udp -p 443:443/tcp \
dnscrypt-server-image init -N example.com
This will only accept connections via DNSCrypt. Containers on the same virtual
network can directly access the DNS cache on the standard DNS port (53), but
to create a non-authenticated public DNS resolver, this extra port has to be
explicitly exposed (`-p 53:53/udp -p 53:53/tcp`).
Now, to start the whole stack:
$ docker start dnscrypt-server
Done.
To check that your DNSCrypt-enabled DNS resolver is accessible, run the
DNSCrypt client proxy on another host:
# dnscrypt-proxy \
--provider-key=<provider key, as displayed when the container was initialized> \
--resolver-address=<your resolver's public IP address> \
--provider-name=2.dnscrypt-cert.example.com
And try using `127.0.0.1` as a DNS resolver.
Note that the actual provider name for DNSCrypt is `2.dnscrypt-cert.example.com`,
not just `example.com` as initially entered. The full name has to start with
`2.dnscrypt-cert.` for the client and the server to use the same version of the
protocol.
Let the world know about your server
====================================
Is your brand new DNS resolver publicly accessible?
Fork the [dnscrypt-proxy repository](https://github.com/jedisct1/dnscrypt-proxy),
edit the [dnscrypt.csv](https://github.com/jedisct1/dnscrypt-proxy/blob/master/dnscrypt-resolvers.csv)
file to add your resolver's informations, and submit a pull request to have it
included in the list of public DNSCrypt resolvers!
Details
=======
- Caching resolver: [Unbound](https://www.unbound.net/), with DNSSEC, prefetching,
and no logs. The number of threads and memory usage are automatically adjusted.
Latest stable version, compiled from source.
- [LibreSSL](http://www.libressl.org/) - Latest stable version, compiled from source.
- [libsodium](https://download.libsodium.org/doc/) - Latest stable version,
minimal build compiled from source.
- [dnscrypt-wrapper](https://github.com/Cofyc/dnscrypt-wrapper) - Latest stable version,
compiled from source.
- [dnscrpt-proxy](https://github.com/jedisct1/dnscrypt-proxy) - Latest stable version,
compiled from source.

53
dnscrypt-wrapper.sh Executable file

@ -0,0 +1,53 @@
#! /bin/sh
KEYS_DIR="/opt/dnscrypt-wrapper/etc/keys"
STKEYS_DIR="${KEYS_DIR}/short-term"
prune() {
find "$STKEYS_DIR" -type f -cmin +86400 -exec rm -f {} \;
}
rotation_needed() {
if [ $(find "$STKEYS_DIR" -type f -cmin -43200 -print -quit | wc -l | sed 's/[^0-9]//g') -le 0 ]; then
echo true
else
echo false
fi
}
new_key() {
ts=$(date '+%s')
/opt/dnscrypt-wrapper/sbin/dnscrypt-wrapper --gen-crypt-keypair \
--crypt-secretkey-file="${STKEYS_DIR}/${ts}.key" &&
/opt/dnscrypt-wrapper/sbin/dnscrypt-wrapper --gen-cert-file \
--provider-publickey-file="${KEYS_DIR}/public.key" \
--provider-secretkey-file="${KEYS_DIR}/secret.key" \
--crypt-secretkey-file="${STKEYS_DIR}/${ts}.key" \
--provider-cert-file="${STKEYS_DIR}/${ts}.cert" && \
mv -f "${STKEYS_DIR}/${ts}.cert" "${STKEYS_DIR}/dnscrypt.cert"
}
stkeys_files() {
res=""
for file in $(ls "$STKEYS_DIR"/[0-9]*.key); do
res="${res}${file},"
done
echo "$res"
}
if [ ! -f "$KEYS_DIR/provider_name" ]; then
exit 1
fi
provider_name=$(cat "$KEYS_DIR/provider_name")
mkdir -p "$STKEYS_DIR"
prune
[ $(rotation_needed) = true ] && new_key
exec /opt/dnscrypt-wrapper/sbin/dnscrypt-wrapper \
--user=_dnscrypt-wrapper \
--listen-address=0.0.0.0:443 \
--resolver-address=127.0.0.1 \
--provider-name="$provider_name" \
--provider-cert-file="${STKEYS_DIR}/dnscrypt.cert" \
--crypt-secretkey-file=$(stkeys_files)

105
entrypoint.sh Executable file

@ -0,0 +1,105 @@
#! /bin/sh
set -e
action="$1"
KEYS_DIR="/opt/dnscrypt-wrapper/etc/keys"
# -N provider-name
init() {
if [ $(is_initialized) = yes ]; then
start
exit $?
fi
while getopts "h?N:" opt; do
case "$opt" in
h|\?) usage ;;
N) provider_name=$(echo "$OPTARG" | sed -e 's/^[ \t]*//' | tr A-Z a-z) ;;
esac
done
[ -z "$provider_name" ] && usage
case "$provider_name" in
.*) usage ;;
2.dnscrypt-cert.*) ;;
*) provider_name="2.dnscrypt-cert.${provider_name}"
esac
echo "Provider name: [$provider_name]"
cd "$KEYS_DIR"
/opt/dnscrypt-wrapper/sbin/dnscrypt-wrapper --gen-provider-keypair | \
tee "${KEYS_DIR}/provider-info.txt"
chmod 640 "${KEYS_DIR}/secret.key"
chmod 644 "${KEYS_DIR}/public.key"
chown root:_dnscrypt-signer "${KEYS_DIR}/public.key" "${KEYS_DIR}/secret.key"
echo "$provider_name" > "${KEYS_DIR}/provider_name"
chmod 644 "${KEYS_DIR}/provider_name"
hexdump -ve '1/1 "%.2x"' < "${KEYS_DIR}/public.key" > "${KEYS_DIR}/public.key.txt"
chmod 644 "${KEYS_DIR}/public.key.txt"
echo
echo -----------------------------------------------------------------------
echo
echo "Congratulations! The container has been properly initialized."
echo "Take a look up above at the way dnscrypt-proxy has to be configured in order"
echo "to connect to your resolver. Then, start the container with the default command."
}
provider_info() {
ensure_initialized
echo "Provider name:"
cat "${KEYS_DIR}/provider_name"
echo
echo "Provider public key:"
cat "${KEYS_DIR}/public.key.txt"
echo
}
is_initialized() {
if [ ! -f "${KEYS_DIR}/public.key" -a ! -f "${KEYS_DIR}/secret.key" -a ! -f "${KEYS_DIR}/provider_name" ]; then
echo no
else
echo yes
fi
}
ensure_initialized() {
if [ $(is_initialized) = no ]; then
echo "Please provide an initial configuration (init -N <provider_name>)" >&2
exit 1
fi
}
start() {
ensure_initialized
echo "Starting DNSCrypt service for provider: "
cat "${KEYS_DIR}/provider_name"
exec /sbin/my_init
}
usage() {
cat << EOT
Commands
========
* init -N <provider_name>: initialize the container for a new provider named <provider_name>
This is supposed to be called only once.
* start (default command): start the resolver and the dnscrypt server proxy.
Ports 443/udp and 443/tcp have to be publicly exposed.
Containers on the same virtual network can directly use this container's Unbound
instance as a DNS resolver, on the standard DNS port (53).
* provider-info: prints the provide name and provider public key.
This container has a single volume that you might want to securely keep a
backup of: /opt/dnscrypt-wrapper/etc/keys
EOT
exit 1
}
case "$action" in
start) start ;;
init) shift ; init $* ;;
provider-info) provider_info ;;
*) usage ;;
esac

18
key-rotation.sh Executable file

@ -0,0 +1,18 @@
#! /bin/sh
sleep 1800
KEYS_DIR="/opt/dnscrypt-wrapper/etc/keys"
STKEYS_DIR="${KEYS_DIR}/short-term"
rotation_needed() {
if [ $(find "$STKEYS_DIR" -type f -cmin -43200 -print -quit | wc -l | sed 's/[^0-9]//g') -le 0 ]; then
echo true
else
echo false
fi
}
[ $(rotation_needed) = true ] || exit 0
sv status dnscrypt-wrapper | egrep -q '^run:' || exit 0
sv restart dnscrypt-wrapper

4
unbound-check.sh Executable file

@ -0,0 +1,4 @@
#! /bin/sh
drill -DQ NS . @127.0.0.1 &&
drill -tDQ NS . @127.0.0.1

77
unbound.sh Executable file

@ -0,0 +1,77 @@
#! /bin/sh
reserved=8388608
availableMemory=$((1024 * $(fgrep MemAvailable /proc/meminfo | sed 's/[^0-9]//g') - $reserved))
if [ $availableMemory -le 0 ]; then
exit 1
fi
msg_cache_size=$(($availableMemory / 3))
rr_cache_size=$(($availableMemory / 3))
nproc=$(nproc)
if [ $nproc -gt 1 ]; then
threads=$(($nproc - 1))
else
threads=1
fi
sed \
-e "s/@MSG_CACHE_SIZE@/${msg_cache_size}/" \
-e "s/@RR_CACHE_SIZE@/${rr_cache_size}/" \
-e "s/@THREADS@/${threads}/" \
> /opt/unbound/etc/unbound/unbound.conf << EOT
server:
verbosity: 1
num-threads: @THREADS@
interface: 0.0.0.0@53
so-reuseport: yes
edns-buffer-size: 1252
delay-close: 10000
cache-min-ttl: 60
cache-max-ttl: 86400
do-daemonize: no
username: "_unbound"
log-queries: no
hide-version: yes
identity: "DNSCrypt"
harden-short-bufsize: yes
harden-large-queries: yes
harden-glue: yes
harden-dnssec-stripped: yes
harden-below-nxdomain: yes
harden-referral-path: no
do-not-query-localhost: no
prefetch: yes
prefetch-key: yes
rrset-roundrobin: yes
minimal-responses: yes
chroot: "/opt/unbound/etc/unbound"
directory: "/opt/unbound/etc/unbound"
auto-trust-anchor-file: "var/root.key"
num-queries-per-thread: 4096
outgoing-range: 8192
msg-cache-size: @MSG_CACHE_SIZE@
rrset-cache-size: @RR_CACHE_SIZE@
access-control: 0.0.0.0/0 allow
access-control: ::0/0 allow
local-zone: "belkin." static
local-zone: "corp." static
local-zone: "domain." static
local-zone: "example." static
local-zone: "home." static
local-zone: "host." static
local-zone: "invalid." static
local-zone: "lan." static
local-zone: "local." static
local-zone: "localdomain." static
local-zone: "test." static
EOT
mkdir -p /opt/unbound/etc/unbound/dev && \
cp -a /dev/random /dev/urandom /opt/unbound/etc/unbound/dev/
mkdir -p -m 700 /opt/unbound/etc/unbound/var && \
chown _unbound:_unbound /opt/unbound/etc/unbound/var && \
/opt/unbound/sbin/unbound-anchor -a /opt/unbound/etc/unbound/var/root.key
exec /opt/unbound/sbin/unbound

22
watchdog.sh Executable file

@ -0,0 +1,22 @@
#! /bin/sh
sleep 600
for service in unbound dnscrypt-wrapper; do
sv check "$service" || sv force-restart "$service"
done
KEYS_DIR="/opt/dnscrypt-wrapper/etc/keys"
GRACE_PERIOD=6
provider_key=$(cat "${KEYS_DIR}/public.key.txt")
provider_name=$(cat "${KEYS_DIR}/provider_name")
(/opt/dnscrypt-proxy/sbin/dnscrypt-proxy \
--user=_dnscrypt-proxy \
--provider-key="$provider_key" \
--provider-name="$provider_name" \
--resolver-address=127.0.0.1:443 \
--test="$GRACE_PERIOD" && \
drill -p 443 -Q TXT "$provider_name" @127.0.0.1) || \
sv force-restart dnscrypt-wrapper