Need help with dual container. Issue with LetsEncrypt for a few days now

I’m getting to that point of desperation, because trying to have the Discourse Bot or Claude to fix this issue, seems impossible. I can’t really explain the issue, because I’m not that knowledgable, and I believe that’s what is really bothering me.

I will try to explain what happened, from my point of view.

When I was converting from single container to dual container, the file in samples/ used web-only and I left it by mistake instead of using web_only.

Then, because of that (I believe), my images weren’t loading, because one “thing” was expected to point to web_only, but it was set to web-only. Made some changes and the images were fixed. not the issue is the LetsEncrypt certificates.

I asked the bot to help me fix it, it told me to wait for the next day, because the issue was the certificates rate-limit. The issue was gonna get fixed. It didn’t. Then asked it again, then asked Claude, then Claude again… and we’ve been in this “wait until tomorrow at X hours and it WILL get fixed” for the past week. It never gets fixed, they both say “oh, I’m sorry, I shouldn’t have assumed it would get fixed, let’s try this instead, because now it will really get fixed”. It never does.

The website itself is up and running, but I feel that every time I want to rebuild, something will happen, and to be honest I don’t want to rely on bandaids all the time.

Claude told me to add something to the hooks in web_only.yml but since nothing like that is mentioned in the instructions provided here on the forum, I was expecting something other solution, such as… solving the actual problem.

Can someone please help me figure out what the issue is, and where things are breaking? I would really appreciate it, because it’s exhausting at this point. Not the work, but not understanding what’s happening and why the “wait until tomorrow” never seems to fix anything.

Thanks!


I asked Claude to explain what the issue seems to be, maybe that helps? Here’s what it said:

Title: Two-container setup: ECC cert folder missing after split, --force loop hitting rate limit every boot

Setup: Two containers (data + web_only), migrated from standalone. Templates: web, ratelimited, ssl, letsencrypt, cloudflare. Hostname alltiago.com, no aliases.

Symptom: Every web_only start hits the Let’s Encrypt rate limit and nginx fails to serve, returning connection errors until the ECC lines are manually removed from /etc/nginx/conf.d/outlets/server/20-https.conf.

What I found:

/shared/letsencrypt/alltiago.com_ecc/ does not exist on my install. /shared/letsencrypt/alltiago.com/ (RSA) exists and works fine, renewing normally.

In web.letsencrypt.ssl.template.yml:

cert_exists() {
  [[ "$(cd ${LETSENCRYPT_DIR}/${DISCOURSE_HOSTNAME}$1 && openssl verify -CAfile <(openssl x509 -in ca.cer) fullchain.cer | grep "OK")" ]]
}

issue_cert "ec-256"
if ! cert_exists "_ecc"; then
  issue_cert "ec-256" "--force"
fi

Because the directory is missing, cert_exists "_ecc" fails on every boot, so --force runs and requests a brand new ECC cert regardless of what’s on disk. This is via the after_ssl hook that patches /etc/runit/1.d/install-ssl, so it runs on every container start, not just bootstrap.

Result: 429 too many certificates (5) already issued for this exact set of identifiers in the last 168h. Then --installcert runs anyway against the empty directory and writes an unusable /shared/ssl/alltiago.com_ecc.cer. nginx is configured with both certs, can’t load the ECC one, and won’t serve.

Confirmed working: ACME HTTP-01 validation succeeds (tested via staging, ECC cert issued fine against letsencrypt_test, correct directory structure created). RSA cert renewed successfully today. So this is not DNS, firewall, or validation.

Questions:

  1. Is there a supported way to recreate alltiago.com_ecc/ without waiting out the rate limit?
  2. Should cert_exists returning false really trigger --force rather than a normal issue? --force bypasses the “existing valid cert” check and guarantees rate-limit exhaustion when the directory is absent.
  3. Is there a documented way to run RSA-only?

Two factual notes so the thread doesn’t go sideways: the retry date moved from Aug 27 to Aug 29 because the RSA renewal today consumed a slot in the rolling 168-hour window. And the reason nobody else reports this is that on a normal install both directories are created at first boot and the --force branch never runs.

Wait. https://alltiago.com/ seems to be working just fine. But here’s what I was going to recommend

Yes, but it’s tricky. If you request a DIFFERENT cert, you get to start your count all over again.

What I’d probably recommend is to add www to the hostname so you get certs for both (but maybe you already did that, so you could add a third name, just to get a new cert).

