Search code examples
wordpressapache.htaccessvirtualhostapache2.4

How to move .htaccess rules/content to virtualhost?


I am trying to move the rules/content in the .htaccess file to the virtualhost (file of my WordPress website).

Server details - Apache 2.4 on Ubuntu 20.04.3 LTS

This is how the virtualhost file looks like after I have moved the contents of the .htaccess file -

<IfModule mod_ssl.c>
<VirtualHost *:443>
Protocols h2 http/1.1
    ServerName example.com
    ServerAlias www.example.com
    ServerAdmin webmaster@localhost
    DocumentRoot /var/www/example.com
    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined

RewriteEngine on
RewriteCond %{HTTP_HOST} ^www.example.com [NC]
RewriteRule ^(.*)$ https://example.com$1 [L,R=permanent,NC]

Include /etc/letsencrypt/options-ssl-apache.conf
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem

<Location />
# BEGIN WordPress
# The directives (lines) between "BEGIN WordPress" and "END WordPress" are
# dynamically generated, and should only be modified via WordPress filters.
# Any changes to the directives between these markers will be overwritten.
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

# END WordPress

# BEGIN Imagify: webp file type
<IfModule mod_mime.c>
        AddType image/webp .webp
</IfModule>
# END Imagify: webp file type
</Location>


</VirtualHost>
</IfModule>

My Queries:-

1. Is it the right way to do it? I mean, can we directly paste the contents of .htaccess file into the virtualhost file/directive inside <Location /> </Location> ?

2. <IfModule mod_rewrite.c> and <IfModule mod_mime.c> are used inside <IfModule mod_ssl.c>. Can we use it like this or have I made any mistakes?

The website was loading without any issues when I checked it (after restarting the Apache server) but I wanted to be sure that I am not doing anything wrong.

Thanks in advance!


Solution

    1. can we directly paste the contents of .htaccess file into the virtualhost file/directive inside <Location /> </Location>

    Not inside a <Location> block. Whilst this may "work" in this instance, it's not officially supported and other directives might break (the URL matched is the absolute file path, not the root-relative URL-path - so the first RewriteRule is not actually doing anything, since it never matches).

    However, you can directly paste the contents of the .htaccess file into an appropriate <Directory> block. And disable .htaccess overrides at the same time - otherwise any .htaccess file will override the <Directory> in the server config!

    1. <IfModule mod_rewrite.c> and <IfModule mod_mime.c> are used inside <IfModule mod_ssl.c>. Can we use it like this

    You can, however, there should be no need to. These <IfModule> wrappers should be removed. This is your server, you know whether these modules are enabled or not.

    The # BEGIN / # END comment markers are only strictly relevant in .htaccess since WordPress looks for these in order to automatically update the .htaccess file.

    For example, have it like this instead (replacing the <Location /> block):

    <Directory /var/www/example.com>
        Require all granted
    
        # Disable .htaccess overrides
        AllowOverride None
    
        # BEGIN WordPress
        RewriteEngine On
        RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
        RewriteBase /
        RewriteRule ^index\.php$ - [L]
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteRule . /index.php [L]
        # END WordPress
    
        # BEGIN Imagify: webp file type
        AddType image/webp .webp
        # END Imagify: webp file type
    </Directory>
    

    In your <VirtualHost> you are not actually permitting access (ie. Require all granted) - I have added this here. But I assume this must be enabled in a parent config somewhere for this to be working?

    Aside: I'm not sure why WordPress write the directives like this, but the RewriteBase directive is not being used here (and should be removed entirely IMO). The slash prefix on the last RewriteRule substitution can also be removed (this makes the code much more portable).

    For example:

    # BEGIN WordPress
    RewriteEngine On
    RewriteRule ^ - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
    
    RewriteRule ^index\.php$ - [L]
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule . index.php [L]
    # END WordPress
    

    (I also change the .* regex to simply ^ on the first RewriteRule - this is just a more efficient regex, since we don't need to actually match anything here.)


    Alternative - directly in the <VirtualHost>

    The alternative is to move the directives directly into the <VirtualHost> container (not in a directory context). However, this requires some changes since the directives are processed much earlier (before the request is mapped to the filesystem) and the URL-paths matched (and written to) are now always root-relative (starting with a slash), instead of being relative. There is also no "looping" by the rewrite engine, unless this is explicitly triggered. The RewriteBase directive is not permitted in this context (and results in an error).

    For example:

    # BEGIN WordPress
    RewriteEngine On
    RewriteRule ^ - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
    
    RewriteCond %{LA-U:REQUEST_FILENAME} !-f
    RewriteCond %{LA-U:REQUEST_FILENAME} !-d
    RewriteRule ^/. /index.php [L]
    # END WordPress
    
    # BEGIN Imagify: webp file type
    AddType image/webp .webp
    

    The LA-U: prefix creates a look-ahead in order to determine the final value of the REQUEST_FILENAME variable (otherwise this is the same as the REQUEST_URI server variable).

    However, strictly speaking, you should still have a <directory /var/www/example.com> container in order to allow access and disable .htaccess overrides.