X Marks the Spot

random commentary on life, the universe, and anything

WordPress, pretty permalinks, and 404s (part 2)


As I noted back in September 2017, I switched from Rackspace to Amazon Lightsail for my personal website as well as for a learning management system I run for Harbor-UCLA Pediatrics.

I’m using apache virtual hosts run both in separate subdirectories. One problem I had, but didn’t have time to fix (and then forgot about), was that turning on pretty permalinks in WordPress broke the learning management system. I knew two things: 1) it was probably a .htaccess issue and 2) my VirtualHost config was probably making a mess of things.

So why now? I have this lovely short domain (fu.fyi) doing nothing, I thought I’d use it as a custom URL shortener through bit.ly. I can set a default 404 for bad links in bit.ly so I thought I’d just use the themed WP one. But then I realized that the 404 being shown was the default apache 404 page. Which meant that I had to figure out why missing pages were not being passed to the WP stack. Which meant fixing .htaccess and httpd.conf.

Giving WordPress Its Own Directory
This is the .htaccess code in WordPress. Can someone explain how it works?
A really lovely online .htaccess checker: https://htaccess.madewithlove.be/

The WP default .htaccess is pretty straightforward.

# BEGIN WordPress

RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]

# END WordPress

What they don’t tell you is that you break things when you duplicate RewriteRules in both VirtualHost configs and .htaccess. So cleaning httpd.conf up:

# lms hosting
<VirtualHost *:80>
   ServerName lms.domain2.com
# redirect all HTTP traffic to HTTPS
   RewriteEngine on
   RewriteCond %{SERVER_NAME} =lms.domain2.com
   RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]

<VirtualHost *:443>
   ServerName lms.domain2.com
   DocumentRoot "/var/www/html/lms"
   <Directory "/var/www/html/lms">
      Options -Indexes +FollowSymLinks
      Require all granted
   Include /etc/letsencrypt/options-ssl-apache.conf
   SSLCertificateFile /etc/letsencrypt/live/domain1.com/fullchain.pem
   SSLCertificateKeyFile /etc/letsencrypt/live/domain1.com/privkey.pem

And adding a catch-all to .htaccess before the WP default:

# Turn on rewrites
RewriteEngine On

# Ruleset 1 - rewrite URI to wordpress subdir
# apply to URLs in this domain
RewriteCond %{HTTP_HOST} ^(www.)?fuweb.com$
# Don't apply (!) to URI with this subdirectory in the path
RewriteCond %{REQUEST_URI} !^/fuweb/
# Don't apply (!) to URLs that go to existing files (-f) or folders (-d)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# Take (everything), call it $1, and remap URI to include /subdir
# ^ = beginning anchor
# (.*) = . [single character] * [wildcard]
# $ = end anchor
RewriteRule ^(.*)$ /fuweb/$1

# Ruleset 2 - rewrite any URI paths to wordpress index.php
# apply to URLs in this domain
RewriteCond %{HTTP_HOST} ^(www.)?fuweb.com$
# if the URI has a / then send to index.php
RewriteRule ^(/)?$ fuweb/index.php [L] 

And the best thing? I actually understand .htaccess better now.

Oh yeah. And it works.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.