This is a continuation of the previous note DNS and SSL at Home.
Here is how to actually configure the central Caddy and all the others to use a single self-signed certificate authority.
Central Caddy
Caddyfile:
https://ca.internal.example.com {
bind 192.168.1.1
acme_server {
lifetime 768h
allow {
domains internal.example.com *.internal.example.com
ip_ranges 192.168.1.0/24 127.0.0.0/8 ::1/128
}
}
tls internal
# EST (RFC 7030)
@est_cacerts path /.well-known/est/cacerts /cacerts
handle @est_cacerts {
root * /opt/etc/caddy/tpl
rewrite * /cacerts.pem
header Content-Type "application/x-pem-file"
templates {
mime application/x-pem-file
}
file_server
}
root * /opt/share/caddy/pki/authorities/local
@certs path /root.crt /intermediate.crt
handle @certs {
header Content-Disposition "attachment; filename={http.request.uri.path.file}"
file_server
}
@fallback not path /acme/*
handle @fallback {
respond "use /root.crt , /intermediate.crt or /.well-known/est/cacerts" 200
}
}
192.168.1.1 {
tls internal
root * /opt/share/caddy/start
file_server
}
:80 {
root * /opt/share/caddy/start
file_server
}
/opt/etc/caddy/tpl/cacerts.pem:
{{- httpInclude "/root.crt"}}{{httpInclude "/intermediate.crt" -}}
Secondary Caddy Instances
Caddyfile:
{
# Key line — point to the internal CA instead of Let's Encrypt
acme_ca https://ca.internal.example.com:8443/acme/local/directory
}
app1.internal.example.com {
reverse_proxy 127.0.0.1:8080
}
app2.internal.example.com {
reverse_proxy 127.0.0.1:8081
}
Computers
# Download
curl -kfL -o ./ca-internal-example-com.crt https://ca.internal.example.com/root.crt
curl -kfL -o ./ca-internal-example-com.pem https://ca.lan.stepin.ru/.well-known/est/cacerts
# Debian/Ubuntu:
sudo cp ca-internal-example-com.crt /usr/local/share/ca-certificates/
sudo update-ca-certificates
# RHEL/Rocky/Alma:
sudo cp ca-internal-example-com.crt /etc/pki/ca-trust/source/anchors/
sudo update-ca-trust
# Macos
sudo security add-trusted-cert \
-d \
-r trustRoot \
-k /Library/Keychains/System.keychain \
./ca-internal-example-com.pem
sudo security find-certificate -c "Caddy Internal CA" /Library/Keychains/System.keychain
# Firefox
brew install nss
PROFILE=$(ls -d ~/Library/Application\ Support/Firefox/Profiles/* 2>/dev/null | head -1)
echo "profile: $PROFILE"
# Add the CA with trust C,T,C (trusted for SSL/TLS)
certutil -A \
-n "Caddy Internal CA" \
-t "C,T,C" \
-i ./ca-internal-example-com.pem \
-d sql:"$PROFILE"
certutil -L -d sql:"$PROFILE" | grep -i caddy
# Windows
# Win+R → certlm.msc → Trusted Root Certification Authorities → Certificates → right-click → All Tasks → Import.
A few words about security: Caddy is configured to issue certificates only for internal IPs and the home network domain. So it should be quite safe to add it to the system.
Testing
curl -k https://ca.lan.stepin.ru/.well-known/est/cacerts
curl -sk https://ca.internal.example.com:8443/acme/local/directory | jq .
curl -v https://app1.internal.example.com/ 2>&1 | grep -E "subject|issuer|expire"