Skip to content

Commit 19ebd93

Browse files
committed
Add TLS certificate guides for Pi-hole
- Add automatic SSL certificate renewal guide using acme.sh + Let's Encrypt * Covers Cloudflare DNS validation setup * Includes certificate installation and Pi-hole configuration * Documents automatic renewal via cron jobs - Add self-signed SSL certificate creation guide * Method 1: Internal CA approach for multiple servers (recommended) * Method 2: Direct self-signed certificates for single server * Includes Subject Alternative Names (SAN) configuration * Covers browser certificate installation steps These guides are adapted from my existing GitHub Gists: - Automatic renewal: https://gist.github.com/kaczmar2/17f02a0ddb59a7d336b20376695797c6 - Self-signed certs: https://gist.github.com/kaczmar2/e1b5eb635c1a1e792faf36508c5698ee Both guides provide step-by-step instructions for different deployment scenarios. Fix Pi-hole branding in new guides. Signed-off-by: Christian Kaczmarek <kaczmar2@outlook.com>
1 parent 798839f commit 19ebd93

File tree

3 files changed

+375
-0
lines changed

3 files changed

+375
-0
lines changed
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
# Automating Certificate Renewal
2+
3+
## Overview
4+
5+
By default, Pi-hole v6 provides a self-signed SSL certificate, but you can automate certificate renewal with acme.sh, Cloudflare and Let's Encrypt.
6+
7+
This guide uses:
8+
9+
- [acme.sh](https://github.com/acmesh-official/acme.sh?tab=readme-ov-file#an-acme-shell-script-acmesh): An ACME shell script.
10+
- [Cloudflare DNS](https://www.cloudflare.com/application-services/products/dns/).
11+
- [Let’s Encrypt](https://letsencrypt.org/).
12+
13+
## Prerequisites
14+
15+
- **Pi-hole installed and running** on your system.
16+
- **A Cloudflare account** that manages your domain’s DNS records.
17+
- **Control of a registered domain** (e.g., `mydomain.com`).
18+
19+
These prerequisites ensure that you can successfully request and install an SSL certificate using **Cloudflare DNS validation** with `acme.sh`.
20+
This guide uses **Cloudflare DNS** and **Let’s Encrypt**. These instructions can be adapted for any DNS provider and Certificate Authority (CA) that `acme.sh` supports. Simply update the `--dns` and `--server` flags accordingly when issuing your certificate.
21+
22+
**Note:** This guide assumes that `acme.sh` runs under the `root` user. The `--reloadcmd` contains commands that require `sudo`, such as removing old certificates, writing the new certificate, and restarting Pi-hole FTL. If you prefer to run `acme.sh` as a regular user, additional configuration is required to allow these commands to execute without a password. Methods for achieving this, such as configuring `sudo` rules, are beyond the scope of this article.
23+
24+
## **1. Install acme.sh as `root`**
25+
26+
Run a login shell as root:
27+
```
28+
sudo -i
29+
```
30+
31+
Install it:
32+
```bash
33+
curl https://get.acme.sh | sh -s email=my@example.com
34+
```
35+
36+
Reload .bashrc to register the acme.sh alias:
37+
```
38+
source .bashrc
39+
```
40+
41+
Verify installation:
42+
```bash
43+
acme.sh --version
44+
```
45+
46+
---
47+
48+
## **2. Set Up Cloudflare DNS API**
49+
For **DNS-based domain verification**, export your **Cloudflare API token**:
50+
51+
```bash
52+
export CF_Token="ofz...xxC"
53+
export CF_Email="me@mydomain.com"
54+
```
55+
This allows `acme.sh` to create the required DNS records automatically.
56+
57+
---
58+
59+
## **3. Issue the SSL Certificate for Pi-hole**
60+
Run:
61+
```bash
62+
acme.sh --issue --dns dns_cf -d ns1.mydomain.com --server letsencrypt
63+
```
64+
This generates:
65+
- **Private key**: `ns1.mydomain.com.key`
66+
- **Full-chain certificate**: `fullchain.cer` (includes `ns1.mydomain.com.cer` + `ca.cer`, in that order)
67+
68+
69+
You do not need these other certificate files:
70+
- **Server certificate**: `ns1.mydomain.com.cer` (included in `fullchain.cer`)
71+
- **Intermediate CA cert**: `ca.cer` (included in `fullchain.cer`)
72+
73+
---
74+
75+
## **4. Install and Apply the SSL Certificate to Pi-hole**
76+
Pi-hole **requires a PEM file** containing **both the private key and server certificate**.
77+
78+
Install the certificate:
79+
```bash
80+
acme.sh --install-cert -d ns1.mydomain.com \
81+
--reloadcmd "sudo rm -f /etc/pihole/tls* && \
82+
sudo cat fullchain.cer ns1.mydomain.com.key | sudo tee /etc/pihole/tls.pem && /
83+
sudo service pihole-FTL restart"
84+
```
85+
86+
This:
87+
88+
- Deletes old certificates (`/etc/pihole/tls*`).
89+
- Creates `tls.pem` with both the full-chain certificate file and private key, in that order.
90+
- Restarts Pi-hole FTL to apply the new certificate.
91+
92+
---
93+
94+
## **5. Configure Pi-hole**
95+
To avoid domain mismatch warnings (`CERTIFICATE_DOMAIN_MISMATCH`), set the **correct hostname**:
96+
97+
```bash
98+
sudo pihole-FTL --config webserver.domain 'ns1.mydomain.com'
99+
sudo service pihole-FTL restart
100+
```
101+
102+
Fixes:
103+
```
104+
CERTIFICATE_DOMAIN_MISMATCH SSL/TLS certificate /etc/pihole/tls.pem does not match domain pi.hole!
105+
```
106+
107+
---
108+
109+
## **Notes**
110+
- Your **certificate renews automatically** via `acme.sh`'s cron job.
111+
- You can manually renew with:
112+
```bash
113+
acme.sh --renew -d ns1.mydomain.com --force
114+
```
115+
- To check your certificate:
116+
```bash
117+
sudo openssl x509 -in /etc/pihole/tls.pem -text -noout
118+
```

docs/guides/ssl/self-signed.md

Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
# Pi-hole v6: Creating Your Own Self-Signed SSL Certificates
2+
3+
## Overview
4+
5+
By default, Pi-hole v6 provides a self-signed SSL certificate, but you can create your own self-signed certificate for Pi-hole that specifies your desired hostnames, fully qualified domain names (FQDN), and IP addresses for your Pi-hole server using **openssl**.
6+
7+
## Prerequisites
8+
9+
Install `openssl`:
10+
```
11+
sudo apt update && sudo apt install openssl -y # For Debian/Ubuntu
12+
sudo yum install openssl -y # For RHEL/CentOS
13+
sudo dnf install openssl -y # For Fedora
14+
```
15+
16+
This guide assumes:
17+
18+
- `openssl` is installed on the same machine that Pi-hole is installed on, but this is not a requirement -
19+
`openssl` can be installed on a machine that is not running Pi-hole; `tls.pem` just needs to be copied to `/etc/pihole` on the target mahcine running Pi-hole.
20+
- All shell commands are executed from the home directory (e.g., `/home/your_user` or `~/`).
21+
22+
---
23+
## Method 1: Use an Internal Certificate Authority CA (Recommended)
24+
- Pros: All future certificates are trusted once you install the CA cert.
25+
- Cons: Requires setting up a CA.
26+
27+
**Summary:** Set up a CA, sign certificates for each server, and install only one CA certificate instead of trusting multiple self-signed certificates.
28+
29+
### Step 1: Create a directory to hold your cert, config, and key files:
30+
```
31+
mkdir -p ~/crt && cd ~/crt
32+
```
33+
34+
### Step 2: Create a Certificate Authority (CA) Key and Certificate
35+
36+
The CA will be used to sign server certificates.
37+
38+
```
39+
openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 -nodes -days 3650 -keyout homelabCA.key -out homelabCA.crt -subj "/C=US/O=My Homelab CA/CN=MyHomelabCA"
40+
```
41+
- `x509`: Generates a self-signed certificate (for a CA).
42+
- `newkey ec`: Creates a new EC key.
43+
- `pkeyopt ec_paramgen_curve:prime256v1`: Uses P-256 curve.
44+
- `nodes`: Skips password protection (optional).
45+
- `-days 3650`: Valid for 10 years.
46+
- `keyout homelabCA.key`: Saves the private key.
47+
- `out homelabCA.crt`: Saves the self-signed CA certificate.
48+
- `subj`: Provides the Distinguished Name (DN) inline:
49+
- `C=US`: Country
50+
- `O=My Homelab CA`: Organization (CA)
51+
- `CN=MyHomelabCA`: Common Name (CA)
52+
53+
The **CA key** (homelabCA.key) and **CA certificate** (homelabCA.crt) is now ready to be used to sign server certificates.
54+
55+
### Step 3: Create a Certificate Configuration File (`cert.cnf`)
56+
57+
```
58+
touch cert.cnf && nano cert.cnf
59+
```
60+
61+
Use the attached [cert.cnf](https://gist.github.com/kaczmar2/e1b5eb635c1a1e792faf36508c5698ee#file-cert-cnf) file as a template:
62+
```ini
63+
# Country Name (C)
64+
#Organization Name (O)
65+
#Common Name (CN) - Set this to your server’s hostname or IP address.
66+
67+
# SAN (Subject Alternative Name), [alt-names] is required
68+
# You can add as many hostname and IP entries as you wish
69+
70+
[req]
71+
default_md = sha256
72+
distinguished_name = req_distinguished_name
73+
req_extensions = v3_ext
74+
x509_extensions = v3_ext
75+
prompt = no
76+
77+
[req_distinguished_name]
78+
C = US
79+
O = My Homelab
80+
CN = pi.hole
81+
82+
[v3_ext]
83+
subjectAltName = @alt_names
84+
85+
[alt_names]
86+
DNS.1 = pi.hole # Default pihole hostname
87+
DNS.2 = pihole-test # Replace with your server's hostname
88+
DNS.3 = pihole-test.home.arpa # Replace with your server's FQDN
89+
IP.1 = 10.10.10.115 # Replace with your Pi-hole IP
90+
IP.2 = 10.10.10.116 # Another local IP if needed
91+
```
92+
93+
### Step 4: Generate a Key and CSR
94+
95+
Use **Elliptic Curve Digital Signature Algorithm (ECDSA)** to generate both the **private key** (`tls.key`) and **Certificate Signing Request (CSR)** (`tls.csr`).
96+
```
97+
openssl req -new -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 -nodes -keyout tls.key -out tls.csr -config cert.cnf
98+
```
99+
- `-newkey ec`: Creates a new EC key.
100+
- `-pkeyopt ec_paramgen_curve:prime256v1`: Uses P-256 curve.
101+
- `-nodes` - No password on the private key.
102+
- `-keyout tls.key`: Saves the private key.
103+
- `-out tls.csr`: Saves the certificate signing request (CSR).
104+
- `-config cert.cnf`: Uses the config file for CSR details.
105+
106+
### Step 5: Sign the CSR with the CA
107+
108+
This generates your server certificate from the CSR.
109+
```
110+
openssl x509 -req -in tls.csr -CA homelabCA.crt -CAkey homelabCA.key -CAcreateserial -out tls.crt -days 365 -sha256 -extfile cert.cnf -extensions v3_ext
111+
```
112+
- `-req -in tls.csr`: Uses the Certificate Signing Request (CSR) for signing.
113+
- `-CA homelabCA.crt -CAkey homelabCA.key`: Uses our CA to sign the certificate.
114+
- `-CAcreateserial`:Generates a unique serial number.
115+
- `-out tls.crt`: Saves the signed certificate.
116+
- `-days 365`: Valid for 365 days (1 year).
117+
- `-extfile cert.cnf` -extensions v3_ext → Includes Subject Alternative Names (SAN)s.
118+
119+
### Step 6: Create a Combined `tls.pem` File
120+
```
121+
cat tls.key tls.crt | tee tls.pem
122+
```
123+
124+
### Step 7: [On Pi-hole Server] Remove existing Pi-hole self-signed cert files:
125+
```
126+
sudo rm /etc/pihole/tls*
127+
```
128+
129+
### Step 8: [On Pi-hole Server] Copy `tls.pem` (cert+private key) to Pi-hole directory
130+
```
131+
sudo cp tls.pem /etc/pihole
132+
```
133+
134+
### Step 9. [On Pi-hole Server] Restart Pi-hole
135+
```
136+
sudo service pihole-FTL restart
137+
```
138+
139+
### Step 10: Install `homelabCA.crt` (CA) in Chrome (this is on your client machine running a browser, for example your Windows PC running Chrome)
140+
Import `homelabCA.crt` into your browser’s **Trusted Root Certificate Store**
141+
- Copy `homelabCA.crt` to your local PC
142+
- Open `chrome://certificate-manager` in Chrome
143+
- Click **Manage Imported Certificates**
144+
- Click **Trusted Root Certification Authorities**
145+
- Click **Import, Next, Finish**
146+
147+
### Issuing additional server certificates with your CA (Optional)
148+
You can issue additional certificates for your other servers using the CA you created in **step 2**, and you do not have to re-install the CA certificate in your browser.
149+
Just run the commands listed in **steps 4 and 5** again:
150+
151+
```
152+
openssl req -new -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 -nodes -keyout tls2.key -out tls2.csr -config cert2.cnf
153+
```
154+
```
155+
openssl x509 -req -in tls.csr -CA homelabCA.crt -CAkey homelabCA.key -CAcreateserial -out tls2.crt -days 365 -sha256 -extfile cert2.cnf -extensions v3_ext
156+
```
157+
158+
---
159+
160+
## Method 2: Use a Self-Signed Certificate and Manually Trust It
161+
- Pros: Simple, no need to set up a CA.
162+
- Cons: Must manually add each self-signed cert to your browser.
163+
164+
**Summary:** Generate a self-signed certificate and install it in your browser. You must manually trust each certificate, so this is adequate for a single server setup.
165+
166+
### Step 1: Create a directory to hold your cert, config, and key files:
167+
```
168+
mkdir -p ~/crt && cd ~/crt
169+
```
170+
171+
### Step 2: Create a Certificate Configuration File (`cert.cnf`)
172+
173+
```
174+
touch cert.cnf && nano cert.cnf
175+
```
176+
177+
Use the attached [cert.cnf](https://gist.github.com/kaczmar2/e1b5eb635c1a1e792faf36508c5698ee#file-cert-cnf) file as a template:
178+
```ini
179+
# Country Name (C)
180+
#Organization Name (O)
181+
#Common Name (CN) - Set this to your server’s hostname or IP address.
182+
183+
# SAN (Subject Alternative Name), [alt-names] is required
184+
# You can add as many hostname and IP entries as you wish
185+
186+
[req]
187+
default_md = sha256
188+
distinguished_name = req_distinguished_name
189+
req_extensions = v3_ext
190+
x509_extensions = v3_ext
191+
prompt = no
192+
193+
[req_distinguished_name]
194+
C = US
195+
O = My Homelab
196+
CN = pi.hole
197+
198+
[v3_ext]
199+
subjectAltName = @alt_names
200+
201+
[alt_names]
202+
DNS.1 = pi.hole # Default pihole hostname
203+
DNS.2 = pihole-test # Replace with your server's hostname
204+
DNS.3 = pihole-test.home.arpa # Replace with your server's FQDN
205+
IP.1 = 10.10.10.115 # Replace with your Pi-hole IP
206+
IP.2 = 10.10.10.116 # Another local IP if needed
207+
```
208+
209+
### Step 3: Generate a key and Self-Signed Certificate
210+
Use **Elliptic Curve Digital Signature Algorithm (ECDSA)** to generate both the **private key** (`tls.key`) and the **Self-Signed Certificate** (`tls.crt`).
211+
```
212+
openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 -nodes -days 365 -keyout tls.key -out tls.crt -config cert.cnf
213+
214+
```
215+
216+
- `x509`: Creates a self-signed certificate.
217+
- `-newkey ec`: Creates a new Elliptic Curve (EC) key.
218+
- `-pkeyopt ec_paramgen_curve:prime256v1`: Uses P-256 (NIST prime256v1) curve.
219+
- `-nodes`: Skips password protection.
220+
- `-days 365`: Valid for 365 days (1 year).
221+
- `-keyout tls.key`: Saves the private key.
222+
- `-out tls.crt`: Saves the self-signed certificate.
223+
- `-config cert.cnf` Uses cert configuration file `cert.cnf` defined above.
224+
225+
### Step 4: Create a Combined `tls.pem` File
226+
```
227+
cat tls.key tls.crt | tee tls.pem
228+
```
229+
230+
### Step 5: [On Pi-hole Server] Remove existing Pi-hole self-signed cert files:
231+
```
232+
sudo rm /etc/pihole/tls*
233+
```
234+
235+
### Step 6: [On Pi-hole Server] Copy `tls.pem` (cert+private key) to Pi-hole directory
236+
```
237+
sudo cp tls.pem /etc/pihole
238+
```
239+
240+
### Step 7. [On Pi-hole Server] Restart Pi-hole
241+
```
242+
sudo service pihole-FTL restart
243+
```
244+
245+
### Step 8: Install `tls.crt` (cert) in Chrome (this is on your client machine running a browser, for example your Windows PC running Chrome)
246+
Import `tls.crt` into your browser’s **Trusted Root Certificate Store**
247+
- Copy `tls.crt` to your local PC
248+
- Open `chrome://certificate-manager` in Chrome
249+
- Click **Manage Imported Certificates**
250+
- Click **Trusted Root Certification Authorities**
251+
- Click **Import, Next, Finish**
252+
253+
## Installation of Self-Signed Certs for Mobile Devices
254+
- See: Pi-hole API > [TLS/SSL](../../api/tls.md)

mkdocs.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,9 @@ nav:
203203
- 'Optional: Full and DNS-only': guides/vpn/openvpn/dual-VPN.md
204204
- 'Optional: Dynamic DNS': guides/vpn/openvpn/dynDNS.md
205205
- 'Troubleshooting': guides/vpn/openvpn/troubleshooting.md
206+
- 'TLS/SSL':
207+
- 'Creating Your Own Self-Signed SSL Certificates': guides/ssl/self-signed.md
208+
- 'Automating Certificate Renewal': guides/ssl/automatic-renewal.md
206209
- 'Misc':
207210
- 'Home Assistant': guides/misc/homeassistant.md
208211
- 'Benchmarking': guides/misc/benchmark.md

0 commit comments

Comments
 (0)