Apache, Let's Encrypt, and site-wide reverse proxies and HTTP redirections

August 24, 2019

Back in the days before Let's Encrypt, life was simple if you had an entire virtual host that wanted to be redirected somewhere (perhaps from its HTTP version to its HTTPS one) or served through a reverse proxy (which is our solution to various traditional problems with a shared webserver), since both of these were single directives in Apache. Then along came Let's Encrypt, where the simplest and easiest way to authenticate your control over a website is through their HTTP challenge, which requires specially handling random URLs under /.well-known/acme-challenge/. Now you want to reverse proxy or redirect everything but the Let's Encrypt challenge directory, and that is not entirely easy.

The easiest case is a reverse proxy, because there's a ProxyPass directive to say 'don't proxy this':

ProxyPass /.well-known/acme-challenge/ !
ProxyPassReverse /.well-known/acme-challenge/ !

(I'm not sure if you need the PPR rule.)

These come before your regular ProxyPass, because the first match wins as far as proxying goes. With reverse proxying not being done for this, your Alias directive can take over.

Redirection is unfortunately not so simple. The straightforward way to redirect an entire site is 'Redirect / ...', and once you put this in the configuration there is, as far as I can tell, no way to override it for some URLs. Redirect specifically acts before Alias and almost anything else, and can't be turned off for a subset of your URL space through a specific <Location> block.

If you only want to redirect the root of your site and have random URLs error out, you can use a restricted RedirectMatch that doesn't match the Let's Encrypt challenge path (or much of anything else):

RedirectMatch temp "^/$" https://<whatever>/

Apache doesn't appear to have any general support for negated regular expressions (unless it's hiding in the depths of PCRE), so you can't easily write a RedirectMatch directive that matches everything except the Let's Encrypt challenge path. You can do a more general version, for example one that skips all paths that start with '/.':

RedirectMatch temp "^/([^.].*|$)" https://<whatever>/$1

(As a disclaimer, I haven't tested this regular expression.)

If you want a HTTP redirection that specifically excludes only the Let's Encrypt challenge directory, then apparently you need to switch from plain Redirect and company to doing your redirection through mod_rewrite:

RewriteCond %{REQUEST_URI} !^/.well-known/acme-challenge/ [NC]
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=302]

(RewriteCond specifically supports negating regular expression matches.)

In theory if you're just redirecting from the HTTP to the HTTPS version of your site, you might let the Let's Encrypt challenge get redirected too. In practice I would be wary of a chicken and egg problem, where you might not be able to get Let's Encrypt to accept the redirection unless you already have a valid TLS certificate for your HTTPS site. Of course in that case you could just temporarily shut down the redirection entirely, since without a valid TLS certificate the HTTPS version is not too usable. But that requires manual action.

(Perhaps and hopefully there are other solutions that I'm missing here.)

Written on 24 August 2019.
« What happens in ZFS when you have 4K sector disks in an ashift=9 vdev
Text UIs and the problem of discoverability »

Page tools: View Source, Add Comment.
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Sat Aug 24 23:06:30 2019
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.