Skip to content

Commit a233bf5

Browse files
committed
Document encrypted DNS for clients and the HTTP/2 and HTTP/3 web server
Signed-off-by: DL6ER <dl6er@dl6er.de>
1 parent 7c96feb commit a233bf5

5 files changed

Lines changed: 119 additions & 1 deletion

File tree

docs/api/tls.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Pi-hole creates a self-signed certificate during installation. This certificate is used to encrypt the web interface and the API. While this certificate is secure, it is not trusted by your browser. This means that you will get a warning when you open the web interface or use the API like:
1+
Pi-hole creates a self-signed certificate during installation. This certificate is used to encrypt the web interface and the API. It is also the certificate Pi-hole presents to clients using it as an [encrypted resolver](../ftldns/encrypted-dns.md) through DoT, DoH or DoQ, so the trust considerations below apply to those clients as well. While this certificate is secure, it is not trusted by your browser. This means that you will get a warning when you open the web interface or use the API like:
22

33
![Warning in Firefox](../images/api/firefox-tls-insecure.png)
44

@@ -118,3 +118,13 @@ If this still did not work, see the remark below the Firefox instructions above.
118118
## Using your own certificate
119119

120120
If you want to use your own certificate, you can do so by placing the certificate and the private key in a location that can be read by user `pihole` (e.g., `/etc/pihole`) and, change the path in `/etc/pihole/pihole.toml` (setting `webserver.tls.cert`) and restart `pihole-FTL` (e.g., `sudo service pihole-FTL restart`). The certificate and the private key must be in PEM format (check automatically generated certificate for an example).
121+
122+
## Certificate renewal
123+
124+
Certificates Pi-hole generated itself are valid for `webserver.tls.validity` days (47 by default) and are renewed automatically two days before they expire, so a self-signed setup keeps working without any maintenance.
125+
126+
Pi-hole only renews certificates it created itself. If you use your own certificate, you have to renew it yourself, and we recommend setting `webserver.tls.validity` to `0` in that case: Pi-hole then leaves the certificate alone entirely and does not track its expiry either, so renewing it in time is up to you.
127+
128+
## Supported protocol versions
129+
130+
FTL terminates TLS itself and requires at least TLS 1.2. On encrypted ports it offers HTTP/1.1, HTTP/2 and HTTP/3, negotiated through ALPN - see [Webserver](../ftldns/webserver.md#http2-and-http3) for what that means for your firewall.

docs/ftldns/encrypted-dns.md

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
Pi-hole can act as an encrypted resolver for the clients in your network. FTL answers DNS-over-TLS (DoT), DNS-over-HTTPS (DoH) and DNS-over-QUIC (DoQ) queries itself, so you no longer need a separate proxy in front of Pi-hole to offer encrypted DNS to your phones, laptops and routers.
2+
3+
This page is about the *downstream* side, i.e., the encryption between your clients and your Pi-hole. It is unrelated to how Pi-hole talks to its own upstream servers.
4+
5+
<!-- markdownlint-disable code-block-style -->
6+
!!! info "This is not the same as encrypting your upstream traffic"
7+
If you want the queries Pi-hole forwards to its upstream resolvers to be encrypted, see the guides for [unbound](../guides/dns/unbound.md), [cloudflared](../guides/dns/cloudflared.md) or [dnscrypt-proxy](../guides/dns/dnscrypt-proxy.md). Both directions can be encrypted independently of each other.
8+
<!-- markdownlint-enable code-block-style -->
9+
10+
## What is served where
11+
12+
Protocol | Standard | Transport | Default port | Config option
13+
---------|----------|----------------|----------------------------------|--------------
14+
DoT | RFC 7858 | TCP | `853` | `dns.dot`
15+
DoQ | RFC 9250 | UDP (QUIC) | `853` | `dns.doq`
16+
DoH | RFC 8484 | TCP/UDP (HTTP) | the HTTPS port of the web server | `dns.doh`
17+
18+
All three are enabled by default and all three use the same TLS certificate as the web interface (`webserver.tls.cert`, see [TLS/SSL](../api/tls.md)).
19+
20+
DoT and DoQ share the port number `853` without colliding, as one uses TCP and the other UDP. Both ports are configurable, but we recommend staying with the defaults: `853` is the port assigned by the respective standard, and it is what clients try first (many of them do not even offer a field for a different port). Setting either option to `0` disables that listener.
21+
22+
DoH has no port of its own. It is served at the path `/dns-query` on the web server's HTTPS port, i.e., the first entry in `webserver.port` carrying the `s` flag, so a Pi-hole reachable at `https://pi.hole/admin` answers DoH at `https://pi.hole/dns-query`. If you change the web server's HTTPS port, the DoH endpoint moves with it.
23+
24+
## Enabling and disabling
25+
26+
```bash
27+
sudo pihole-FTL --config dns.dot 853 # DoT on the standard port (default)
28+
sudo pihole-FTL --config dns.doq 853 # DoQ on the standard port (default)
29+
sudo pihole-FTL --config dns.doh true # DoH on the HTTPS web server port (default)
30+
```
31+
32+
Set `dns.dot` or `dns.doq` to `0`, or `dns.doh` to `false`, to switch the respective listener off. All three options require a restart of `pihole-FTL` to take effect.
33+
34+
Who may query these listeners is governed by [`dns.listeningMode`](configfile.md), exactly like plain DNS on port 53: unless the mode is `ALL`, connections from outside your local network are dropped. This matters more here than for plain DNS, because encrypted resolvers are often reachable from the Internet by design - Pi-hole does not open itself up just because you enabled DoT.
35+
36+
<!-- markdownlint-disable code-block-style -->
37+
!!! warning "Do not expose your Pi-hole to the Internet"
38+
An openly reachable resolver will be found and abused for amplification attacks. If you want to use your Pi-hole while away from home, put it behind a VPN, e.g., [WireGuard](../guides/vpn/wireguard/index.md), instead of forwarding port `853` in your router.
39+
<!-- markdownlint-enable code-block-style -->
40+
41+
## Certificates
42+
43+
All three protocols present the certificate configured in `webserver.tls.cert`. With the self-signed certificate Pi-hole generates for itself, clients will refuse the connection unless they trust Pi-hole's certificate authority - see [adding the CA to your browser or device](../api/tls.md#adding-the-ca-to-your-browser). Some clients are stricter than browsers here and accept a manually installed CA for DoT/DoQ only reluctantly or not at all, so a certificate from a public CA for a domain you own is the more comfortable route if you run into trouble.
44+
45+
The name your clients use must match the certificate. If your certificate was created for `pi.hole` but the client is configured with an IP address, validation fails.
46+
47+
## Using it from a client
48+
49+
<!-- markdownlint-disable code-block-style -->
50+
???+ example "Testing from the command line"
51+
52+
=== "DoT"
53+
54+
```bash
55+
kdig +tls @pi.hole example.com
56+
```
57+
58+
=== "DoQ"
59+
60+
```bash
61+
kdig +quic @pi.hole example.com
62+
```
63+
64+
=== "DoH"
65+
66+
```bash
67+
curl -H 'accept: application/dns-message' \
68+
'https://pi.hole/dns-query?dns=AAABAAABAAAAAAAAB2V4YW1wbGUDY29tAAABAAE' \
69+
--output -
70+
```
71+
72+
`kdig` is part of the `knot-dnsutils` package. Add `+tls-ca=/etc/pihole/tls_ca.crt` (or `curl --cacert ...`) if the client machine does not trust Pi-hole's CA yet.
73+
<!-- markdownlint-enable code-block-style -->
74+
75+
Common places to enter these on real devices:
76+
77+
- **Android** (9 and later): *Settings -> Network & internet -> Private DNS*, which speaks DoT and expects a hostname.
78+
- **iOS/macOS**: through a DNS profile, which can carry either a DoT or a DoH server.
79+
- **Firefox**: *Settings -> Privacy & Security -> DNS over HTTPS*, using `https://pi.hole/dns-query` as a custom provider.
80+
- **Routers**: many recent firmwares (OpenWrt, AVM FRITZ!OS, Unifi) can forward to a DoT server.
81+
82+
Queries arriving this way show up in the query log like any other query, attributed to the client that sent them.
83+
84+
## Requests over plain HTTP
85+
86+
`/dns-query` is only served over HTTPS. A plaintext request is answered with `426 Upgrade Required` rather than being resolved, so a misconfigured client cannot silently fall back to sending your DNS traffic in the clear.

docs/ftldns/webserver.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,20 @@ FTL comes with the embedded webserver [CivetWeb](https://github.com/civetweb/civ
1111

1212
You can use the webserver to serve static files, dynamic content, or even custom HTTP responses (see the following examples). The webserver is configured through `pihole.toml` and can be accessed at `https://pi.hole/admin/`. Serving files outside of the webserver's home directory (`admin/`) is disabled by default for security reasons. It can be enabled by setting `webserver.serve_all` to `true`.
1313

14+
### HTTP/2 and HTTP/3
15+
16+
On encrypted ports, FTL terminates TLS itself and speaks HTTP/1.1, HTTP/2 and HTTP/3, whichever the client asks for. CivetWeb keeps serving the actual content over HTTP/1.1 behind that front end, which is why the Lua pages and everything else described on this page work the same regardless of the protocol version a browser picked.
17+
18+
The protocol is chosen through ALPN during the TLS handshake, so there is nothing to configure and nothing to enable:
19+
20+
- **HTTP/1.1** is used by clients that ask for nothing else, and on plaintext ports.
21+
- **HTTP/2** (`h2`) is used by every current browser on your HTTPS port.
22+
- **HTTP/3** (`h3`) runs on QUIC, i.e., on **UDP** with the same port number as the HTTPS port. Because a browser cannot know this in advance, FTL advertises it in an `Alt-Svc` header on its HTTP/2 responses, and the browser transparently switches over for subsequent requests.
23+
24+
The practical consequence is the firewall: if you only allow TCP to your web server port, everything keeps working but clients never get past HTTP/2, because their QUIC attempts on UDP time out. Allow UDP on the same port to make HTTP/3 usable.
25+
26+
TLS 1.2 is the lowest version FTL accepts. Clients older than that cannot connect at all, which in practice concerns only rather ancient devices.
27+
1428
### Example 1: Custom HTTP status code
1529

1630
Create a file like

docs/main/prerequisites.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,15 @@ Pi-hole needs a static IP address to properly function (a DHCP reservation is ju
6969
| pihole-FTL | 547 (DHCPv6) | IPv6 UDP | The DHCP server is an optional feature that requires additional ports. |
7070
| pihole-FTL | 80 (HTTP)<br/>443 (HTTPS) | TCP | If you have another webserver already listening on port `80`/`443`, then `pihole-FTL` will attempt to bind to `8080`/`8443` instead. If neither of these ports are available, `pihole-FTL`'s webserver will be unavailable until ports are configured manually (see configuration option `webserver.port`) |
7171
| pihole-FTL | 123 (NTP) | UDP | The NTP server is an optional feature that requires an additional port. |
72+
| pihole-FTL | 853 (DoT/DoQ) | TCP/UDP | Encrypted DNS for your clients: DNS-over-TLS on TCP, DNS-over-QUIC on UDP (configuration options `dns.dot` and `dns.doq`). DNS-over-HTTPS needs no port of its own, it is served on the HTTPS port(s) above. See [Encrypted DNS](../ftldns/encrypted-dns.md) |
7273

7374
!!! info
7475
The use of pihole-FTL on ports _67_ or _547_ is optional, but required if you use the DHCP functions of Pi-hole.
7576
The use of port _123_ is required when using pihole-FTL as NTP-Server.
77+
The use of port _853_ is only required if your clients should use Pi-hole as an encrypted resolver.
78+
79+
!!! info "HTTP/3 uses UDP"
80+
Pi-hole's web server offers HTTP/3 on the **UDP** port with the same number as its HTTPS port (`443` by default). Blocking UDP there does not break anything, clients simply stay on HTTP/2.
7681

7782
## Firewalls
7883

@@ -81,6 +86,8 @@ Because Pi-hole was designed to work inside a local network, the following rules
8186

8287
**Check your local network settings before applying these rules.**
8388

89+
The examples cover the ports Pi-hole uses by default. If your clients use Pi-hole as an [encrypted resolver](../ftldns/encrypted-dns.md), add the same rules for `853/tcp` and `853/udp`, and for `443/udp` if they should reach the web interface over HTTP/3.
90+
8491
### IPTables
8592

8693
IPTables uses two sets of tables. One set is for IPv4 chains, and the second is for IPv6 chains. If only IPv4 blocking is used for the Pi-hole installation, only apply the rules for IP4Tables. Full Stack (IPv4 and IPv6) require both sets of rules to be applied. _Note: These examples insert the rules at the front of the chain. Please see your distribution's documentation for the exact proper command to use._

mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ nav:
139139
- 'Interfaces': ftldns/interfaces.md
140140
- 'DNS cache': ftldns/dns-cache.md
141141
- 'DNS resolver': ftldns/dns-resolver.md
142+
- 'Encrypted DNS': ftldns/encrypted-dns.md
142143
- 'Blocking mode': ftldns/blockingmode.md
143144
- 'Privacy levels': ftldns/privacylevels.md
144145
- 'dnsmasq warnings': ftldns/dnsmasq_warn.md

0 commit comments

Comments
 (0)