Set up Let’s Encrypt with multiple domains / redirects is supposed to help.

Yes, it is, because I was told to use a “bandaid” related to nginx. I can’t really explain what it is, because I don’t understand it.
But the issue is that if I then want to do a normal rebuild, I will have issues (at least, from what I was told now, if I do it before Aug 29 when, hopefully, the certificate will be reissued. At this point, I can’t truly trust any of that.

Yes, www is already there from when I first installed Discourse last year.

Now, after I pushed Claude to the limit to help me understand what’s happening, here’s what I got, and feel free to challenge that, because I’m here to learn when possible:

  • ECC, which seems to be the issue now, isn’t truly necessary, because RSA is the default and everyone will still access my website without issues, if I drop ECC completely.
  • As I said, hopefully, on Aug 29, this whole issue will be gone, once the 168h resets and the 5 cert limit is also reset:
sudo docker exec web_only grep -i "retry after" /shared/letsencrypt/acme.sh.log | tail -1
  "detail": "too many certificates (5) already issued for this exact set of identifiers in the last 168h0m0s, retry after 2026-08-29 03:43:15 UTC: see https://letsencrypt.org/docs/rate-limits/#new-certificates-per-exact-set-of-identifiers",
  • If on Aug 29 things don’t go back to normal, Claude is recommending dropping ECC. This is what it said when I asked which file would be modified and which section:

File: the copy we’re about to make, web.letsencrypt.rsa-only.template.yml (leaving your original stock file untouched as a fallback).

What gets removed inside it: this whole block, found in the /usr/local/bin/letsencrypt section of the file:

########################################################
# ECDSA cert
########################################################
issue_cert "ec-256"

if ! cert_exists "_ecc"; then
  # Try to issue the cert again if something goes wrong
  issue_cert "ec-256" "--force"
fi

LE_WORKING_DIR="${LETSENCRYPT_DIR}" ${LETSENCRYPT_DIR}/acme.sh \
  --installcert --ecc \
  -d ${DISCOURSE_HOSTNAME} \
  --fullchainpath /shared/ssl/${DISCOURSE_HOSTNAME}_ecc.cer \
  --keypath /shared/ssl/${DISCOURSE_HOSTNAME}_ecc.key \
  --reloadcmd "sv reload nginx"

That’s the entire ECC section, nothing else in the file changes. The RSA section right above it stays exactly as-is.

One more file gets touched after that: containers/web_only.yml, to point at this new copy instead of the stock template. We’ll do that as a separate, later step.

Yeah. No. I would not change any templates.

I guess the easiest way is to wait and then rebuild with the stock templates. Unless you want to get support from the AI instead of anyone else who knows how to use discourse forevermore.

I asked Claude to follow your advice by adding www as a new certificate request (if that’s what it’s called?) It seems to be working now.

When I asked which files are leftovers from this whole process, I got this:

Here’s what’s actually there, split by what’s from tonight vs. older leftovers from before this conversation:

From tonight (this session):

  • /tmp/acme.sh.txt — the script copy you asked to download, safe to delete now that you have it on your Mac
  • /tmp/crtsh.json — empty 150-byte file from the crt.sh 502 error, junk, safe to delete
  • /root/discourse-backup-20260827-1857.tar.gz — the real backup from earlier tonight (SSL/letsencrypt configs), this one’s actually worth keeping, not junk

Older, from before this conversation (Aug 23 and Aug 25), not something I put there:

  • /tmp/app.yml
  • /tmp/check.png, /tmp/check162.png, /tmp/after.png, /tmp/rendered_avatar.png

I don’t know what those older ones are for, they predate anything we did tonight, likely leftovers from an earlier troubleshooting session (yours, the bot’s, or a previous Claude chat). Do you recognize them, or want me to help figure out what they’re from before deciding whether to delete?

Nothing suspicious showed up outside /tmp and /root, the broader system scan came back clean, just normal log files.


Can I go ahead and delete all of those?

Should I then revert what I just did?

I don’t mind talking to real humans at all, but I just don’t want to ask all the questions here and flood the forum with the whole process (output/logs from Terminal), and instead I rather just come up with something that’s already “kinda” working to make the conversation a bit shorter. We all have our own lives and limited time, and I don’t want to jump to the forum right away, unless I really hit a wall, you know?

I appreciate your help!
So, right now, should I revert what I did? Do you see any issue with that approach compared to just waiting for the 29th?