See my other guides for SSL certificates on Pi-hole v6:
Pi-hole v6 introduces changes to its web server:
- Embedded Web Server – Pi-hole no longer relies on
lighttpd
. - TLS Configuration – Certificates must be in PEM format containing both the private key and certificate.
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.
This guide uses:
- acme.sh: An ACME shell script.
- Cloudflare DNS.
- Let’s Encrypt.
- Pi-hole v6 installed and running on your system.
- A Cloudflare account that manages your domain’s DNS records.
- Control of a registered domain (e.g.,
mydomain.com
).
These prerequisites ensure that you can successfully request and install an SSL certificate using Cloudflare DNS validation with acme.sh
.
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, including ZeroSSL. Simply update the --dns
and --server
flags accordingly when issuing your certificate.
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.
Run a login shell as root:
sudo -i
Install it:
curl https://get.acme.sh | sh -s [email protected]
Reload .bashrc to register the acme.sh alias:
source .bashrc
Verify installation:
acme.sh --version
For DNS-based domain verification, export your Cloudflare API token:
export CF_Token="ofz...xxC"
export CF_Email="[email protected]"
This allows acme.sh
to create the required DNS records automatically.
Run:
acme.sh --issue --dns dns_cf -d ns1.mydomain.com --server letsencrypt
This generates:
- Private key:
ns1.mydomain.com.key
- Full-chain certificate:
fullchain.cer
(includesns1.mydomain.com.cer
+ca.cer
, in that order)
You do not need these other certificate files:
- Server certificate:
ns1.mydomain.com.cer
(included infullchain.cer
) - Intermediate CA cert:
ca.cer
(included infullchain.cer
)
Pi-hole requires a PEM file containing both the private key and server certificate.
Install the certificate:
acme.sh --install-cert -d ns1.mydomain.com \
--reloadcmd "sudo rm -f /etc/pihole/tls* && \
sudo cat fullchain.cer ns1.mydomain.com.key | sudo tee /etc/pihole/tls.pem && /
sudo service pihole-FTL restart"
This:
- Deletes old certificates (
/etc/pihole/tls*
). - Creates
tls.pem
with both the full-chain certificate file and private key, in that order. - Restarts Pi-hole FTL to apply the new certificate.
To avoid domain mismatch warnings (CERTIFICATE_DOMAIN_MISMATCH
), set the correct hostname:
sudo pihole-FTL --config webserver.domain 'ns1.mydomain.com'
sudo service pihole-FTL restart
Fixes:
CERTIFICATE_DOMAIN_MISMATCH SSL/TLS certificate /etc/pihole/tls.pem does not match domain pi.hole!
- Your certificate renews automatically via
acme.sh
's cron job. - You can manually renew with:
acme.sh --renew -d ns1.mydomain.com --force
- To check your certificate:
sudo openssl x509 -in /etc/pihole/tls.pem -text -noout
acme.sh --issue --dns dns_cf -d ns1.mydomain.com --server letsencrypt
Missing info when using cloudfare - would be nice to have cloudfare only guide