diff --git a/Makefile b/Makefile
index edf31c6af0eab6b4fa0b400e6367bc1f0e500819..e96b6c2e891e1a490717ad27c905a75d611e7c01 100644
--- a/Makefile
+++ b/Makefile
@@ -10,7 +10,7 @@ LDFLAGS += $(shell pkg-config --libs libsystemd)
 all: hddemux hddemux.1
 
 check: hddemux
-	./testsuite
+	PATH=.:$$PATH ./testsuite
 
 hddemux: hddemux.c
 	gcc $(CPPFLAGS) $(CFLAGS) $< $(LDFLAGS) -std=c11 -pedantic -Wall -Werror -o $@
diff --git a/testsuite b/testsuite
index 684c128504564c9e51e4282c96cb2a8e123bb57e..b65455770cae870886f47ea704728462d95ad1e6 100755
--- a/testsuite
+++ b/testsuite
@@ -1,18 +1,146 @@
 #!/bin/bash
 
+# test suite for hddemux
+
+# requires:
+#  - nginx
+#  - knot-resolver
+#  - kdig (from knot-dnsutils)
+#  - curl
+#  - certtool (from gnutls-bin)
+
+# environment variables:
+#  - WORKDIR: a place for all generated files.
+#             if unset, it will be auto-generated.
+#             it will be created as needed.
+#             if the directory doesn't currently exist, it will be cleaned up at exit.
+#             if it already exists, it will not be cleaned up.
+#  -  TESTIP: the IP address to use for testing.
+#             the user needs to be able to open listening sockets, and to connect to them
+#             by default, 127.7.8.9
+
+# Author: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
+# 2018-08-29
+# License: GPLv3+
+
+# error on exit
 set -e
+# for handling jobspecs:
+set -m
 
-# test suite for hddemux
+hddemux=$(which hddemux) || hddemux=./hddemux
+
+[ -x "$hddemux" ]
+
+if [ -z "$WORKDIR" ]; then
+    d="$(mktemp -d)"
+    remove="$d"
+else
+    d="$WORKDIR"
+fi
+ip="${TESTIP:-127.7.8.9}"
+
+printf "hddemux test\n------------\n  binary: %s\n workdir: %s\n IP addr: %s\n" "$hddemux" "$d" "$ip"
+
+section() {
+    printf "\n%s\n" "$1"
+    sed 's/./-/g' <<<"$1"
+}
 
-# this is just a stub.
+cleanup () {
+    section "cleaning up"
+    /usr/sbin/nginx -c "$d/nginx.conf" -p "$d" -s stop 2> "$d/nginx-stop.err" || true
+    kill %2 || true
+    kill %1 || true
+    if [ "$remove" ]; then
+        printf "cleaning up working directory %s\n" "$remove"
+        rm -rf "$remove"
+    fi
+}
 
-[ -x ./hddemux ]
+trap cleanup EXIT
 
+
+section "simple failing run"
 # hddemux with no arguments and no listening file descriptors should fail:
-if ./hddemux; then
+if "$hddemux"; then
     false
 fi
 
-# should probably try to actually test it!
 
-true
+section "make Certificate Authority key and certificate"
+cat > "$d/ca.template" <<EOF
+cn = "testing certificate authority (NOT FOR PRODUCTION)"
+expiration_days = 12
+ca
+path_len = 1
+nc_permit_dns = example
+cert_signing_key
+EOF
+certtool --stdout-info --generate-privkey --outfile "$d/ca-key.pem"
+certtool --stdout-info --generate-self-signed --template "$d/ca.template" --load-privkey "$d/ca-key.pem" --outfile "$d/ca-cert.pem"
+
+section "make End Entity key and certificate"
+cat > "$d/ee.template" <<EOF
+cn = "test.example"
+dns_name = test.example
+expiration_days = 10
+signing_key
+tls_www_server
+EOF
+certtool --stdout-info --generate-privkey --outfile "$d/ee-key.pem"
+certtool --stdout-info --pubkey-info --load-privkey "$d/ee-key.pem" --outfile "$d/ee-pubkey.pem"
+certtool --stdout-info --generate-certificate --load-ca-privkey "$d/ca-key.pem" --load-ca-certificate "$d/ca-cert.pem" --template "$d/ee.template" --load-pubkey "$d/ee-pubkey.pem" --outfile "$d/ee-cert.pem"
+
+
+
+section "make knot-resolver configuration on $ip:8853"
+cat > "$d/kresd.conf" <<EOF
+modules = { 'hints > iterate' }
+net.tls("$d/ee-cert.pem", "$d/ee-key.pem")
+hints["monkeys.example"] = "127.15.23.5"
+EOF
+systemd-socket-activate -l "$ip:8853" --fdname=tls /usr/sbin/kresd -c "$d/kresd.conf" "$d" 2> "$d/kresd.err" &
+
+section "make hddeumx configuration on $ip:2000"
+systemd-socket-activate -l "$ip:2000" -E=HTTP_TARGET="$ip:8853" -E DNS_TARGET="$ip:8853" "$hddemux" 2> "$d/hddemux.err" &
+
+section "set up nginx on $ip:4433"
+cat >"$d/nginx.conf" <<EOF
+error_log stderr;
+worker_processes 1;
+pid nginx.pid;
+
+events {
+ worker_connections 10;
+}
+http {
+ default_type text/plain;
+ ssl_protocols TLSv1.2;
+ ssl_prefer_server_ciphers on;
+ server {
+  listen $ip:4433 ssl;
+  server_name test.example;
+  ssl_certificate ee-cert.pem;
+  ssl_certificate_key ee-key.pem;
+  access_log access.log;
+  location / {
+   root data;
+   index index.txt;
+  }
+ }
+}
+EOF
+mkdir -p "$d/data"
+echo "Hello, world!" > "$d/data/index.txt"
+/usr/sbin/nginx -c "$d/nginx.conf" -p "$d" 2> "$d/nginx.err"
+
+section "test with kdig"
+x=$(kdig +short +tls +tls-ca="$d/ca-cert.pem" +tls-hostname=test.example @"$ip:2000" monkeys.example)
+[ "$x" = "127.15.23.5" ]
+echo "successful DNS-over-TLS request to $ip on port 2000"
+
+section "test with curl"
+x=$(curl --silent --show-error --cacert "$d/ca-cert.pem" --resolve "test.example:2000:$ip" --resolve "test.example:4433:$ip" https://test.example:4433/)
+[ "$x" = "Hello, world!" ]
+echo "successful HTTPS request to $ip on port 2000"