Recently, in one of my clients’ server, we decided to move to the traditional Apache with mod_php instead of Nginx with php-fpm, after going through the pros and cons of each setup. If you are not aware already that AllowOverride All
brings a major performance lag into the whole setup. To overcome this, we can move the rewrite rules written on any part of your site into Apache’s configuration file (apache.conf or httpd.conf or any other name depending on the distribution you use). By moving the rewrite rules into the httpd.conf, we could disable AllowOverride altogether for a particular site and make this Apache with mod_php server stack a bit faster than Nginx with php-fpm stack. Here is how you can move all the rewrite rules into your server’s config…
Combining Apache VirtulHost and WordPress Permalink Rewrite Rules
Here is the traditional virtual host configuration in Apache…
ServerAdmin DocumentRoot /www/docs/dummy-host.example.com ServerName dummy-host.example.com ErrorLog logs/dummy-host.example.com-error_log CustomLog logs/dummy-host.example.com-access_log common
And here is the traditional rewrite rules for pretty permalinks …
# BEGIN WordPress
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
# END WordPress
So, let’s combine this…
ServerAdmin DocumentRoot /www/docs/dummy-host.example.com ServerName dummy-host.example.com ErrorLog logs/dummy-host.example.com-error_log CustomLog logs/dummy-host.example.com-access_log common # BEGIN WordPress RewriteEngine On RewriteBase / RewriteRule ^index\.php$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.php [L] # END WordPress
Finally, lets test the configuration and reload the Apache server…
httpd -t && service httpd reload
> Syntax error on line 1037 of /etc/httpd/conf/httpd.conf:
> RewriteBase: only valid in per-directory config files
Oops. :) It turns out that we have to use “Directory” to insert the rewrite rules. So, here is the modified version…
ServerAdmin DocumentRoot /www/docs/dummy-host.example.com ServerName dummy-host.example.com ErrorLog logs/dummy-host.example.com-error_log CustomLog logs/dummy-host.example.com-access_log common <Directory "/www/docs/dummy-host.example.com"> # BEGIN WordPress RewriteEngine On RewriteBase / RewriteRule ^index\.php$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.php [L] # END WordPress </Directory>
Let’s see, if we could succeed this time…
httpd -t && service httpd reload
> Syntax OK
> Reloading httpd: [OK]
That’s it. Now, you can be proud to say that your Apache server with mod_php is faster than Nginx with php-fpm.
Let’s do more: Akismet .htaccess code in httpd.conf
Since version 2.5.7, Akismet introduced a new .htaccess file to block direct access to files. Let’s dive in and see what’s in it…
Order Deny,Allow
Deny from all
<FilesMatch "^akismet\.(css|js)$">
Allow from all
</FilesMatch>
Pretty simple? Yeh. Let’s put it in Apache config file…
ServerAdmin DocumentRoot /www/docs/dummy-host.example.com ServerName dummy-host.example.com ErrorLog logs/dummy-host.example.com-error_log CustomLog logs/dummy-host.example.com-access_log common <Directory "/www/docs/dummy-host.example.com"> # BEGIN WordPress RewriteEngine On RewriteBase / RewriteRule ^index\.php$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.php [L] # END WordPress </Directory> <Directory "/www/docs/dummy-host.example.com/wp-content/plugins/akismet"> Order Deny,Allow Deny from all <FilesMatch "^akismet\.(css|js)$"> Allow from all </FilesMatch> </Directory>
Final Stack
We deployed Nginx to serve the static files and Varnish to cache the dynamic content. We were still not satisfied with the performance of our server. Upon troubleshooting, we noticed that we had forgotten to remove AllowOverride All
. :)
why don’t to simple include .htaccess in apache config? like
include “path_to_your_site/.htaccess”
Good question and a nice tip! By not parsing htaccess files, there is a slight increase in security as well. Even if a hacker can modify the htaccess file, that wouldn’t be parsed by Apache, while using the method mentioned in the post.
+1. You sir, are a gentleman and a scholar. If this was reddit, I’d give you gold.
That means the ‘apache’ user will need to have read access (to the file/s being included) that is, kind of, unnecessary, due to security reasons.
Yea, let’s not give ‘apache’ read access to the folder it was configured to serve. This made my week.
Hi James,
That made my day as well. :) Realized it only when you quoted it. Updated my other reply now for better clarify.
Thanks for pointing it out.
Pothi
Just a small remark: I see you use the directory “/www/docs/dummy-host.example.com/wp-content/akismet” for protection of Akismet files, but this should be “/www/docs/dummy-host.example.com/wp-content/plugins/akismet” (so in the plugins subdirectory of wp-content, not directly under it).
Good catch. Fixed it now. Thanks Tristan!
This solved my LONG TIME problem of getting apache re-write to work! Thank you!!! Here was my final solution that your comments inspired (in case anyone is interested).
Glad to be some inspiration, Andrew!
I’ve edited your comment for better formatting of the code.
Thanks.
While there’d be no difference in terms of performance, here’s why (I think) it’s even better to add all your .htaccess rules in /etc/apache2/sites-available/example.com instead of httpd.conf:
Apache’s main configuration file is apache2.conf (located in ‘/etc/apache2’ directory). On Ubuntu this file has a directive like
Include httpd.conf
, so you can simply add all your rules in ‘/etc/apache2/httpd.conf’ and it’ll work.But that isn’t the case on Debian (even in Wheezy). For your httpd.conf rules to work, you’d first have to add the line
Include httpd.conf
in ‘/etc/apache2/apache2.conf’.I am saying this ’cause I had a hard time figuring out why the same rules placed in httpd.conf were working on Ubuntu Server, but not on Debian!
But… there’s always a
Include sites-enabled/
directive in apache2.conf. So, you can safely call ‘/etc/apache2/sites-available/example.com’ home for your site’s Virtual Host configuration as well as all the .htaccess rules (because they’ll all take effect when you doa2ensite example.com
).That’s something I learnt today. (Any thoughts against it are welcome!)
I have no thoughts on your point (because I never followed the standard directory / file name schemes; I always compile from source). However, it is interested to see your analysis on this situation.
Thanks for the comment and sharing your thoughts.
Pothi
Great solution! Thanks for share this with the word, but when i implement this on my server the CPU reaches 100%.
Sorry for my bad english., but, do you know what problem is this?
No idea, Sorry!
Hi Pothi,
thanks for your inspiration. I have two things to add that took me hours for finding the misconfiguration (or it is a bug in Apache 2.2.22).
This line did not work in my configuration, it caused a http 302 redirect.
RewriteRule . /index.php [L]
I had to enter the complete path to fix it
RewriteRule . /www/docs/dummy-host.example.co/index.php [L]
And I noticed that a RewriteEngine On in a .htaccess file did result in a 404 error. So first delete the .htaccess or comment rewriting stuff out.
Hope this helps others who are having the same problem.
Christian
Thanks for sharing, Christian!
Glad you made that comment and said “a RewriteEngine On in a .htaccess file did result in a 404 error.”.
Pretty sure I’m having the same issue, was trying to move the standard WordPress rules from the .htaccess file to the conf file, but kept getting 404 errors. Made no sense at all!
I was moving rules in batches and the W3 Total Cache Plugins Page Cache rules were still leftin the .htaccess file which includes RewriteEngine On. Had to move ALL the .htaccess rules in one go to make it work. Your comment pointed me in the right direction.
Unfortunately W3 Total Cache seems to recreate the Page Cache rules when the cache is cleared manually which added the RewriteEngine On resulting in a 404 error.
Not solved the issue yet. but at least I know why it’s not working.
David