Trying to use Let's Encrypt + Cloudflare

So, my website is behind Cloudflare. I am trying to make it https.

I tried using Cloudflare SSL (Full (strict)) but no, it did not work. I tried using Let’s Encrypt’s SSL which would not work because it is behind such proxy stuff as stated in official tutorial. What I encounter is Error 521.

What I am trying to achieve is:
Public > Cloudflare SSL > Origin > Let’s Encrypt SSL > Host
Or just Let’s Encrypt or Cloudflare in the middle. It does not matter, actually.

app.yml
templates:
  - "templates/postgres.template.yml"
  - "templates/redis.template.yml"
  - "templates/web.template.yml"
  - "templates/web.ratelimited.template.yml"
  - "templates/web.ssl.template.yml"
  - "templates/web.letsencrypt.ssl.template.yml"

expose:
  - "80:80"   # http
  - "443:443" # https

params:
  db_default_text_search_config: "pg_catalog.english"
  db_shared_buffers: "128MB"

env:
  LANG: en_US.UTF-8
  UNICORN_WORKERS: 2
  DISCOURSE_HOSTNAME: censored.com
  DISCOURSE_DEVELOPER_EMAILS: 'censored@gmail.com'
  DISCOURSE_SMTP_ADDRESS: smtp.sendgrid.net
  DISCOURSE_SMTP_PORT: 465
  DISCOURSE_SMTP_USER_NAME: apikey
  DISCOURSE_SMTP_PASSWORD: "censored"
  DISCOURSE_SMTP_ENABLE_START_TLS: true
  LETSENCRYPT_ACCOUNT_EMAIL: censored@gmail.com

volumes:
  - volume:
      host: /var/discourse/shared/standalone
      guest: /shared
  - volume:
      host: /var/discourse/shared/standalone/log/var-log
      guest: /var/log

hooks:
  after_code:
    - exec:
        cd: $home/plugins
        cmd:
          - git clone https://github.com/discourse/docker_manager.git
  after_web_config:
    - replace:
        filename: /etc/nginx/nginx.conf
        from: /sendfile.+on;/
        to: |
          server_names_hash_bucket_size 64;
          sendfile on;
    - file:
        path: /etc/nginx/conf.d/discourse_redirect_1.conf
        contents: |
          server {
            listen 80 default_server;
            server_name _;
            return 301 $scheme://censored.com$request_uri;
          }
    - file:
        path: /etc/nginx/conf.d/discourse_redirect_2.conf
        contents: |
          server {
            listen 443 ssl default_server;
            server_name _;
            return 301 $scheme://censored.com$request_uri;
          }

run:
  - exec: echo "Beginning of custom commands"
  - exec: echo "End of custom commands"
2 Likes

Easiest will be to disable ssl on discourse side and let cloudflare manage ssl for you but that’s not okay at all times.

What I’ve done in my case is that I run discourse behind an nginx reverse proxy with letsencrypt ssl (in dns-01 with cloudflare dns plugin) and that makes it so that:
discourse (sockets) > nginx (ssl) > Cloudflare (ssl) > Public

3 Likes

Hi,

I have added cloudflare.template to app.yml and enabled SSL as Full (not Full Strict) in cloudflare crypto settings
Also disabled rocket loader which is working fine for me.

Ok, step one to do this involves temporarily unchecking the orange cloud and bypassing Cloudflare entirely. To issue the initial certificate Let’s Encrypt needs direct communication with your server.

Ensure that in your app.yml the following lines are uncommented:

  • “templates/web.ssl.template.yml”
  • “templates/web.letsencrypt.ssl.template.yml”

and add this one:

  • “templates/cloudflare.template.yml”

There’s little to no risk in doing this, so click on the orange cloud to disable CloudFlare, configure Let’s Encrypt. When your site is working again under HTTPS you also need to make a change within Discourse enabling the force_https setting under /admin.

