mirror of
https://github.com/pi-hole/docs.git
synced 2026-08-17 18:33:02 +01:00
Document encrypted DNS for clients and the HTTP/2 and HTTP/3 web server
Signed-off-by: DL6ER <dl6er@dl6er.de>
This commit is contained in:
+16
-2
@@ -1,4 +1,4 @@
|
||||
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:
|
||||
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:
|
||||
|
||||

|
||||
|
||||
@@ -12,7 +12,7 @@ It is also possible to add the CA to your operating system's certificate store.
|
||||
|
||||
Note that you have to add the **CA** certificate (e.g., `/etc/pihole/tls_ca.crt`) and not the server certificate (e.g., `/etc/pihole/tls.pem`).
|
||||
|
||||
It is worth noting that the certificate is only valid for the domain that you had configured during certificate creation. If you access the Pi-hole web interface using a different domain, you will get a warning. This is because the certificate does not match the domain. You can either add the certificate for the other domain as well or you can create a new certificate for the other domain. You can easily create a new certificate by removing the old certificate and restarting `pihole-FTL` (e.g., `sudo rm /etc/pihole/tls* && sudo service pihole-FTL restart`). This will create a new certificate for the domain configured in `/etc/pihole/pihole.toml` (setting `webserver.domain`).
|
||||
It is worth noting that the certificate is valid for `pi.hole` and, if you configured one, for your custom `webserver.domain` - but for nothing else, in particular not for your Pi-hole's IP address. If you access the web interface under any other name, you will get a warning because the certificate does not match the domain. You can either add the certificate for the other domain as well or you can create a new certificate for the other domain. You can easily create a new certificate by removing the old certificate and restarting `pihole-FTL` (e.g., `sudo rm /etc/pihole/tls* && sudo service pihole-FTL restart`). This will create a new certificate for the domain configured in `/etc/pihole/pihole.toml` (setting `webserver.domain`).
|
||||
|
||||
<!-- markdownlint-disable code-block-style -->
|
||||
!!! warning "Security warning"
|
||||
@@ -118,3 +118,17 @@ If this still did not work, see the remark below the Firefox instructions above.
|
||||
## Using your own certificate
|
||||
|
||||
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).
|
||||
|
||||
## Certificate renewal
|
||||
|
||||
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 `pihole-FTL` never ends up serving an expired certificate.
|
||||
|
||||
Renewal creates a *new* certificate authority as well, because the old CA's private key was discarded right after the previous certificate was signed and can no longer sign anything. Every device you added the CA to therefore has to be given the new `/etc/pihole/tls_ca.crt` after each renewal. If you added the CA to your devices, a longer `webserver.tls.validity` means fewer of these rounds - or use a certificate from a public CA instead.
|
||||
|
||||
Pi-hole recognizes its own certificates by their common name: both issuer and subject have to read `pi.hole`. A self-signed certificate Pi-hole created for a different `webserver.domain` therefore does *not* qualify - it is treated like a foreign certificate and only logs `is about to expire soon, but it is not a Pi-hole certificate` when the time comes. Renew it by deleting `/etc/pihole/tls*` and restarting `pihole-FTL`.
|
||||
|
||||
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 that certificate alone entirely and does not track its expiry either, so renewing it in time is up to you. Note that `0` disables renewal, not the initial generation - if the file `webserver.tls.cert` points at does not exist, Pi-hole still creates a self-signed certificate for it, then with a fixed validity of roughly 30 years.
|
||||
|
||||
## Supported protocol versions
|
||||
|
||||
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.
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
<!-- markdownlint-disable code-block-style -->
|
||||
!!! info "This is not the same as encrypting your upstream traffic"
|
||||
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.
|
||||
<!-- markdownlint-enable code-block-style -->
|
||||
|
||||
## What is served where
|
||||
|
||||
Protocol | Standard | Transport | Default port | Config option
|
||||
---------|----------|----------------|----------------------------------|--------------
|
||||
DoT | RFC 7858 | TCP | `853` | `dns.dot`
|
||||
DoQ | RFC 9250 | UDP (QUIC) | `853` | `dns.doq`
|
||||
DoH | RFC 8484 | TCP/UDP (HTTP) | the HTTPS port of the web server | `dns.doh`
|
||||
|
||||
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)).
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
## Enabling and disabling
|
||||
|
||||
```bash
|
||||
sudo pihole-FTL --config dns.dot 853 # DoT on the standard port (default)
|
||||
sudo pihole-FTL --config dns.doq 853 # DoQ on the standard port (default)
|
||||
sudo pihole-FTL --config dns.doh true # DoH on the HTTPS web server port (default)
|
||||
```
|
||||
|
||||
Set `dns.dot` or `dns.doq` to `0`, or `dns.doh` to `false`, to switch the respective listener off. Changing any of the three makes `pihole-FTL` restart itself so the new setting takes effect, which interrupts DNS resolution for a moment - you do not have to restart it yourself.
|
||||
|
||||
Who may query these listeners is governed by [`dns.listeningMode`](configfile.md), but the rule is stricter than the one dnsmasq applies on port 53: unless the mode is `ALL`, the client has to sit on a subnet directly attached to your Pi-hole, where loopback and point-to-point peers such as a VPN count as local, and in `SINGLE` or `BIND` it must be on the subnet of the configured `dns.interface`. Plain DNS is more permissive, as `SINGLE` and `BIND` accept any origin that reaches the configured interface, so a routed client that gets an answer on port 53 can still be turned away here. That is deliberate - encrypted resolvers are often reachable from the Internet by design, and Pi-hole does not open itself up just because you enabled DoT.
|
||||
|
||||
<!-- markdownlint-disable code-block-style -->
|
||||
!!! warning "Do not expose your Pi-hole to the Internet"
|
||||
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.
|
||||
<!-- markdownlint-enable code-block-style -->
|
||||
|
||||
## Certificates
|
||||
|
||||
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.
|
||||
|
||||
The certificate is created by the web server, not by these listeners, and only when `webserver.port` contains a TLS port (`443s` by default). If you serve the web interface over plain HTTP only, no certificate is generated and DoT and DoQ wait for one instead of starting - they log `DoT waiting for the webserver TLS certificate` once and retry until the file appears. Point `webserver.tls.cert` at your own certificate in that case.
|
||||
|
||||
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.
|
||||
|
||||
## Using it from a client
|
||||
|
||||
<!-- markdownlint-disable code-block-style -->
|
||||
???+ example "Testing from the command line"
|
||||
|
||||
=== "DoT"
|
||||
|
||||
```bash
|
||||
kdig +tls @pi.hole example.com
|
||||
```
|
||||
|
||||
=== "DoQ"
|
||||
|
||||
```bash
|
||||
kdig +quic @pi.hole example.com
|
||||
```
|
||||
|
||||
=== "DoH"
|
||||
|
||||
```bash
|
||||
curl -H 'accept: application/dns-message' \
|
||||
'https://pi.hole/dns-query?dns=AAABAAABAAAAAAAAB2V4YW1wbGUDY29tAAABAAE' \
|
||||
--output -
|
||||
```
|
||||
|
||||
`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.
|
||||
<!-- markdownlint-enable code-block-style -->
|
||||
|
||||
Common places to enter these on real devices:
|
||||
|
||||
- **Android** (9 and later): *Settings -> Network & internet -> Private DNS*, which speaks DoT and expects a hostname.
|
||||
- **iOS/macOS**: through a DNS profile, which can carry either a DoT or a DoH server.
|
||||
- **Firefox**: *Settings -> Privacy & Security -> DNS over HTTPS*, using `https://pi.hole/dns-query` as a custom provider.
|
||||
- **Routers**: many recent firmwares (OpenWrt, AVM FRITZ!OS, Unifi) can forward to a DoT server.
|
||||
|
||||
Queries arriving this way show up in the query log like any other query, attributed to the client that sent them.
|
||||
|
||||
## Requests over plain HTTP
|
||||
|
||||
`/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.
|
||||
@@ -11,6 +11,20 @@ FTL comes with the embedded webserver [CivetWeb](https://github.com/civetweb/civ
|
||||
|
||||
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`.
|
||||
|
||||
### HTTP/2 and HTTP/3
|
||||
|
||||
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.
|
||||
|
||||
The protocol is chosen through ALPN during the TLS handshake, so there is nothing to configure and nothing to enable:
|
||||
|
||||
- **HTTP/1.1** is used by clients that ask for nothing else, and on plaintext ports.
|
||||
- **HTTP/2** (`h2`) is used by every current browser on your HTTPS port.
|
||||
- **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.
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
### Example 1: Custom HTTP status code
|
||||
|
||||
Create a file like
|
||||
|
||||
@@ -69,10 +69,15 @@ Pi-hole needs a static IP address to properly function (a DHCP reservation is ju
|
||||
| pihole-FTL | 547 (DHCPv6) | IPv6 UDP | The DHCP server is an optional feature that requires additional ports. |
|
||||
| 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`) |
|
||||
| pihole-FTL | 123 (NTP) | UDP | The NTP server is an optional feature that requires an additional port. |
|
||||
| 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) |
|
||||
|
||||
!!! info
|
||||
The use of pihole-FTL on ports _67_ or _547_ is optional, but required if you use the DHCP functions of Pi-hole.
|
||||
The use of port _123_ is required when using pihole-FTL as NTP-Server.
|
||||
The use of port _853_ is only required if your clients should use Pi-hole as an encrypted resolver.
|
||||
|
||||
!!! info "HTTP/3 uses UDP"
|
||||
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.
|
||||
|
||||
## Firewalls
|
||||
|
||||
@@ -81,6 +86,8 @@ Because Pi-hole was designed to work inside a local network, the following rules
|
||||
|
||||
**Check your local network settings before applying these rules.**
|
||||
|
||||
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.
|
||||
|
||||
### IPTables
|
||||
|
||||
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._
|
||||
|
||||
@@ -139,6 +139,7 @@ nav:
|
||||
- 'Interfaces': ftldns/interfaces.md
|
||||
- 'DNS cache': ftldns/dns-cache.md
|
||||
- 'DNS resolver': ftldns/dns-resolver.md
|
||||
- 'Encrypted DNS': ftldns/encrypted-dns.md
|
||||
- 'Blocking mode': ftldns/blockingmode.md
|
||||
- 'Privacy levels': ftldns/privacylevels.md
|
||||
- 'dnsmasq warnings': ftldns/dnsmasq_warn.md
|
||||
|
||||
Reference in New Issue
Block a user