WordPress .htaccess

A .htaccess specifically designed for WordPress content management system with a focus on security and performance.

The Code

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index.php$ - [L]
RewriteRule ^login/?$ /wp-login.php [QSA,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

# END WordPress

#######################
# Hardening WordPress #
#######################

# <files wp-config.php>
#    Order allow,deny
#    Deny from all
# </files>

# <files readme.html>
#    Order allow,deny
#    Deny from all
# </files>

# <files license.txt>
#    Order allow,deny
#    Deny from all
# </files>

<FilesMatch "^(wp-config.php|readme.html|license.txt)">
    Order allow,deny
    Deny from all
    Satisfy All
</FilesMatch>

# Block the include-only files.
<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteBase /
    RewriteRule ^wp-admin/includes/ - [F,L]
    RewriteRule !^wp-includes/ - [S=3]
    RewriteRule ^wp-includes/[^/]+.php$ - [F,L]
    RewriteRule ^wp-includes/js/tinymce/langs/.+.php - [F,L]
    RewriteRule ^wp-includes/theme-compat/ - [F,L]
</IfModule>

# Block access to wp-login.php
# <Files wp-login.php>
#    Order Deny,Allow
#    Deny from all
#    Allow from xx.xx.xx.xx
# </Files>

# Block access to the following file types, i.e. filename.type
<FilesMatch "(^#.*#|.(bak|config|dist|txt|html|htm|eot|otf|ttc|ttf|woff|inc|ini|log|psd|sh|sql)|~)$">
    Order allow,deny
    Deny from all
    Satisfy All
</FilesMatch>

# Disallow directory listing
<IfModule mod_autoindex.c>
    Options -Indexes
</IfModule>

# Block outside domain names from using the POST method
<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{REQUEST_METHOD} POST
    RewriteCond %{REQUEST_URI} .(wp-comments-post|wp-login).php*
    RewriteCond %{HTTP_REFERER} !.*<%= domain_name %>.* [OR]
    RewriteCond %{HTTP_USER_AGENT} ^$
    RewriteRule (.*) http://%{REMOTE_ADDR}/$ [R=301,L]
</ifModule>

# Security Headers - X-Content-Type: nosniff
# https://msdn.microsoft.com/en-us/library/ie/gg622941%28v=vs.85%29.aspx
<IfModule mod_headers.c>
  Header set X-Content-Type-Options nosniff
</IfModule>

# Security Headers - X-Frame-Options
# Prevents ClickJacking - Prevents an attacker from iframing your content
# https://blog.mozilla.org/security/2013/12/12/on-the-x-frame-options-security-header/
# <IfModule mod_headers.c>
#  Header always append X-Frame-Options SAMEORIGIN
# </IfModule>

# Security Headers - X-XSS-Protection
# Protects against some types of XSS (cross-site scripting) attacks
<IfModule mod_headers.c>
  Header set X-XSS-Protection "1; mode=block"
</IfModule>

############################
# Performance Optimization #
############################

# Leverage Browser Caching by setting HTTP header expires
<IfModule mod_expires.c>
    ExpiresActive On
    ExpiresByType image/jpg "access plus 1 year"
    ExpiresByType image/jpeg "access plus 1 year"
    ExpiresByType image/gif "access plus 1 year"
    ExpiresByType image/png "access plus 1 year"
    ExpiresByType text/css "access plus 1 month"
    ExpiresByType application/pdf "access plus 1 month"
    ExpiresByType text/x-javascript "access plus 1 month"
    ExpiresByType application/javascript "access plus 1 month"
    ExpiresByType text/javascript "access plus 1 month"
    ExpiresByType application/x-shockwave-flash "access plus 1 month"
    ExpiresByType image/x-icon "access plus 1 year"
    ExpiresDefault "access plus 2 days"
</IfModule>

# Use UTF-8 encoding
AddDefaultCharset utf-8

# Force the use of UTF-8 encoding
<IfModule mod_mime.c>
    AddCharset utf-8 .css .js
</IfModule>

# Specify a Vary: Accept-Encoding header
<IfModule mod_headers.c>
  <FilesMatch ".(js|css|xml|gz)$">
    Header append Vary: Accept-Encoding
  </FilesMatch>
</IfModule>

# Use the GZIP Apache module
<ifModule mod_gzip.c>
    mod_gzip_on Yes
    mod_gzip_dechunk Yes
    mod_gzip_item_include file .(html?|txt|css|js|php|pl)$
    mod_gzip_item_include handler ^cgi-script$ mod_gzip_item_include mime ^text/.*
    mod_gzip_item_include mime ^application/x-javascript.*
    mod_gzip_item_exclude mime ^image/.*
    mod_gzip_item_exclude rspheader ^Content-Encoding:.*gzip.*
</ifModule>

# Enable DEFALTE
<IfModule mod_deflate.c>
    AddOutputFilter DEFLATE js css
    AddOutputFilterByType DEFLATE text/plain
    AddOutputFilterByType DEFLATE text/html
    AddOutputFilterByType DEFLATE text/xml
    AddOutputFilterByType DEFLATE text/css
    AddOutputFilterByType DEFLATE text/javascript
    AddOutputFilterByType DEFLATE application/xml
    AddOutputFilterByType DEFLATE application/xhtml+xml
    AddOutputFilterByType DEFLATE application/rss+xml
    AddOutputFilterByType DEFLATE application/javascript
    AddOutputFilterByType DEFLATE application/x-javascript
    BrowserMatch ^Mozilla/4 gzip-only-text/html
    BrowserMatch ^Mozilla/4.0[678] no-gzip
    BrowserMatch bMSIE !no-gzip !gzip-only-text/html
    Header append Vary User-Agent
</IfModule>

# Keep alive for persistent connections
# <IfModule mod_headers.c>
#    Header set Connection Keep-Alive
# </IfModule>

WordPress .htaccess Yeoman Generator

WordPress .htaccess Yeoman Generator is a Yeoman Generator that will generate a  .htaccess file specifically for WordPress.

Install

npm install -g generator-wordpress-htaccess

Usage

yo wordpress-htaccess

If you generate the .htaccess file in a directory that is not the directory where your WordPress installed, you will need to move the .htaccess file.

mv .htaccess /path/to/wordpress