How to use rewrite rule to create exception rule for https redirection for directory ./well-known

All we need is an easy explanation of the problem, so here it is.

Here is my situation:

  • Server A: support.example.com -> port 80 is forwarded to this server
  • Server B: hr.example.com

Both are running apache2.

For server B I want to use Let’s encrypt. I want to redirect all HTTP requests to HTTPS except for location ./well-known/acme-challenge in order to be able to renew certificate.

Here is my virtualhost of server A:

<VirtualHost *:80>
  ServerName hr.example.com
  Redirect / https://hr.example.com

  RewriteEngine on
  RewriteRule ^"/.well-known/acme-challenge\$" "<IP-SERVER B>/.well-known/acme-challenge" [PT]
</VirtualHost>

But this results in requests to http://hr.example.com/.well-known/acme-challenge being redirect to HTTPS indeed.
How can I make an exception?

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

The Acme Challenge protocol that the LetsEncrypt bot uses will happily follow redirects. There is no need to reverse proxy the requests to another machine, you can simply redirect those requests there.

I would first create a specific redirect for the challenge and then redirect everything else to HTTPS:

<VirtualHost *:80>
  ServerName hr.example.com
  Redirect permanent /.well-known/acme-challenge/ http://support.example.com/.well-known/acme-challenge/
  Redirect permanent / https://hr.example.com/
</VirtualHost>

I just tested this set of rules on my server by creating this virtual host and putting hr.example.com into my /etc/hosts file as 127.0.0.1.

# curl -s --head http://hr.example.com/
HTTP/1.1 301 Moved Permanently
Location: https://hr.example.com/

# curl -s --head http://hr.example.com/.well-known/acme-challenge/foo
HTTP/1.1 301 Moved Permanently
Location: http://support.example.com/.well-known/acme-challenge/foo

It is often problematic to mix rewrite rules and redirect directives. It isn’t always clear which will be executed first. If you do want to use the proxy method, I would switch your redirect to a rewrite rule that follows the proxy directive. I changed your rewrite rule a bit too. It should be a proxy rule ([P]) not a pass-through rule ([PT]). You also need to proxy every file within that challenge directory, not just the directory itself.

<VirtualHost *:80>
  ServerName hr.example.com    
  RewriteEngine on
  RewriteRule ^/.well-known/acme-challenge/(.*) http://<IP-SERVER B>/.well-known/acme-challenge/$1 [P,L]
  ProxyPassReverse /.well-known/acme-challenge/ http://<IP-SERVER B>/.well-known/acme-challenge/
  RewriteRule /(.*) https://hr.example.com/$1 [R=301,L]      
</VirtualHost>

I blogged about similar problems that I had. A trick that I found helpful but which doesn’t appear to exactly match your situation was to create an exception to proxy rules. If you are reverse proxying your entire site but you want to make an exception to handle the acme challenge locally (or allow it to be redirected) you can prevent the proxying of that directory with:

# Don't allow this directory to be reverse proxied
ProxyPass /.well-known/acme-challenge/ !

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply