|
# ###################################################################### |
|
# # SECURITY # |
|
# ###################################################################### |
|
|
|
# ---------------------------------------------------------------------- |
|
# | File access | |
|
# ---------------------------------------------------------------------- |
|
|
|
# Block access to directories without a default document. |
|
# Usually you should leave this uncommented because you shouldn't allow anyone |
|
# to surf through every directory on your server (which may includes rather |
|
# private places like the CMS's directories). |
|
|
|
<IfModule mod_autoindex.c> |
|
Options -Indexes |
|
</IfModule> |
|
|
|
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
|
|
|
# Block access to hidden files and directories. |
|
# This includes directories used by version control systems such as Git and SVN. |
|
|
|
<IfModule mod_rewrite.c> |
|
RewriteCond %{SCRIPT_FILENAME} -d [OR] |
|
RewriteCond %{SCRIPT_FILENAME} -f |
|
RewriteRule "(^|/)\." - [F] |
|
</IfModule> |
|
|
|
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
|
|
|
# Block access to backup and source files. |
|
# These files may be left by some text editors and can pose a great security |
|
# danger when anyone has access to them. |
|
|
|
<FilesMatch "(^#.*#|\.(bak|config|dist|fla|inc|ini|log|psd|sh|sql|sw[op])|~)$"> |
|
Order allow,deny |
|
Deny from all |
|
Satisfy All |
|
</FilesMatch> |
|
|
|
# Rules to block access to WordPress specific files |
|
<files readme.html> |
|
Order allow,deny |
|
Deny from all |
|
</files> |
|
<files readme.txt> |
|
Order allow,deny |
|
Deny from all |
|
</files> |
|
<files README.md> |
|
Order allow,deny |
|
Deny from all |
|
</files> |
|
<files install.php> |
|
Order allow,deny |
|
Deny from all |
|
</files> |
|
<files wp-config.php> |
|
Order allow,deny |
|
Deny from all |
|
</files> |
|
|
|
# Rules to disable XML-RPC |
|
<files xmlrpc.php> |
|
Order allow,deny |
|
Deny from all |
|
</files> |
|
|
|
# Deny access to all .htaccess files |
|
<files ~ "^.*\.([Hh][Tt][Aa])"> |
|
order allow,deny |
|
deny from all |
|
satisfy all |
|
</files> |
|
|
|
<IfModule mod_rewrite.c> |
|
RewriteEngine On |
|
|
|
# Rules to protect wp-includes |
|
RewriteRule ^wp-admin/includes/ - [F] |
|
RewriteRule !^wp-includes/ - [S=3] |
|
RewriteCond %{SCRIPT_FILENAME} !^(.*)wp-includes/ms-files.php |
|
RewriteRule ^wp-includes/[^/]+\.php$ - [F] |
|
RewriteRule ^wp-includes/js/tinymce/langs/.+\.php - [F] |
|
RewriteRule ^wp-includes/theme-compat/ - [F] |
|
|
|
# Rules to prevent php execution in uploads |
|
RewriteRule ^(.*)/uploads/(.*).php(.?) - [F] |
|
|
|
# Rules to block unneeded HTTP methods |
|
RewriteCond %{REQUEST_METHOD} ^(TRACE|DELETE|TRACK) [NC] |
|
RewriteRule ^(.*)$ - [F] |
|
|
|
# Rules to block foreign characters in URLs |
|
RewriteCond %{QUERY_STRING} ^.*(%0|%A|%B|%C|%D|%E|%F).* [NC] |
|
RewriteRule ^(.*)$ - [F] |
|
|
|
# Rules to help reduce spam |
|
RewriteCond %{REQUEST_METHOD} POST |
|
RewriteCond %{REQUEST_URI} ^(.*)wp-comments-post\.php* |
|
RewriteCond %{HTTP_REFERER} !^(.*)CHANGETHENAMEOFYOURWEBSITEHERE.com.* |
|
RewriteCond %{HTTP_REFERER} !^http://jetpack\.wordpress\.com/jetpack-comment/ [OR] |
|
RewriteCond %{HTTP_USER_AGENT} ^$ |
|
RewriteRule ^(.*)$ - [F] |
|
</IfModule> |
|
|
|
|
|
# ###################################################################### |
|
# # WEB PERFORMANCE # |
|
# ###################################################################### |
|
|
|
# ---------------------------------------------------------------------- |
|
# | Compression | |
|
# ---------------------------------------------------------------------- |
|
|
|
<IfModule mod_deflate.c> |
|
|
|
# Force compression for mangled `Accept-Encoding` request headers |
|
# https://developer.yahoo.com/blogs/ydn/pushing-beyond-gzipping-25601.html |
|
|
|
<IfModule mod_setenvif.c> |
|
<IfModule mod_headers.c> |
|
SetEnvIfNoCase ^(Accept-EncodXng|X-cept-Encoding|X{15}|~{15}|-{15})$ ^((gzip|deflate)\s*,?\s*)+|[X~-]{4,13}$ HAVE_Accept-Encoding |
|
RequestHeader append Accept-Encoding "gzip,deflate" env=HAVE_Accept-Encoding |
|
</IfModule> |
|
</IfModule> |
|
|
|
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
|
|
|
# Compress all output labeled with one of the following media types. |
|
# |
|
# (!) For Apache versions below version 2.3.7 you don't need to |
|
# enable `mod_filter` and can remove the `<IfModule mod_filter.c>` |
|
# and `</IfModule>` lines as `AddOutputFilterByType` is still in |
|
# the core directives. |
|
# |
|
# https://httpd.apache.org/docs/current/mod/mod_filter.html#addoutputfilterbytype |
|
|
|
<IfModule mod_filter.c> |
|
AddOutputFilterByType DEFLATE "application/atom+xml" \ |
|
"application/javascript" \ |
|
"application/json" \ |
|
"application/ld+json" \ |
|
"application/manifest+json" \ |
|
"application/rdf+xml" \ |
|
"application/rss+xml" \ |
|
"application/schema+json" \ |
|
"application/vnd.geo+json" \ |
|
"application/vnd.ms-fontobject" \ |
|
"application/x-font-ttf" \ |
|
"application/x-javascript" \ |
|
"application/x-web-app-manifest+json" \ |
|
"application/xhtml+xml" \ |
|
"application/xml" \ |
|
"font/eot" \ |
|
"font/opentype" \ |
|
"image/bmp" \ |
|
"image/svg+xml" \ |
|
"image/vnd.microsoft.icon" \ |
|
"image/x-icon" \ |
|
"text/cache-manifest" \ |
|
"text/css" \ |
|
"text/html" \ |
|
"text/javascript" \ |
|
"text/plain" \ |
|
"text/vcard" \ |
|
"text/vnd.rim.location.xloc" \ |
|
"text/vtt" \ |
|
"text/x-component" \ |
|
"text/x-cross-domain-policy" \ |
|
"text/xml" |
|
|
|
</IfModule> |
|
|
|
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
|
|
|
# Map the following filename extensions to the specified |
|
# encoding type in order to make Apache serve the file types |
|
# with the appropriate `Content-Encoding` response header |
|
# (do note that this will NOT make Apache compress them!). |
|
# |
|
# If these files types would be served without an appropriate |
|
# `Content-Enable` response header, client applications (e.g.: |
|
# browsers) wouldn't know that they first need to uncompress |
|
# the response, and thus, wouldn't be able to understand the |
|
# content. |
|
# |
|
# https://httpd.apache.org/docs/current/mod/mod_mime.html#addencoding |
|
|
|
<IfModule mod_mime.c> |
|
AddEncoding gzip svgz |
|
</IfModule> |
|
|
|
</IfModule> |
|
|
|
# ---------------------------------------------------------------------- |
|
# | ETags | |
|
# ---------------------------------------------------------------------- |
|
|
|
# Remove `ETags` as resources are sent with far-future expires headers. |
|
# |
|
# https://developer.yahoo.com/performance/rules.html#etags |
|
# https://tools.ietf.org/html/rfc7232#section-2.3 |
|
|
|
# `FileETag None` doesn't work in all cases. |
|
<IfModule mod_headers.c> |
|
Header unset ETag |
|
</IfModule> |
|
|
|
FileETag None |
|
|
|
# ---------------------------------------------------------------------- |
|
# | Expires headers | |
|
# ---------------------------------------------------------------------- |
|
|
|
# Serve resources with far-future expires headers. |
|
# |
|
# (!) If you don't control versioning with filename-based |
|
# cache busting, you should consider lowering the cache times |
|
# to something like one week. |
|
# |
|
# https://httpd.apache.org/docs/current/mod/mod_expires.html |
|
|
|
<IfModule mod_expires.c> |
|
|
|
ExpiresActive on |
|
ExpiresDefault "access plus 1 month" |
|
|
|
# CSS |
|
ExpiresByType text/css "access plus 1 year" |
|
|
|
# Data interchange |
|
ExpiresByType application/atom+xml "access plus 1 hour" |
|
ExpiresByType application/rdf+xml "access plus 1 hour" |
|
ExpiresByType application/rss+xml "access plus 1 hour" |
|
|
|
ExpiresByType application/json "access plus 0 seconds" |
|
ExpiresByType application/ld+json "access plus 0 seconds" |
|
ExpiresByType application/schema+json "access plus 0 seconds" |
|
ExpiresByType application/vnd.geo+json "access plus 0 seconds" |
|
ExpiresByType application/xml "access plus 0 seconds" |
|
ExpiresByType text/xml "access plus 0 seconds" |
|
|
|
# Favicon (cannot be renamed!) and cursor images |
|
ExpiresByType image/vnd.microsoft.icon "access plus 1 year" |
|
ExpiresByType image/x-icon "access plus 1 year" |
|
|
|
# HTML |
|
ExpiresByType text/html "access plus 0 seconds" |
|
|
|
# JavaScript |
|
ExpiresByType application/javascript "access plus 1 year" |
|
ExpiresByType application/x-javascript "access plus 1 year" |
|
ExpiresByType text/javascript "access plus 1 year" |
|
|
|
# Manifest files |
|
ExpiresByType application/manifest+json "access plus 1 year" |
|
|
|
ExpiresByType application/x-web-app-manifest+json "access plus 0 seconds" |
|
ExpiresByType text/cache-manifest "access plus 0 seconds" |
|
|
|
# Media files |
|
ExpiresByType audio/ogg "access plus 1 month" |
|
ExpiresByType image/bmp "access plus 1 month" |
|
ExpiresByType image/gif "access plus 1 month" |
|
ExpiresByType image/jpeg "access plus 1 month" |
|
ExpiresByType image/png "access plus 1 month" |
|
ExpiresByType image/svg+xml "access plus 1 month" |
|
ExpiresByType video/mp4 "access plus 1 month" |
|
ExpiresByType video/ogg "access plus 1 month" |
|
ExpiresByType video/webm "access plus 1 month" |
|
|
|
# Web fonts |
|
|
|
# Embedded OpenType (EOT) |
|
ExpiresByType application/vnd.ms-fontobject "access plus 1 year" |
|
ExpiresByType font/eot "access plus 1 year" |
|
|
|
# OpenType |
|
ExpiresByType font/opentype "access plus 1 year" |
|
|
|
# TrueType |
|
ExpiresByType application/x-font-ttf "access plus 1 year" |
|
|
|
# Web Open Font Format (WOFF) 1.0 |
|
ExpiresByType application/font-woff "access plus 1 year" |
|
ExpiresByType application/x-font-woff "access plus 1 year" |
|
ExpiresByType font/woff "access plus 1 year" |
|
|
|
# Web Open Font Format (WOFF) 2.0 |
|
ExpiresByType application/font-woff2 "access plus 1 year" |
|
|
|
# Other |
|
ExpiresByType text/x-cross-domain-policy "access plus 1 week" |
|
|
|
</IfModule> |
Improved force trailing slash code (if you need to force a trailing slash on the end of your URLs to avoid duplicate content issues)...
You can add this towards the top of the
.htaccess
(just after the force www. code would be ideal).