Once your server is communicating via HTTPS you can change one more setting at Cloudflare if there are no other sites or applications under the same domain. Visit the ‘Crypto’ tab at Cloudflare and swap SSL from ‘Flexible’ to ‘Full (Strict)’.

Note that certain CloudFlare features are incompatible with Discourse, you’re going to need to create the following page rule:

And disable Brotli, which is under the ‘Speed’ tab of your domain:

This is neither easy, not a good idea. It’s easy to secure Discourse using Let’s Encrypt once you allow Let’s Encrypt to enrol the certificate. Troubleshooting the mixed scenario is much more hassle.

8 Likes

I don’t understand how is it not easy?
If someone is just starting out, not filling in the letsencrypt email disables ssl
And once You’ve got cloudflare proxying everything and managing ssl, pretty much all that’s left is to create a page rule and disable performance.

Because it doesn’t make the system any simpler.

Whether you encapsulate the traffic in SSL at Discourse, a reverse proxy, or via Cloudflare, Force_HTTPS needs to be enabled. In the scenario where the server talks to CF over :80 that means that any time you access the server directly (and bypass cloudflare) you’re using Discourse with Force_HTTPS enabled while HTTPS isn’t present.

Enabling HTTPs is easy, the only thing which defeats the process for CloudFlare users is the need for direct server communication during enrollment for the challenge to go through, which is also easy. It leaves the server in a consistent state whether the CF proxy is enabled, or not. There’s no inconsistency in behavior - which your suggestion would create.

And adding a reverse proxy is many orders of magnitude more complex.

3 Likes

Nobody would be here wanting to deploy cloudflare for the sake of simplicity. General implication is to increase the security bit or to use cloudflare on the rest of the website while still being able to host discourse on a subdomain (however in this case, gray cloud is the best) But there are the fanboys and you absolutely totally gotta do something for the fanboys.

Again, I disagree, CloudFlare is oft misunderstood and sold as a magic bullet for server security, which is why I see so many customer deployments with Cloudflare present and not a shred of hardening done to the local server. The perception is that you turn on CloudFlare and the rest is taken care of.

So in that case simple both describes perception of the product, and also those making the decision :D.

5 Likes

I had my own horror stories with trying to use cloudflare on Discourse so I just keep them totally unrelated. Managing your own server puts you into a very different perception than that of the end user who is scared of ssh.

You’re right. Thanks for enlightenment.

Will Let’s Encrypt continue to renew automatically within 90 days?

I am afraid Cloudflare says, Full Strict mode requires a valid SSL certificate from the trusted authority. If renew fail by chance, Full Strict Mode will throw Invalid SSL error to the visitors.

Where, Let’s Encrypt requires direct HTTP connection to the server IP.


Guess, this may be resolved via DNS auth way. But, how to enable for Discourse, Any idea?

In future, if Discourse add an option

Cloudflare email _________
Global API key _____________

Submit

We will use this information to manage your DNS for Let’s Encrypt renewal.

This would be great!

Yes. It should do. Cerbot does that. I do not think Discourse dev team would have skipped that feature.

Edit:

image

I think, It may work with Full, but not with “Full Strict”. For now, I would prefer to avoid CF for Discourse.

It works with Full (Strict).

But how actually Let’s Encrypt validate for renewal?

Through http-01 challenge

1 Like

Let’s Encrypt will connect to Cloudflare IP, not directly to origin IP. Will it work?

As far as I know it looks for a secret in the .well-known folder.

1 Like

In http-01 challenge: I doubt this whole thing because let’s encrypt cannot be installed when Cloudflare is active, so it is highly unlikely they may renew without looking up real IP.

Per
https://tools.ietf.org/html/draft-ietf-acme-acme-07#section-8.3

There is no mention of looking up for IP as long as the .well-known directory returns the correct token for validation, the certificate should be issued without any problems.

2 Likes

Correct, renewal works.

2 Likes