===================================================================== ___ __ _ __ ___ _____/ (_)___ / /_(_) /__ / _ \/ ___/ / / __ \/ __/ / //_/ / __/ /__/ / / /_/ / /_/ / ,< \___/\___/_/_/ .___/\__/_/_/|_| /_/ =====================================================================
Over the holidays we got our two younger children HP laptops for them to do their school work on and to have a proper computer. While the schools Google Classroom login effectively adds restrictions to Chrome, I still wanted to have some guardrails on their Internet access as well as ad-blocking.
The first thing I did was replace the Windows S install that came on the laptops with Linux Mint[1] as I've always enjoyed the Cinnamon desktop environment[2] and it has a low enough learning curve that the kids could easily pick it up. After installing a few apps and games (OpenRCT2[3]) from the Software Center and setting their own passwords, they were up and running and surfing the world-wide-web.
=> 1: https://www.linuxmint.com/ | 2: https://projects.linuxmint.com/cinnamon/ | 3: https://openrct2.org/
Finally I added Tailscale[4] to both laptops to put them on my tailnet[5]. This has benefits of accessing tailnet-only services, easier remote access, and leveraging the dnscrypt-proxy on OpenBSD[6] I setup a few years ago for DNS.
=> 4: https://tailscale.com/ | 5: https://tailscale.com/kb/1136/tailnet | 6: https://www.ecliptik.com/Running-dnscrypt-proxy-on-OpenBSD/
My original DNS config worked well, but I wanted to add some guardrails specifically for the kids laptops,
=> 7: https://blog.cloudflare.com/introducing-1-1-1-1-for-families/ | 8: https://github.com/DNSCrypt/dnscrypt-proxy/wiki/Public-blocklist | 9: https://support.google.com/a/answer/6212415 | 10: https://github.com/DNSCrypt/dnscrypt-proxy/wiki/Public-blocklist
First I tried using the existing dnscrypt-proxy[11] to provide a different set of DNS resolvers depending on the source IP, but this wasn't possible. Eventually I came up with a seperate DNS infrastructure in a container for the laptops to use,
=> 11: https://github.com/DNSCrypt/dnscrypt-proxy
FROM debian:trixie-slim
ENV DEBIAN_FRONTEND noninteractive
RUN apt update && \
apt install -y dnscrypt-proxy \
ca-certificates \
&& apt clean
WORKDIR /tmp
ENTRYPOINT [ "/usr/sbin/dnscrypt-proxy" ]
CMD [ "-config", "/etc/dnscrypt-proxy/dnscrypt-proxy.toml" ]
docker compose[12] is used to bring up the stack, which includes a `tailscale` container to provide network and access to other devices on the tailnet. Configuration files are monted read-only from the current directly and some volumes to maintain state across restarts. => https://docs.docker.com/compose/ 12: https://docs.docker.com/compose/
version: '3.9' services: tailscale: container_name: tailscale-dnscrypt hostname: dnscrypt-proxy image: ghcr.io/tailscale/tailscale stdin_open: true environment: - TS_AUTH_KEY=${TS_AUTH_KEY} - TS_USERSPACE=true - TS_STATE_DIR=/var/lib/tailscale - TS_SOCKET=/var/run/tailscale/tailscaled.sock volumes: - dnscryptvarlib:/var/lib restart: unless-stopped dnscrypt-proxy: build: . stdin_open: true volumes: - ./dnscrypt-proxy.toml:/etc/dnscrypt-proxy/dnscrypt-proxy.toml:ro - ./blocklist.txt:/etc/dnscrypt-proxy/blocklist.txt:ro - ./cloaking-rules.txt:/etc/dnscrypt-proxy/cloaking-rules.txt:ro - ./domains-allowlist.txt:/etc/dnscrypt-proxy/domains-allowlist.txt:ro - keys:/etc/dnscrypt-proxy/keys restart: unless-stopped network_mode: 'service:tailscale' volumes: dnscryptvarlib: keys:
The dnscrypt-proxy configuration uses the cloudflare-family
source and ad-blocking using a blocklist.txt
generated with generate-domains-blocklist.py[13]. All logs go to /dev/stdout
so they appear in docker compose logs
.
=> 13: https://github.com/DNSCrypt/dnscrypt-proxy/wiki/Combining-Blocklists
server_names = ['cloudflare-family']
listen_addresses = ['127.0.0.1:53']
max_clients = 250
user_name = '_dnscrypt-proxy'
ipv4_servers = true
ipv6_servers = false
force_tcp = false
timeout = 2500
keepalive = 30
log_level = 2
use_syslog = true
cert_refresh_delay = 240
dnscrypt_ephemeral_keys = true
tls_disable_session_tickets = true
cache = true
cloaking_rules = '/etc/dnscrypt-proxy/cloaking-rules.txt'
[query_log]
file = '/dev/stdout'
format = 'tsv'
[sources]
[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']
minisign_key = 'RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3'
cache_file = '/var/tmp/public-resolvers.md'
refresh_delay = 72
[blocked_names]
blocked_names_file = '/etc/dnscrypt-proxy/blocklist.txt'
log_file = '/dev/stdout'
log_format = 'tsv'
[allowed_names]
allowed_names_file = '/etc/dnscrypt-proxy/domains-allowlist.txt
Cloaking[14] is used so all YouTube requests resolve to `restrict.youtube.com`. => https://github.com/DNSCrypt/dnscrypt-proxy/wiki/Public-blocklist 14: https://github.com/DNSCrypt/dnscrypt-proxy/wiki/Public-blocklist
www.youtube.com restrict.youtube.com m.youtube.com restrict.youtube.com youtubei.googleapis.com restrict.youtube.com youtube.googleapis.com restrict.youtube.com www.youtube-nocookie.com restrict.youtube.com
Since I only want DNS available to devices on my tailnet, and not publicly available, there's a tailscale
container in the docker-compose.yml
that provides networking to the dnscrypt-proxy
container using network_mode
.
Set this up by creating an auth key[15] for your tailnet and then putting it into a .env
file that docker compose will source in and set as the TS_AUTH_KEY
variable.
=> 15: https://tailscale.com/kb/1085/auth-keys
TS_AUTH_KEY=tskey-auth-xxxxxxxxxxx
## Enabling on Linux Mint My tailnet uses Magic DNS[16] which sets the nameserver for all devices on a tailnet to `100.100.100.100`, but since this is a DNS server specific to a subset of systems we want to use the IP of the `dnscrypt-proxy` device instead. => https://tailscale.com/kb/1081/magicdns 16: https://tailscale.com/kb/1081/magicdns After bringing up the stack with `docker compose up`, the `tailscale` container will authenticate to the tailnet and have an Tailscale IP (eg `100.112.129.40`). This IP is then added to the laptops `/etc/resolv.conf`,
nameserver 100.112.129.40
search tailnet-3831.ts.net
text/gemini; lang=en
This content has been proxied by September (3851b).