I can confirm that letsencrypt renewal fails. I’ve been running a self-hosted Discourse install for years, and very strangely renewal failed for me two times in a row over the past couple of months. The second time was this morning, and so I started investigating.
I’ve traced it to the following two commits:
And relevant line linked:
There are two issues, I think.
First, return 301 https://${DISCOURSE_HOSTNAME}$request_uri; gets turned into return 301 https://<MY SERVER NAME> without a $request_uri at the end. I have verified on my self-hosted install, and also on a friend’s self-hosted install that was set up in the past week. I don’t understand how Discourse template works, so I don’t know why it gets dropped.
Second, as @lessLost mentioned, the 301 redirect is outside of the location block. I believe a server level redirect overrides all location blocks. LetsEncrypt uses http for renewals. However, any attempt to curl -I http://YOUR_DOMAIN/.well-known/acme-challenge/test will return a 301 to https, instead of a 404 (which is expected behaviour; we want a 404 not a 301).
I’ve fixed this manually on my self-hosted install, but I expect any update will override my changes. Unfortunately I don’t understand the templates enough to submit a pull request @pfaffman — or I’d do that too.
Edited to add:
I believe this is mistaken —
I’m fairly certain LetsEncrypt uses http by default (for obvious reasons, if the cert is expired then it can’t renew!) But placing the 301 at the server block level forces all requests to 301 to https, which is inconsistent with this renewal strategy.
Edit 2: Evidence for the http renewal strategy, but you may also Google around to verify this.