New installer works well, but one hostname gave me fits

First, appreciation where it is due: the new installer is a big improvement. When it works, which is most of the time, it is a much friendlier path than the older manual flow, and I am able to get clean installs through it. Run the installer, complete the registration/activation like always, then set about adjusting app.yml to my specifications. Easy peasy. Many thanks to @Falco and Team! What a huge difference from the old days of Discourse installing.

I am posting this because I also hit one hostname that gave me fits, and I think the experience may point to a few places where the installer could surface clearer information for self-hosters.

What worked

I successfully installed Discourse on a fresh server using:

  • own domain: yes
  • SMTP: yes
  • the current installer flow

The install reached:

Tallyho!
Congratulations, you installed Discourse!
Register a new account to get started.

So this is not a “the new installer is broken” post. The installer can work very nicely.

The difficult hostname

On another install, using the same general path, the target hostname was:

forum.domain.tld

The installer command was:

wget -qO- https://raw.githubusercontent.com/discourse/discourse_docker/main/install-discourse | sudo bash

The choices were roughly:

  • create 2 GB swapfile: yes
  • use my own domain: yes
  • hostname: forum.domain.tld
  • configure SMTP: yes
  • SMTP provider: SendGrid
  • SMTP port: 587

The installer reached:

[4/5] Verifying domain configuration
? Checking your domain name...
? Connection to forum.domain.tld succeeded.

It then wrote the config and rebuilt the app.

But the site did not come up cleanly in the browser. The symptom eventually became:

forum.domain.tld refused to connect

Repeated rebuild/retry attempts did not clear it.

Discourse Doctor result

./discourse-doctor found the app container and the expected config values. The container was running and ports 80/443 appeared to be bound.

But it reported:

Discourse version at forum.domain.tld: NOT FOUND

and later:

Discourse version at localhost: NOT FOUND

That made the problem feel different from ordinary public DNS propagation alone.

ACME rate limit

Earlier in the troubleshooting path, I also attempted installs using the Discourse service-assisted paths:

  • DiscourseID
  • the yoursite.discourse.diy flow

That is where the repeated server-hammering/retry behavior happened, and where the ACME log showed a Let’s Encrypt rate limit:

type: urn:ietf:params:acme:error:rateLimited
status: 429
detail: too many certificates (5) already issued for this exact set of identifiers...

The useful log path was:

/shared/letsencrypt/acme.sh.log

This was a big lesson. From the browser, the failure looked like a generic reachability issue. But the real blocker at that point was certificate issuance.

The most confusing part was that the install-complete/final status block did not surface this as an actionable error. The final user-facing symptom was just that the site refused the browser connection.

Later checking showed the failure chain more clearly:

ACME 429 rate limit
-> zero-byte .cer files under /shared/ssl
-> nginx tries to load the zero-byte cert
-> nginx fails startup
-> ports 80/443 refuse
-> browser says connection refused

Feature request buried in the experience:

It would be very helpful if the installer/rebuild routine checked /shared/letsencrypt/acme.sh.log after the cert step and surfaced rate-limit errors such as:

rateLimited
too many certificates
status: 429

For example:

Let's Encrypt rate limit hit for this hostname.
Wait until the retry-after time shown in /shared/letsencrypt/acme.sh.log before retrying.
Repeated rebuilds may not help.

That would save users from chasing DNS, SMTP, app.yml quoting, Docker, or firewall issues when the actual problem is ACME.

After the rate limit cleared

After the Let’s Encrypt rate-limit window had cleared, I still saw a confusing domain validation situation.

The installer reported:

[4/5] Verifying domain configuration
? Checking your domain name...
? Connection to forum.domain.tld succeeded.

But a local DNS lookup still showed:

Resolve-DnsName -Name "forum.domain.tld"

with:

Resolve-DnsName: forum.domain.tld : DNS name does not exist.

How can those two things coexist?

I can imagine several possibilities:

  • the server and workstation were using different recursive resolvers
  • one resolver had stale NXDOMAIN cached
  • DNS propagation was partial at that moment
  • the installer checks something other than a plain DNS lookup
  • the installer or a related service had cached validation state

I am not claiming which one is true. I am mainly noting that from the user’s seat, the installer saying “connection succeeded” can make later DNS or reachability errors harder to interpret.

DNS isolation check

To test whether this was just slow Cloudflare propagation, I added another record in the same zone:

test.domain.tld

Within a few moments, public DNS checker results were green.

That made me less confident that general Cloudflare propagation was the whole issue. It looked more like the problem was specific to forum.domain.tld.

Comparison installs

I also had a successful install on another hostname:

discourse.domain2.tld

using the same general installer path.

Another test hostname, for DNS diagnostics, was:

forum.domain3.tld

The comparison installs are what pushed me away from “the new installer is broken” and toward “something hostname-specific happened here.”

Current theory

My current theory, not proven, is that forum.domain.tld may have had some hostname-specific cached/reserved/remembered state somewhere outside the server itself.

Places I wondered about:

  • DiscourseID
  • the yoursite.discourse.diy flow
  • installer-side domain validation
  • some cached relationship between a previous setup attempt and the hostname

The reason I am wondering about those service-assisted paths is that I had previously tried them with the same problem hostname, and that was also the path where the repeated attempts eventually hit the Let’s Encrypt rate limit.

Again, this is a hypothesis, not a conclusion.

Questions

  1. Does the new installer contact a Discourse-controlled service during own-domain installs?
  2. Does DiscourseID or the discourse.diy flow reserve, remember, or cache hostnames?
  3. Is there any release/reset path for a hostname that was previously used or attempted during setup?
  4. What exactly does [4/5] Verifying domain configuration check?
  5. Could the installer surface ACME rate-limit failures more clearly before the final status/result block?

What would have helped

Three things would have made the troubleshooting path much clearer:

  1. A clear installer warning when /shared/letsencrypt/acme.sh.log contains a rate-limit failure.
  2. A short explanation of what the domain verification step actually checks.
  3. If any DiscourseID / discourse.diy / installer-side hostname cache or reservation exists, a visible way to inspect or release that state.

Thanks again for the work on the new installer. It really does feel like the right direction. I am posting this in that spirit: it worked beautifully when it worked, and the rough edge here seems like the kind of thing that better installer messaging could make much easier to diagnose.

Written with my inputs by my new BFF Codex.

I am in Let’s Encrypt rate-limit jail until:

2026-07-09 23:25:18 UTC

and, like Alcatraz, breaking out is not an option. I will resume testing and report back later.

If someone on the Discourse side is able to check whether there is any cached, reserved, or remembered state for forum.domain.tld in the DiscourseID / discourse.diy / installer flow, that would be helpful too.

Regarding the Let’s Encrypt, this is a very common issue when someone tries to emit too many certificates in a short burst. Won’t ever affect people who do the install via the easy path in a single stroke, but it is a recurrent issue affecting people who do many installs while testing stuff.

My plan is to move us away from acme.sh very soon into nginx native acme support, which should make it easier to surface this issue.

That’s blocked on Update to trixie - Pull Request #1048 - discourse/discourse_docker - GitHub