#+TITLE: d.rymcg.tech wildcard TLS with acme-dns #+PROPERTY: header-args :exports both :results both :eval never-export #+OPTIONS: noweb:t #+SETUPFILE: theme/simple_dark.theme * Introduction This article is about the mechanics of how a Docker server can be provisioned with automatic TLS certificates. [[https://github.com/EnigmaCurry/d.rymcg.tech][d.rymcg.tech]] is a large collection of open-source Docker Compose projects and CLI tools to make it easier to deploy applications and manage Docker servers from your workstation. All of the tools discussed in this article are provided via d.rymcg.tech. [[https://doc.traefik.io/traefik][Traefik]] is the service gateway used to proxy all of the installed applications and to integrate sentry auth. [[https://www.rfc-editor.org/rfc/rfc8555][ACME]] (RFC 8555) is the protocol used by a client (e.g. Traefik or acme.sh) to request and acquire TLS certificates from a Certificate Authority (e.g. Let's Encrypt or Step-CA), and to manage certificate renewals automatically. [[https://github.com/joohoi/acme-dns][acme-dns]] is a tiny DNS server limited in scope to handling ACME type DNS-01 challenges. It allows clients to register and securely update the necessary TXT records that the ACME protocol requires. When using acme-dns, you need to tell you primary DNS server to delegate some of its authority to your acme-dns instance, but only for a sub-domain, and only for the purpose of the ACME DNS-01 challenge. From a security perspective, this is a much better situation than using your DNS provider's API directly. No longer does your app server need to store a god-mode API token that controls your whole domain - acme-dns follows the principle of least privilege - the API tokens it uses can *only* be used to update a specific sub-domain's TXT records for the purposes of ACME, and cannot be used to create any other type of domain records. Your primary DNS server will require administrative action only to setup the CNAME records used to delegate its authority to acme-dns (and if you are creating a wild-card certificate for a single sub-domain, this is a one-time procedure). [[https://github.com/acmesh-official/acme.sh?tab=readme-ov-file][acme.sh]] is an ACME client written in Bash, used to request certificates on any machine or container. In this scenario, acme.sh replaces the builtin Traefik ACME client that has long been used in legacy d.rymcg.tech installations. Ripping this functionality out of the hands of Traefik gives us more control over how, when, and where certificates are created/updated. [[https://smallstep.com/docs/step-ca/][Step-CA]] is a self-hosted Certificate Authority (i.e. ACME server) that you can deploy to create a private [[https://en.wikipedia.org/wiki/Public_key_infrastructure][PKI]], without relying on Let's Encrypt or any other trust store. Your own CA won't be trusted by mainstream web browsers, so your users will need to install your Step-CA cert to make your websites appear with valid TLS, but this infrastructure let's you build your own full-stack empire, as well as evade detection from global [[https://letsencrypt.org/docs/ct-logs/][Certificate Transparency]] logs. * Overview This article will cover the following steps: 1. Setup your workstation. 2. Deploy a Docker server. 3. Setup your primary DNS. 4. Deploy Traefik and a few applications. 5. Deploy of acme-dns (or use the community instance). 6. Install TLS certificates with Let's Encrypt. 7. Install TLS certificates with Step-CA. 8. Configure Mutual TLS. * Requirements 1. A workstation computer with a Bash shell (e.g. a desktop/laptop running Linux, or Windows WSL) 2. A server (VPS) where you want to install Docker. 3. A DNS server or provider * Setup Workstation Follow [[https://github.com/enigmacurry/d.rymcg.tech][d.rymcg.tech]] instructions to setup Workstation along with the =d= alias. * Choose your acme-dns provider You may either host your own [[https://github.com/EnigmaCurry/d.rymcg.tech/tree/master/acme-dns][acme-dns]] instance, or to use the free community instance at https://auth.acme-dns.io/ (don't worry that this link shows a 404, that actually means its up!) If you choose to use the free community service, be aware that you are giving some trust in your domain to a third party and there is no guarantee of availability. If you choose to run your own acme-dns instance, you must do so on a separate machine (there would otherwise be a circular dependency between Traefik needing acme-dns, but acme-dns being served through Traefik). * Create Droplet Make sure to choose to install your workstation SSH key on the droplet. * Create Docker context on Workstation #+begin_src bash $ d context new > This command can help create a new SSH config and Docker context. Proceed? Yes > You must specify the SSH config entry to use I want to make a new SSH host entry in ~/.ssh/config > Enter the new SSH context name (short host name) : insulon > Enter the fully qualified SSH Host DNS name : 157.245.230.226 ## Here is the new SSH config entry: Host insulon Hostname 157.245.230.226 User root ControlMaster auto ControlPersist yes ControlPath /tmp/ssh-%u-%r@%h:%p ? Do you want to append this config to ~/.ssh/config? (y/N) y ? Do you want to switch to the new insulon context now? (y/N) y #+end_src * Install Docker #+begin_src bash d install-docker #+end_src * Configure d.rymcg.tech #+begin_src bash $ d config > This will make a configuration for the current docker context (insulon). Proceed? Yes ROOT_DOMAIN: Enter the root domain for this context (eg. d.example.com) : insulon.rymcg.tech Configured .env_insulon ENV_FILE=.env_insulon_default > Is this server behind another trusted proxy using the proxy protocol? No Set DEFAULT_CLI_ROUTE_LAYER_7_PROXY_PROTOCOL=false Set DEFAULT_CLI_ROUTE_LAYER_4_PROXY_PROTOCOL=false > Do you want to save cleartext passwords in passwords.json by default? No Set DEFAULT_SAVE_CLEARTEXT_PASSWORDS_JSON=false #+end_src * Configure Traefik #+begin_src bash d make traefik config #+end_src ** Config *** Traefik user Create the traefik user. *** TLS certificates and authorities **** Configure TLS certificates (make certs) ***** Create a new certificate Create a new wildcard certificate for your domain: #+begin_src Enter the main domain (CN) for this certificate (eg. `d.rymcg.tech` or `*.d.rymcg.tech`) : insulon.rymcg.tech Now enter additional domains (SANS), one per line: Enter a secondary domain (enter blank to skip) : *.insulon.rymcg.tech Enter a secondary domain (enter blank to skip) : Main domain: insulon.rymcg.tech Secondary (SANS) domains: *.insulon.rymcg.tech #+end_src Choose =Done=. **** Configure ACME (Let's Encrypt or Step-CA) ***** Acme.sh + acme-dns ****** Let's Encrypt (production) #+begin_src > Which ACME provider do you want to use? Acme.sh + ACME-DNS (new; recommended!) Set TRAEFIK_ACME_ENABLED=false Set TRAEFIK_STEP_CA_ENABLED=false Set TRAEFIK_ACME_SH_ENABLED=true Set TRAEFIK_ACME_CHALLENGE=dns > Which ACME server should acme.sh use? Let's Encrypt (production) Set TRAEFIK_ACME_SH_ACME_CA=acme-v02.api.letsencrypt.org Set TRAEFIK_ACME_SH_ACME_DIRECTORY=/directory Set TRAEFIK_ACME_SH_TRUST_SYSTEM_STORE=true TRAEFIK_ACME_SH_ACME_DNS_BASE_URL: ACME-DNS base URL (e.g. https://auth.acme-dns.example.net) (eg. https://auth.acme-dns.io) : https://auth.acme-dns.io TRAEFIK_ACME_SH_DNS_RESOLVER: Trusted DNS resolver IP used inside acme-sh container (eg. 1.1.1.1) : 1.1.1.1 TRAEFIK_ACME_SH_CERT_PERIOD_HOURS: Validity target in hours (e.g. 48 for Step-CA, 2160 for LE) (eg. 1440) : 1440 Set TRAEFIK_ACME_SH_ACMEDNS_ACCOUNT_JSON=/acme.sh/acmedns-account.json TRAEFIK_ACME_SH_ACMEDNS_ALLOW_FROM: acme-dns allow_from (JSON array or comma list; blank to skip) : #+end_src *** Create DNS records (CNAME and A) Look for the CNAME records output to the screen, e.g.: #+begin_src ### EXAMPLE: Create these CNAME records (on your root domain's DNS server) BEFORE traefik install: _acme-challenge.insulon.rymcg.tech. CNAME 615b56da-6105-4b80-baee-7612decd3b06.auth.acme-dns.io. #+end_src You must create the =CNAME= record on your root domain's DNS server. You must also create a wildcard =A= record for your clients to access the services, e.g.: #+begin_src ### EXAMPLE: *.insulon.rymcg.tech. A 123.123.123.123 #+end_src *** Install Traefik Go back to the main menu and choose =Install (make install)= *** Check acme-sh logs for issuance of the certificate #+begin_src bash d make traefik logs service=acme-sh #+end_src Look in the log for the certificate to be successfully issued: #+begin_src acme-sh-1 | 2025-09-12T18:16:01.965738376Z acme-sh-1 | 2025-09-12T18:16:01.970307171Z [entrypoint:acme-sh] Public ACME CA detected (acme-v02.api.letsencrypt.org); skipping TOFU and using system trust. acme-sh-1 | 2025-09-12T18:16:01.970328612Z [entrypoint:acme-sh] Using system trust store only: /etc/ssl/certs/ca-certificates.crt acme-sh-1 | 2025-09-12T18:16:02.291928260Z [entrypoint:acme-sh] dns_acmedns: hydrated missing envs from /acme.sh/acmedns-account.json acme-sh-1 | 2025-09-12T18:16:02.292281439Z [entrypoint:acme-sh] ACME server: https://acme-v02.api.letsencrypt.org/directory acme-sh-1 | 2025-09-12T18:16:02.292487082Z [entrypoint:acme-sh] Target validity: +1440h acme-sh-1 | 2025-09-12T18:16:02.292689059Z [entrypoint:acme-sh] Let's Encrypt detected; skipping --valid-to (LE does not support NotBefore/NotAfter). acme-sh-1 | 2025-09-12T18:16:02.991015073Z [entrypoint:acme-sh] Requesting certificate: acme-sh-1 | 2025-09-12T18:16:02.991023715Z [entrypoint:acme-sh] CN: insulon.rymcg.tech acme-sh-1 | 2025-09-12T18:16:02.991026764Z [entrypoint:acme-sh] SANs: *.insulon.rymcg.tech acme-sh-1 | 2025-09-12T18:16:04.468239771Z [Fri Sep 12 18:16:04 UTC 2025] Using CA: https://acme-v02.api.letsencrypt.org/directory acme-sh-1 | 2025-09-12T18:16:04.585778816Z [Fri Sep 12 18:16:04 UTC 2025] Account key creation OK. acme-sh-1 | 2025-09-12T18:16:04.747781785Z [Fri Sep 12 18:16:04 UTC 2025] Registering account: https://acme-v02.api.letsencrypt.org/directory acme-sh-1 | 2025-09-12T18:16:05.311626804Z [Fri Sep 12 18:16:05 UTC 2025] Registered acme-sh-1 | 2025-09-12T18:16:05.379359119Z [Fri Sep 12 18:16:05 UTC 2025] ACCOUNT_THUMBPRINT='I4UN5usfnES9PFCVRQ_-BAjb-Lo_QVyVOI7zlEbxcLU' acme-sh-1 | 2025-09-12T18:16:05.386038497Z [Fri Sep 12 18:16:05 UTC 2025] Creating domain key acme-sh-1 | 2025-09-12T18:16:05.433936403Z [Fri Sep 12 18:16:05 UTC 2025] The domain key is here: /acme.sh/insulon.rymcg.tech_ecc/insulon.rymcg.tech.key acme-sh-1 | 2025-09-12T18:16:05.502638058Z [Fri Sep 12 18:16:05 UTC 2025] Multi domain='DNS:insulon.rymcg.tech,DNS:*.insulon.rymcg.tech' acme-sh-1 | 2025-09-12T18:16:07.297929241Z [Fri Sep 12 18:16:07 UTC 2025] Getting webroot for domain='insulon.rymcg.tech' acme-sh-1 | 2025-09-12T18:16:07.468740195Z [Fri Sep 12 18:16:07 UTC 2025] Getting webroot for domain='*.insulon.rymcg.tech' acme-sh-1 | 2025-09-12T18:16:07.717317190Z [Fri Sep 12 18:16:07 UTC 2025] Adding TXT value: sQIpN5QKXCeCh5X5eVOfBTr9NvC5F8DILoaV9KxMrK0 for domain: _acme-challenge.insulon.rymcg.tech acme-sh-1 | 2025-09-12T18:16:07.727250464Z [Fri Sep 12 18:16:07 UTC 2025] Using acme-dns acme-sh-1 | 2025-09-12T18:16:08.782448051Z [Fri Sep 12 18:16:08 UTC 2025] The TXT record has been successfully added. acme-sh-1 | 2025-09-12T18:16:08.834508315Z [Fri Sep 12 18:16:08 UTC 2025] Adding TXT value: AYWMHUQL62NQGtifjwfHAN48Iy-TeOTq12LyL1I0OKU for domain: _acme-challenge.insulon.rymcg.tech acme-sh-1 | 2025-09-12T18:16:08.837331043Z [Fri Sep 12 18:16:08 UTC 2025] Using acme-dns acme-sh-1 | 2025-09-12T18:16:09.926056295Z [Fri Sep 12 18:16:09 UTC 2025] The TXT record has been successfully added. acme-sh-1 | 2025-09-12T18:16:09.929443427Z [Fri Sep 12 18:16:09 UTC 2025] Let's check each DNS record now. Sleeping for 20 seconds first. acme-sh-1 | 2025-09-12T18:16:29.942593404Z [Fri Sep 12 18:16:29 UTC 2025] You can use '--dnssleep' to disable public dns checks. acme-sh-1 | 2025-09-12T18:16:29.945972468Z [Fri Sep 12 18:16:29 UTC 2025] See: https://github.com/acmesh-official/acme.sh/wiki/dnscheck acme-sh-1 | 2025-09-12T18:16:30.006309137Z [Fri Sep 12 18:16:30 UTC 2025] Checking insulon.rymcg.tech for _acme-challenge.insulon.rymcg.tech acme-sh-1 | 2025-09-12T18:16:34.399558627Z [Fri Sep 12 18:16:34 UTC 2025] Not valid yet, let's wait for 10 seconds then check the next one. acme-sh-1 | 2025-09-12T18:16:44.804378735Z [Fri Sep 12 18:16:44 UTC 2025] Checking insulon.rymcg.tech for _acme-challenge.insulon.rymcg.tech acme-sh-1 | 2025-09-12T18:16:48.908999963Z [Fri Sep 12 18:16:48 UTC 2025] Not valid yet, let's wait for 10 seconds then check the next one. acme-sh-1 | 2025-09-12T18:16:59.178797519Z [Fri Sep 12 18:16:59 UTC 2025] Let's wait for 10 seconds and check again. acme-sh-1 | 2025-09-12T18:17:09.187850314Z [Fri Sep 12 18:17:09 UTC 2025] You can use '--dnssleep' to disable public dns checks. acme-sh-1 | 2025-09-12T18:17:09.191592674Z [Fri Sep 12 18:17:09 UTC 2025] See: https://github.com/acmesh-official/acme.sh/wiki/dnscheck acme-sh-1 | 2025-09-12T18:17:09.243596011Z [Fri Sep 12 18:17:09 UTC 2025] Checking insulon.rymcg.tech for _acme-challenge.insulon.rymcg.tech acme-sh-1 | 2025-09-12T18:17:13.332990454Z [Fri Sep 12 18:17:13 UTC 2025] Not valid yet, let's wait for 10 seconds then check the next one. acme-sh-1 | 2025-09-12T18:17:23.759202184Z [Fri Sep 12 18:17:23 UTC 2025] Checking insulon.rymcg.tech for _acme-challenge.insulon.rymcg.tech acme-sh-1 | 2025-09-12T18:17:24.155289461Z [Fri Sep 12 18:17:24 UTC 2025] Success for domain insulon.rymcg.tech '_acme-challenge.insulon.rymcg.tech'. acme-sh-1 | 2025-09-12T18:17:24.158793755Z [Fri Sep 12 18:17:24 UTC 2025] Let's wait for 10 seconds and check again. acme-sh-1 | 2025-09-12T18:17:34.167424092Z [Fri Sep 12 18:17:34 UTC 2025] You can use '--dnssleep' to disable public dns checks. acme-sh-1 | 2025-09-12T18:17:34.170488792Z [Fri Sep 12 18:17:34 UTC 2025] See: https://github.com/acmesh-official/acme.sh/wiki/dnscheck acme-sh-1 | 2025-09-12T18:17:34.222323903Z [Fri Sep 12 18:17:34 UTC 2025] Checking insulon.rymcg.tech for _acme-challenge.insulon.rymcg.tech acme-sh-1 | 2025-09-12T18:17:34.621515846Z [Fri Sep 12 18:17:34 UTC 2025] Success for domain insulon.rymcg.tech '_acme-challenge.insulon.rymcg.tech'. acme-sh-1 | 2025-09-12T18:17:34.666610500Z [Fri Sep 12 18:17:34 UTC 2025] Checking insulon.rymcg.tech for _acme-challenge.insulon.rymcg.tech acme-sh-1 | 2025-09-12T18:17:34.670995274Z [Fri Sep 12 18:17:34 UTC 2025] Already succeeded, continuing. acme-sh-1 | 2025-09-12T18:17:34.673988560Z [Fri Sep 12 18:17:34 UTC 2025] All checks succeeded acme-sh-1 | 2025-09-12T18:17:34.698678061Z [Fri Sep 12 18:17:34 UTC 2025] Verifying: insulon.rymcg.tech acme-sh-1 | 2025-09-12T18:17:35.054156018Z [Fri Sep 12 18:17:35 UTC 2025] Pending. The CA is processing your order, please wait. (1/30) acme-sh-1 | 2025-09-12T18:17:37.433224258Z [Fri Sep 12 18:17:37 UTC 2025] Success acme-sh-1 | 2025-09-12T18:17:37.460369898Z [Fri Sep 12 18:17:37 UTC 2025] Verifying: *.insulon.rymcg.tech acme-sh-1 | 2025-09-12T18:17:37.850095959Z [Fri Sep 12 18:17:37 UTC 2025] Pending. The CA is processing your order, please wait. (1/30) acme-sh-1 | 2025-09-12T18:17:40.195027089Z [Fri Sep 12 18:17:40 UTC 2025] Success acme-sh-1 | 2025-09-12T18:17:40.201499188Z [Fri Sep 12 18:17:40 UTC 2025] Removing DNS records. acme-sh-1 | 2025-09-12T18:17:40.227878562Z [Fri Sep 12 18:17:40 UTC 2025] Removing txt: sQIpN5QKXCeCh5X5eVOfBTr9NvC5F8DILoaV9KxMrK0 for domain: _acme-challenge.insulon.rymcg.tech acme-sh-1 | 2025-09-12T18:17:40.230951400Z [Fri Sep 12 18:17:40 UTC 2025] Using acme-dns acme-sh-1 | 2025-09-12T18:17:40.234062258Z [Fri Sep 12 18:17:40 UTC 2025] Successfully removed acme-sh-1 | 2025-09-12T18:17:40.263533171Z [Fri Sep 12 18:17:40 UTC 2025] Removing txt: AYWMHUQL62NQGtifjwfHAN48Iy-TeOTq12LyL1I0OKU for domain: _acme-challenge.insulon.rymcg.tech acme-sh-1 | 2025-09-12T18:17:40.266822692Z [Fri Sep 12 18:17:40 UTC 2025] Using acme-dns acme-sh-1 | 2025-09-12T18:17:40.269650406Z [Fri Sep 12 18:17:40 UTC 2025] Successfully removed acme-sh-1 | 2025-09-12T18:17:40.281446614Z [Fri Sep 12 18:17:40 UTC 2025] Verification finished, beginning signing. acme-sh-1 | 2025-09-12T18:17:40.306160284Z [Fri Sep 12 18:17:40 UTC 2025] Let's finalize the order. acme-sh-1 | 2025-09-12T18:17:40.309354833Z [Fri Sep 12 18:17:40 UTC 2025] Le_OrderFinalize='https://acme-v02.api.letsencrypt.org/acme/finalize/2656989411/427395475441' acme-sh-1 | 2025-09-12T18:17:40.905359297Z [Fri Sep 12 18:17:40 UTC 2025] Downloading cert. acme-sh-1 | 2025-09-12T18:17:40.908282353Z [Fri Sep 12 18:17:40 UTC 2025] Le_LinkCert='https://acme-v02.api.letsencrypt.org/acme/cert/06b4671559abf824dc5bb823f6816adcc524' acme-sh-1 | 2025-09-12T18:17:41.315548009Z [Fri Sep 12 18:17:41 UTC 2025] Cert success. acme-sh-1 | 2025-09-12T18:17:41.318576644Z -----BEGIN CERTIFICATE----- acme-sh-1 | 2025-09-12T18:17:41.318624706Z MIIDpDCCAyugAwIBAgISBrRnFVmr+CTcW7gj9oFq3MUkMAoGCCqGSM49BAMDMDIx acme-sh-1 | 2025-09-12T18:17:41.318632087Z CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQDEwJF acme-sh-1 | 2025-09-12T18:17:41.318637052Z ODAeFw0yNTA5MTIxNzE5MTBaFw0yNTEyMTExNzE5MDlaMB0xGzAZBgNVBAMTEmlu acme-sh-1 | 2025-09-12T18:17:41.318642014Z c3Vsb24ucnltY2cudGVjaDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABPvdpNQ0 acme-sh-1 | 2025-09-12T18:17:41.318646363Z 6k65sdZTAhZWxBN/9Jc4MSjAuvljH7/8aO9jAIG+UoahQ/QTRovFqwm9wh7gSQSV acme-sh-1 | 2025-09-12T18:17:41.318651765Z U7eLTHBbtypZgRCjggI0MIICMDAOBgNVHQ8BAf8EBAMCB4AwHQYDVR0lBBYwFAYI acme-sh-1 | 2025-09-12T18:17:41.318656878Z KwYBBQUHAwEGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFA9RNDM1 acme-sh-1 | 2025-09-12T18:17:41.318662027Z 24GI3rlOZfUg234r0+gQMB8GA1UdIwQYMBaAFI8NE6L2Ln7RUGwzGDhdWY4jcpHK acme-sh-1 | 2025-09-12T18:17:41.318667243Z MDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcwAoYWaHR0cDovL2U4LmkubGVuY3Iu acme-sh-1 | 2025-09-12T18:17:41.318672434Z b3JnLzAzBgNVHREELDAqghQqLmluc3Vsb24ucnltY2cudGVjaIISaW5zdWxvbi5y acme-sh-1 | 2025-09-12T18:17:41.318806972Z eW1jZy50ZWNoMBMGA1UdIAQMMAowCAYGZ4EMAQIBMC0GA1UdHwQmMCQwIqAgoB6G acme-sh-1 | 2025-09-12T18:17:41.318815566Z HGh0dHA6Ly9lOC5jLmxlbmNyLm9yZy8zNy5jcmwwggECBgorBgEEAdZ5AgQCBIHz acme-sh-1 | 2025-09-12T18:17:41.318821238Z BIHwAO4AdQAN4fIwK9MNwUBiEgnqVS78R3R8sdfpMO8OQh60fk6qNAAAAZk/Jbf+ acme-sh-1 | 2025-09-12T18:17:41.318826084Z AAAEAwBGMEQCICtsJRTQ3k2mh50NY5WGxzY6b6vCp4xVGh4brlBU5M/UAiBXGl0c acme-sh-1 | 2025-09-12T18:17:41.318830856Z +PxX8ujNLryZtoi9jIVYbz0hwz+EIapeOr0sfgB1ABoE/0nQVB1Ar/agw7/x2MRn acme-sh-1 | 2025-09-12T18:17:41.318836150Z L07s7iNAaJhrF0Au3Il9AAABmT8luD4AAAQDAEYwRAIgDxzo1gOy936gDA/Gworv acme-sh-1 | 2025-09-12T18:17:41.318855970Z qX2pB/QVQUIAIAmqE/YkTBwCIDskHsOxCSNUf1E5drVgns+FMtwrkeMjsB+lWgyy acme-sh-1 | 2025-09-12T18:17:41.318861388Z 00O3MAoGCCqGSM49BAMDA2cAMGQCMAC3xDSYS0TlqWiuHl/AeStLOe4vUOUG/i5I acme-sh-1 | 2025-09-12T18:17:41.318866529Z hWspA621HP9cIhQGcemu77GL0gH4SQIwBrQBATaL14gwKNqGsiCNvoJwq156mYEH acme-sh-1 | 2025-09-12T18:17:41.318884957Z VwlC9XlAcH1BNRdL0H7Vlfb1z9KxQ2dQ acme-sh-1 | 2025-09-12T18:17:41.318890370Z -----END CERTIFICATE----- acme-sh-1 | 2025-09-12T18:17:41.325677668Z [Fri Sep 12 18:17:41 UTC 2025] Your cert is in: /acme.sh/insulon.rymcg.tech_ecc/insulon.rymcg.tech.cer acme-sh-1 | 2025-09-12T18:17:41.329685309Z [Fri Sep 12 18:17:41 UTC 2025] Your cert key is in: /acme.sh/insulon.rymcg.tech_ecc/insulon.rymcg.tech.key acme-sh-1 | 2025-09-12T18:17:41.339824563Z [Fri Sep 12 18:17:41 UTC 2025] The intermediate CA cert is in: /acme.sh/insulon.rymcg.tech_ecc/ca.cer acme-sh-1 | 2025-09-12T18:17:41.343650288Z [Fri Sep 12 18:17:41 UTC 2025] And the full-chain cert is in: /acme.sh/insulon.rymcg.tech_ecc/fullchain.cer acme-sh-1 | 2025-09-12T18:17:41.536989549Z [Fri Sep 12 18:17:41 UTC 2025] The domain 'insulon.rymcg.tech' seems to already have an ECC cert, let's use it. acme-sh-1 | 2025-09-12T18:17:41.621268040Z [Fri Sep 12 18:17:41 UTC 2025] Installing cert to: /certs/insulon.rymcg.tech/cert.cer acme-sh-1 | 2025-09-12T18:17:41.628549032Z [Fri Sep 12 18:17:41 UTC 2025] Installing CA to: /certs/insulon.rymcg.tech/ca.cer acme-sh-1 | 2025-09-12T18:17:41.635783256Z [Fri Sep 12 18:17:41 UTC 2025] Installing key to: /certs/insulon.rymcg.tech/insulon.rymcg.tech.key acme-sh-1 | 2025-09-12T18:17:41.648151356Z [Fri Sep 12 18:17:41 UTC 2025] Installing full chain to: /certs/insulon.rymcg.tech/fullchain.cer acme-sh-1 | 2025-09-12T18:17:41.657532140Z [Fri Sep 12 18:17:41 UTC 2025] Running reload cmd: touch '/traefik/restart_me' acme-sh-1 | 2025-09-12T18:17:41.669247971Z [Fri Sep 12 18:17:41 UTC 2025] Reload successful acme-sh-1 | 2025-09-12T18:17:41.677056823Z [entrypoint:acme-sh] Certificate details for insulon.rymcg.tech: acme-sh-1 | 2025-09-12T18:17:41.727222044Z notBefore=Sep 12 17:19:10 2025 GMT acme-sh-1 | 2025-09-12T18:17:41.735464637Z notAfter=Dec 11 17:19:09 2025 GMT acme-sh-1 | 2025-09-12T18:17:41.735523096Z issuer=C=US, O=Let's Encrypt, CN=E8 acme-sh-1 | 2025-09-12T18:17:41.735529514Z subject=CN=insulon.rymcg.tech acme-sh-1 | 2025-09-12T18:17:41.735534692Z X509v3 Subject Alternative Name: acme-sh-1 | 2025-09-12T18:17:41.735540318Z DNS:*.insulon.rymcg.tech, DNS:insulon.rymcg.tech acme-sh-1 | 2025-09-12T18:17:41.736623193Z [entrypoint:acme-sh] Installed files under: /certs/insulon.rymcg.tech acme-sh-1 | 2025-09-12T18:17:41.739492248Z + exec crond -n -s -m off #+end_src * Install whoami Install whoami as a test to use the certificate: #+begin_src bash $ d make whoami config Configuring environment file: .env_insulon_default WHOAMI_TRAEFIK_HOST: Enter the whoami domain name (eg. whoami.example.com) : whoami.insulon.rymcg.tech > Do you want to enable sentry authorization in front of this app (effectively making the entire site private)? No $ d make whoami install #+end_src * Check the TLS cert is correctly used #+begin_src bash d script tls_debug whoami.insulon.rymcg.tech #+end_src This will connect to your whoami service and print information about the TLS certificate. The important bit to watch for is this: #+begin_src --- Certificate chain 0 s:CN=insulon.rymcg.tech i:C=US, O=Let's Encrypt, CN=E8 a:PKEY: id-ecPublicKey, 256 (bit); sigalg: ecdsa-with-SHA384 v:NotBefore: Sep 12 17:19:10 2025 GMT; NotAfter: Dec 11 17:19:09 2025 GMT 1 s:C=US, O=Let's Encrypt, CN=E8 i:C=US, O=Internet Security Research Group, CN=ISRG Root X1 a:PKEY: id-ecPublicKey, 384 (bit); sigalg: RSA-SHA256 v:NotBefore: Mar 13 00:00:00 2024 GMT; NotAfter: Mar 12 23:59:59 2027 GMT --- #+end_src This shows that Let's Encrypt issued the certificate and the validity period. * Step-CA TODO