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.diyflow
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.diyflow - 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
- Does the new installer contact a Discourse-controlled service during own-domain installs?
- Does DiscourseID or the
discourse.diyflow reserve, remember, or cache hostnames? - Is there any release/reset path for a hostname that was previously used or attempted during setup?
- What exactly does
[4/5] Verifying domain configurationcheck? - 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:
- A clear installer warning when
/shared/letsencrypt/acme.sh.logcontains a rate-limit failure. - A short explanation of what the domain verification step actually checks.
- 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.