So I have started to delve deep into home lab(bing) and really upped my lab set up as well. Maybe one day I’ll go over it as it’s kind of a dream come true.
Anyway, I will maybe make some posts about the physical and software stacks. But most definitely the most important and unclear part I ran into even in my entire time I’ve been messing with services is true valid TLS certificates for internal services running off private IPs easily and quickly. No import required.
So I’m so stoked that the days of browser warnings, direct IPs, cleartext HTTP or most annoyingly, iOS protections refusing to accept resolutions to private IPs, are over!
Your mileage may vary but my network topology is now far from basic and I have my hacking lab vlan separate from my home lab vlan which meant some DNS rebinding issues that if need be I can go over in the future.
Anyway, I’m using Caddy for the reverse proxies and I went with the Cloudflare route for generating the certificates.
First, create/sign into your Cloudflare account. Then Purchase/Transfer the TLD you want to use.
Now lets prep the Caddy Docker Image.
Here’s how the entry should look like in the docker-compose.xml
caddy:
build:
context: .
dockerfile: Dockerfile
# dns:
# - 1.1.1.1
# - 8.8.8.8
ports:
- "80:80"
- "443:443"
environment:
- CLOUDFLARE_API_TOKEN=${CLOUDFLARE_API_TOKEN}
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy_data:/data
- caddy_config:/config
volumes:
caddy_data:
caddy_config:
And the Dockerfile to add cloudflare DNS support:
# Build Caddy with Cloudflare DNS plugin
FROM caddy:builder AS builder
RUN xcaddy build \
--with github.com/caddy-dns/cloudflare
# Final image with custom Caddy
FROM caddy:alpine
COPY --from=builder /usr/bin/caddy /usr/bin/caddy
Now within your cloudflare account, create a new API token with the following privileges:
Zone –> Zone –> Read
Zone –> DNS –> Edit
Under Zone Resources, select specific zone and then the TLD you want to use.

FYI, you can name the token whatever you want.
Now lets create a .env file in the same directory you have the rest of the docker+caddy files. Add this entry:
CLOUDFLARE_API_TOKEN=CLOUDFLAREAPITOKENVALUENOW
Now lets set up the Caddyfile
at the top add:
{
acme_dns cloudflare {env.CLOUDFLARE_API_TOKEN}
email cloudflare@contacttlsregistration.com
}
(cloudflaredomain_tls) {
tls {
dns cloudflare {env.CLOUDFLARE_API_TOKEN}
resolvers DNS-SERVER-IP-GOES-HERE
}
}
TLD.com, *.TLD.com {
import cloudflaredomain_tls
reverse_proxy 192.168.1.111:8080
}
Now here’s an example entry:
graphs.TLD.com {
import cloudflaredomain_tls
reverse_proxy 192.168.1.111:1403
}
Within DNS server, create a new zone for the TLD you’re using:

Create entries for all subdomains (and the TLD if you’re going to use it as well)

Now I’d ensure that it resolves properly using nslookup or whatever on one of the boxes that use the DNS server.
After that, disable the zone.
Now spin up the Caddy container!
docker compose up -d
And you should see in your Cloudflare dashboard the txt verification records:

You can check the logs via:
docker compose logs caddy
And you should see it all going well.
If you run into any issues, you should uncomment the DNS entries within the docker-compose and restart the caddy container. Once the certificates are generated you can comment them out again.
Once it’s all good, go back to your DNS server and enable the zone.
And Boom! Legit trusted TLS certificates
You can confirm by navigating to one of the services via HTTPS on one of your boxes:

And one of your phones:

Now feel free to delete the Cloudflare API key and ensure that the txt records are deleted.
Disable the DNS zone, add the Cloudflare API key and restart the Caddy container when you need to generate new certificates or if you have any problems when adding new subdomains.
Enjoy!
END TRANSMISSION
