Two real, verified findings from actually testing the "let Caddy issue a
self-signed cert automatically" approach against a literal IP:
1. TLS SNI is not sent for literal IP connections (out of spec — SNI's
HostName type explicitly excludes IPs). Confirmed via openssl s_client:
the handshake fails with a TLS-layer internal_error, even though Caddy
logs "certificate obtained successfully" — Caddy has no way to select a
cert without SNI. No Caddyfile config fixes this; the address has to be
a hostname.
2. Caddy's automatic-HTTPS heuristic only treats bare IPs and "localhost"
as obviously-private. Any other name — including a made-up LAN hostname
like "bookstore-staging.test" — it assumes might be real and tries
Let's Encrypt, which fails the same way staging.example.com did.
Fixed by forcing `tls internal` explicitly in Caddyfile.staging,
removing the guesswork entirely.
Verified end-to-end with curl --resolve (proper SNI, no real DNS/hosts
change needed to test): direct HTTPS 200, HTTP->HTTPS redirect chain 200.
README now documents the /etc/hosts requirement and how to trust Caddy's
root cert to skip the one-time browser warning.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>