Certbot corrupted my virtual-host .conf record.
I spun up a new Linode with Ubuntu 20 on it.
I followed all the docs to install the firewall and LAMP and put one of my domains on it (radioqsl.com) and it worked just fine. (I've done this before but not recently.)
After the DNS propagation (I don't use Linode nameservers… I use PairDomains.com as my registry) I installed certbot and ran it without any arguments or options. It ran fine.
All of a sudden the site would not resolve. It took me quite some time to track it down but what happened is that certbot injected the following into the /etc/apache2/sites-available virtual-host .conf record:
RewriteEngine on
RewriteCond %{SERVER_NAME} =radioqsl.com [OR]
RewriteCond %{SERVER_NAME} =www.radioqsl.com
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
I don't know what I did wrong but once I deleted this code the site started working just fine again.
If anyone has an idea what happened I'd love to know.
Thanks,
Al
4 Replies
That’s a standard config to redirect HTTP to HTTPS so I’m assuming you answered “yes” when Certbot asked if you wanted to force all traffic to HTTPS.
The only thing I could see that might stop that working is the Apache rewrite module not being available.
Have you tried
a2enmod rewrite
Followed by a restart?
systemctl restart apache2
mod_rewrite is a weird and wonderful thing. You can do all kinds of stuff with it…really amazing stuff. If you don't already have a copy, I suggest you acquire:
The Definitive Guide to Apache mod_rewrite by Rich Bowen
and read/understand every word of it.
It's choice quality stuff™…
-- sw
I added the code back into the .conf record for the domain.
xxxxxx@saturn:/etc/apache2/sites-available# sudo a2enmod rewrite
Module rewrite already enabled
xxxxx@saturn:/etc/apache2/sites-available# sudo systemctl restart apache2
Looks like the module was already there.
Now the code no longer breaks the site. I don't know why I get the "not found" earlier before I took out the code.
I'll just leave it in there.
In your apache2(8) configuration, you have
RewriteEngine on
RewriteCond %{SERVER_NAME} =radioqsl.com [OR]
RewriteCond %{SERVER_NAME} =www.radioqsl.com
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
I believe your problem is with the [END] flag (from apache2(8) mod_rewrite doc ):
END
Using the [END] flag terminates not only the current round of rewrite processing (like [L]) but also prevents any subsequent rewrite processing from occurring in per-directory (.htaccess
) context.L|last
The [L] flag causes mod_rewrite to stop processing the rule set. In most contexts, this means that if the rule matches, no further rules will be processed. This corresponds to the last command in Perl, or the break command in C. Use this flag to indicate that the current rule should be applied immediately without considering further rules.
If you are usingRewriteRule
in either.htaccess
files or in <Directory> sections, it is important to have some understanding of how the rules are processed. The simplified form of this is that once the rules have been processed, the rewritten request is handed back to the URL parsing engine to do what it may with it. It is possible that as the rewritten request is handled, the .htaccess file or <Directory> section may be encountered again, and thus the ruleset may be run again from the start. Most commonly this will happen if one of the rules causes a redirect - either internal or external - causing the request process to start over.
It is therefore important, if you are usingRewriteRule
directives in one of these contexts, that you take explicit steps to avoid rules looping, and not count solely on the [L] flag to terminate execution of a series of rules, as shown below.
An alternative flag, [END], can be used to terminate not only the current round of rewrite processing but prevent any subsequent rewrite processing from occurring in per-directory (.htaccess
) context. This does not apply to new requests resulting from external redirects. [n.b., emphasis added]
The example given here will rewrite any request toindex.php
, giving the original request as a query string argument toindex.php
, however, theRewriteCond
ensures that if the request is already forindex.php
, theRewriteRule
will be skipped.
RewriteBase "/" RewriteCond "%{REQUEST_URI}" "!=/index.php" RewriteRule "^(.*)" "/index.php?req=$1" [L,PT]
The way I read this is that, if you use [END] and the rule matches, no further rewrite processing that may be present in any site configuration linked in /etc/sites-enabled or .htaccess file in any site directory will occur (causing the kind of problems you had previously…which were not related to DNS or your firewall btw).
I don't think that's what you want. I think what you need to use here is the [L] (Last) flag…and move the rewrite processing from wherever you put it back in your virtual host configuration:
<VirtualHost ...>
...
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{SERVER_NAME} =radioqsl.com [OR]
RewriteCond %{SERVER_NAME} =www.radioqsl.com
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [L,NE,R=permanent]
# ^
# |
# + used to be END
#
</IfModule>
</VirtualHost>
If you had only one <VirtualHost>, certbot(1)s assumption would have been ok. However, I'll bet you don't have just one…
-- sw
P.S. It's advisable to enclose all configuration directives requiring a specific module to be loaded in an <IfModule></IfModule> pair. This way, if mod_rewrite isn't loaded, your configuration won't fail.