Home Docs Dev HTTPS & .test

Dev HTTPS with .test domains

Trusted local TLS in five minutes — no browser warnings, no Let’s Encrypt rate limits.

Why .test? RFC 2606 reserves it for testing — it will never resolve on the public internet, so you can hand out names like crm.solisoft.test to anything on your LAN with zero risk of collision.

Why mkcert? It installs a development root CA into your OS trust store. Browsers and curl trust certs it signs, so HTTPS “just works” locally without the --insecure dance.

1

Install mkcert

Pick the recipe for your client machine — the laptop you’ll be browsing from. The CA needs to be installed on every device that talks to the proxy.

macOS
# Homebrew
brew install mkcert nss
mkcert -install

nss is needed for Firefox.

Linux
# Debian/Ubuntu
sudo apt install libnss3-tools
brew install mkcert     # or build from source
mkcert -install

Linuxbrew works; or grab a release binary from the mkcert repo.

Windows
# Chocolatey or Scoop
choco install mkcert
mkcert -install

Run the install once with admin rights.

Verify
mkcert -CAROOT
# prints the directory holding rootCA.pem — remember it,
# the same path will be used as --cacert by curl below.
2

Generate a wildcard cert

One cert per parent domain covers every subdomain. The proxy will pick it for any SNI one label deep (per RFC 6125).

terminal
mkcert \
  -cert-file _wildcard.solisoft.test.cert.pem \
  -key-file  _wildcard.solisoft.test.key.pem  \
  # SAN list — cover the parent and one label deep
  "*.solisoft.test" "solisoft.test"

Naming matters. The proxy looks for files literally named _wildcard.<parent>.cert.pem + _wildcard.<parent>.key.pem. Don’t rename them, don’t put them in a subdirectory.

3

Install on the proxy

Copy the pair into the proxy’s tls.cache_dir (default ./certs/) and restart the proxy.

scp _wildcard.solisoft.test.{cert,key}.pem  proxy-host:/path/to/proxy/certs/

# Restart — cert files are scanned ONCE at startup.
# SIGUSR1 and POST /api/v1/reload only refresh routing.
ssh proxy-host 'kill "$(cat /path/to/proxy/proxy.pid)" && soli-proxy --dev -d'

Cert files are not hot-reloaded. Adding, replacing, or removing a cert file requires a full proxy restart. The reload endpoints (SIGUSR1, POST /api/v1/reload) re-parse config.toml and routing only.

On startup the proxy log should now contain:

Loaded wildcard certificate for *.solisoft.test
4

Resolve .test to the proxy

Pick whichever fits your setup — the proxy doesn’t care which you use.

Quick — per-host hosts file
# /etc/hosts (macOS, Linux)
192.168.1.30  soli.solisoft.test \
              crm.solisoft.test \
              www.delupay.test

Good for one or two devices, painful at scale.

Recommended — dnsmasq wildcard
# /etc/dnsmasq.d/test.conf
address=/.test/192.168.1.30

Resolves any *.test name — no per-host edits.

No DNS at all? Use curl --resolve
curl --resolve soli.solisoft.test:443:192.168.1.30 \
     https://soli.solisoft.test/
5

Verify

curl -v \
     --cacert "$(mkcert -CAROOT)/rootCA.pem" \
     --resolve soli.solisoft.test:443:192.168.1.30 \
     https://soli.solisoft.test/

# Look for:
#   * Server certificate: ...
#   *  SSL certificate verify ok.

In the browser, hit the URL directly — you should see a normal padlock with no warning. If you see “Not Secure”, your client doesn’t trust the mkcert CA: re-run mkcert -install and restart the browser.

6

Troubleshooting

How the proxy picks a cert

On every TLS handshake the resolver tries, in order:

  1. Exact match: certs/<sni>.cert.pem
  2. Wildcard, one label deep: certs/_wildcard.<parent>.cert.pem
  3. Self-signed fallback: certs/self-signed.cert.pem (auto-generated)

curl says bad signature

Almost always means mkcert’s root CA was regenerated (e.g. you ran mkcert -uninstall && mkcert -install, or reinstalled the OS) after you generated the cert. The new CA has the same subject DN as the old one but a different key, so leaf certs signed by the old key no longer verify.

Run this on the client to confirm:

echo | openssl s_client -servername soli.solisoft.test \
     -connect 192.168.1.30:443 -showcerts 2>/dev/null \
  | awk '/BEGIN CERT/,/END CERT/' > /tmp/live.pem
openssl verify -CAfile "$(mkcert -CAROOT)/rootCA.pem" /tmp/live.pem

If it prints certificate signature failure, regenerate the wildcard cert (step 2), copy it back, and restart the proxy.

Helper scripts

scripts/diag-mkcert-mac.sh Three-step diagnostic: live cert, local CA, openssl verify. Run on the client.
scripts/regen-mkcert-and-deploy.sh Regenerates the wildcards listed in PARENTS=(), scps to the proxy host, restarts the daemon, and verifies. Run on the client.

Other gotchas

  • Two-label SNI. Wildcard match is one label deep. a.b.solisoft.test will not match _wildcard.solisoft.test — either flatten the name or generate _wildcard.b.solisoft.test.
  • Cert covers parent too. Don’t forget the bare parent in the SAN list ("*.solisoft.test" "solisoft.test") if you also serve https://solisoft.test/.
  • Multiple devices. Each device that connects to the proxy needs the mkcert CA in its trust store. Generate certs on one machine and copy $(mkcert -CAROOT)/rootCA.pem to the others, then trust it locally.
  • CI / Docker. Bake rootCA.pem into the image and trust it at build time — mkcert is for development trust, not for shipping.