TLS Configuration
Enable encrypted DNS with DoT and DoH
Blockasaurus supports DNS-over-TLS (DoT, port 853) and DNS-over-HTTPS (DoH) for encrypted DNS resolution. TLS configuration depends on your deployment scenario. Choose the one that matches your setup:
| Scenario | TLS? | Certificate | Use Case |
|---|---|---|---|
| 1. No TLS | No | None | Simple homelab, LAN only |
| 2. Self-signed cert | Yes | Self-signed wildcard | Homelab with DoT/DoH, no public domain |
| 3. Let’s Encrypt | Yes | Wildcard via DNS-01 | Custom domain, production deployment |
Scenario 1: No TLS
The simplest setup. Clients send plain DNS queries over UDP/TCP to port 53. No certificates needed. Client identification uses source IP or EDNS CPE-ID.
Standalone config.yml
databasePath: /var/lib/blockasaurus/blockasaurus.db
ports:
dns: 53
http: 4000
log:
level: info
Helm values.yaml
config:
ports:
dns: 53
http: 80
databasePath: /data/blocky.db
# Optional: enable CPE-ID for per-client identification
# without needing TLS or subdomains
clientGroupEndpoints:
cpeId: true
service:
dns:
enabled: true
type: LoadBalancer
Without TLS, DNS queries are sent in plain text. This is fine for a home network where you trust the local transport, but not suitable for remote clients or networks you don’t control.
Scenario 2: Self-Signed Certificate
For homelabs that want DoT and DoH but don’t have a public domain. You generate a self-signed wildcard certificate and distribute the CA to your devices.
Generate the Certificate
Create a self-signed CA and wildcard certificate for your local domain:
# Generate CA key and certificate
openssl genrsa -out ca.key 4096
openssl req -x509 -new -nodes -key ca.key \
-sha256 -days 3650 -out ca.crt \
-subj "/CN=Blockasaurus CA"
# Generate server key
openssl genrsa -out tls.key 2048
# Create certificate signing request with SANs
cat > san.cnf <<EOF
[req]
distinguished_name = req_dn
req_extensions = v3_req
prompt = no
[req_dn]
CN = blockasaurus.local
[v3_req]
subjectAltName = @alt_names
[alt_names]
DNS.1 = blockasaurus.local
DNS.2 = *.blockasaurus.local
EOF
openssl req -new -key tls.key -out tls.csr -config san.cnf
# Sign with CA
openssl x509 -req -in tls.csr -CA ca.crt -CAkey ca.key \
-CAcreateserial -out tls.crt -days 825 \
-extfile san.cnf -extensions v3_req
The wildcard *.blockasaurus.local is required for
per-client-group subdomains (e.g., kids.blockasaurus.local).
Include both the bare domain and the wildcard in the certificate’s
Subject Alternative Names.
Standalone config.yml
databasePath: /var/lib/blockasaurus/blockasaurus.db
certFile: /etc/blockasaurus/tls.crt
keyFile: /etc/blockasaurus/tls.key
ports:
dns: 53
http: 4000
https: 443
tls: 853
clientGroupEndpoints:
domains:
- blockasaurus.local
cpeId: true
log:
level: info
Helm values.yaml
First, create the TLS secret in your cluster:
kubectl create secret tls blockasaurus-tls \
--cert=tls.crt --key=tls.key \
-n blockasaurus
tls:
enabled: true
secretName: blockasaurus-tls
config:
ports:
dns: 53
http: 80
https: 443
tls: 853
databasePath: /data/blocky.db
certFile: /certs/tls.crt
keyFile: /certs/tls.key
clientGroupEndpoints:
domains:
- blockasaurus.local
advertiseAddress: auto
cpeId: true
service:
dns:
enabled: true
type: LoadBalancer
dot: true
http: true
https: true
Trust the CA on Clients
Since the certificate is self-signed, each client device needs to trust
your CA certificate (ca.crt). The web UI’s Client Groups
setup guide provides platform-specific instructions, and iOS/macOS
configuration profiles can include the CA automatically.
| macOS | Import ca.crt into Keychain Access, mark as trusted |
| iOS | Install the config profile from the web UI (includes CA) |
| Windows | Import into Trusted Root Certification Authorities |
| Android | Settings → Security → Install certificate |
| Linux | Copy to /usr/local/share/ca-certificates/ and run update-ca-certificates |
Scenario 3: Let’s Encrypt Wildcard Certificate
The production setup. You own a domain (e.g., dns.example.com)
and use Let’s Encrypt with DNS-01 validation to get a trusted wildcard
certificate. No CA distribution needed — clients trust Let’s
Encrypt by default.
Prerequisites
- A domain you control (e.g.,
dns.example.com) - DNS hosted by a provider that supports API access (Cloudflare, Route53, etc.)
- For Kubernetes: cert-manager installed in the cluster
Standalone: certbot
Use certbot with a DNS plugin to obtain a wildcard certificate:
# Example with Cloudflare DNS plugin
sudo certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials /etc/cloudflare.ini \
-d dns.example.com \
-d "*.dns.example.com"
databasePath: /var/lib/blockasaurus/blockasaurus.db
certFile: /etc/letsencrypt/live/dns.example.com/fullchain.pem
keyFile: /etc/letsencrypt/live/dns.example.com/privkey.pem
ports:
dns: 53
http: 80
https: 443
tls: 853
clientGroupEndpoints:
domains:
- dns.example.com
cpeId: true
log:
level: info
Set up a cron job or systemd timer to renew the certificate automatically. Blockasaurus will pick up the new certificate on restart.
Kubernetes: cert-manager
The Helm chart creates a cert-manager Certificate resource
automatically when certificate.enabled: true:
certificate:
enabled: true
issuerRef:
name: letsencrypt-dns01-cloudflare
kind: ClusterIssuer
dnsNames:
- dns.example.com # base domain
- "*.dns.example.com" # wildcard for per-group subdomains
# secretName defaults to {fullname}-tls
tls:
enabled: true
secretName: blockasaurus-tls
config:
ports:
dns: 53
http: 80
https: 443
tls: 853
databasePath: /data/blocky.db
certFile: /certs/tls.crt
keyFile: /certs/tls.key
clientGroupEndpoints:
domains:
- dns.example.com
advertiseAddress: auto
cpeId: true
service:
dns:
enabled: true
type: LoadBalancer
externalTrafficPolicy: Local # preserves client source IPs
dot: true
http: true
https: true
Both the base domain and wildcard are required in
dnsNames. A wildcard cert (*.dns.example.com)
does not cover the bare domain (dns.example.com).
Port Reference
| Port | Protocol | Service | Requires TLS |
|---|---|---|---|
53 |
UDP/TCP | Plain DNS | No |
80 |
TCP | HTTP (Web UI + DoH fallback) | No |
443 |
TCP | HTTPS (DoH + Web UI) | Yes |
853 |
TCP | DNS-over-TLS (DoT) | Yes |
Advanced: Separate Admin Port
If your DoH endpoint is internet-facing, you may want to restrict the web
UI to an internal-only port. Use adminPort to separate the
admin UI from the DNS server endpoint:
config:
ports:
dns: 53
http: 80 # DNS server only (internet-facing DoH)
https: 443 # DNS server only (internet-facing DoH)
adminPort: 8080 # Web UI, API, metrics (internal only)
tls: 853
service:
dns:
externalTrafficPolicy: Local
dot: true
http: true # DoH on the LoadBalancer
https: true
adminPort:
enabled: true # Admin UI on a separate ClusterIP
type: ClusterIP
port: 8080
When adminPort is configured, the /metrics
Prometheus endpoint moves to the admin port. Update your
prometheus.io/port pod annotation accordingly.