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.



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.

[email protected]:/etc/apache2/sites-available# sudo a2enmod rewrite
Module rewrite already enabled

[email protected]:/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 ):

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.

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 using RewriteRule 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 using RewriteRule 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 to index.php, giving the original request as a query string argument to index.php, however, the RewriteCond ensures that if the request is already for index.php, the RewriteRule 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

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.


Please enter an answer

You can mention users to notify them: @username

You can use Markdown to format your question. For more examples see the Markdown Cheatsheet.

> I’m a blockquote.

I’m a blockquote.

[I'm a link] (https://www.google.com)

I'm a link

**I am bold** I am bold

*I am italicized* I am italicized

Community Code of Conduct