hint
Version:
The linting tool for the web
637 lines (461 loc) • 26.2 kB
Markdown
# Basic server configuration for Apache
The following configurations should be a good starting point to
pass most of `webhint`'s checks that require adding to or modifying
the server configuration.
There are some assumptions though:
* The below snippet works with Apache `v2.2.0+`, but you need to have
[`mod_deflate`][mod_deflate], [`mod_expires`][mod_expires],
[`mod_headers`][mod_headers], [`mod_mime`][mod_mime],
[`mod_rewrite`][mod_rewrite], and for Apache versions below `v2.3.7`
[`mod_filter`][mod_filter] [enabled][how to enable apache modules]
for it to take effect.
* If you have access to the [main Apache configuration file][main
apache conf file] (usually called `httpd.conf`), you should add
the logic in, for example, a [`<Directory>`][apache directory]
section in that file. This is usually the recommended way as
[using `.htaccess` files slows down][htaccess is slow] Apache!
If you don't have access to the main configuration file (quite
common with hosting services), add the snippets in a `.htaccess`
file in the root of the web site/app.
```apache
# ######################################################################
# # MEDIA TYPES AND CHARACTER ENCODINGS (content-type) #
# ######################################################################
# ----------------------------------------------------------------------
# | Media types |
# ----------------------------------------------------------------------
# Serve resources with the proper media types (f.k.a. MIME types).
# https://webhint.io/docs/user-guide/hints/hint-content-type/
<IfModule mod_mime.c>
# Data interchange
# 2.2.x+
AddType text/xml xml
# 2.2.x - 2.4.x
AddType application/json json
AddType application/rss+xml rss
# 2.4.x+
AddType application/json map
# JavaScript
# 2.2.x+
# See: https://html.spec.whatwg.org/multipage/scripting.html#scriptingLanguages.
AddType text/javascript js mjs
# Manifest files
# 2.2.x+
AddType application/manifest+json webmanifest
AddType text/cache-manifest appcache
# Media files
# 2.2.x - 2.4.x
AddType audio/mp4 f4a f4b m4a
AddType audio/ogg oga ogg spx
AddType video/mp4 mp4 mp4v mpg4
AddType video/ogg ogv
AddType video/webm webm
AddType video/x-flv flv
# 2.2.x+
AddType image/svg+xml svgz
AddType image/x-icon cur
# 2.4.x+
AddType image/webp webp
# Web fonts
# 2.2.x - 2.4.x
AddType application/vnd.ms-fontobject eot
# 2.2.x+
AddType font/woff woff
AddType font/woff2 woff2
AddType font/ttf ttf
AddType font/collection ttc
AddType font/otf otf
# Other
# 2.2.x+
AddType text/vtt vtt
</IfModule>
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Serve all resources labeled as `text/html` or `text/plain`
# with the media type `charset` parameter set to `utf-8`.
#
# https://httpd.apache.org/docs/current/mod/core.html#adddefaultcharset
AddDefaultCharset utf-8
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Serve the following file types with the media type `charset`
# parameter set to `utf-8`.
#
# https://httpd.apache.org/docs/current/mod/mod_mime.html#addcharset
<IfModule mod_mime.c>
AddCharset utf-8 .appcache \
.atom \
.css \
.js \
.json \
.manifest \
.map \
.mjs \
.rdf \
.rss \
.vtt \
.webmanifest \
.xml
</IfModule>
# ######################################################################
# # Compression (http-compression) #
# ######################################################################
# Server resources compressed.
# https://webhint.io/docs/user-guide/hints/hint-http-compression/
# [!] The following relies on Apache being configured to have
# the correct filename extensions to media types mappings
# (see `content-type` section).
#
# [!] For Zopfli and Brotli this snippet assumes that running
# the build step will result in 3 version for every resource:
#
# * the original (e.g.: script.js) - this file should exists
# in case the user agent doesn’t requests things compressed
# * the file compressed with Zopfli (e.g.: script.js.gz)
# * the file compressed with Brotli (e.g.: script.js.br)
<IfModule mod_headers.c>
<IfModule mod_rewrite.c>
# Turn on the rewrite engine (this is necessary in order for
# the `RewriteRule` directives to work).
#
# https://httpd.apache.org/docs/current/mod/core.html#options
RewriteEngine On
# Enable the `FollowSymLinks` option if it isn't already.
#
# https://httpd.apache.org/docs/current/mod/core.html#options
Options +FollowSymlinks
# If the web host doesn't allow the `FollowSymlinks` option,
# it needs to be comment out or removed, and then the following
# uncomment, but be aware of the performance impact.
#
# https://httpd.apache.org/docs/current/misc/perf-tuning.html#symlinks
# Options +SymLinksIfOwnerMatch
# Depending on how the server is set up, you may also need to
# use the `RewriteOptions` directive to enable some options for
# the rewrite engine.
#
# https://httpd.apache.org/docs/current/mod/mod_rewrite.html#rewriteoptions
# RewriteBase /
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# 1) Brotli
# If `Accept-Encoding` header contains `br`
RewriteCond "%{HTTP:Accept-encoding}" "br"
# and the request is made over HTTPS.
RewriteCond "%{HTTPS}" "on"
# The Brotli pre-compressed version of the file exists
# (e.g.: `script.js` is requested and `script.js.gz` exists).
RewriteCond "%{REQUEST_FILENAME}\.br" "-s"
# Then, serve the Brotli pre-compressed version of the file.
RewriteRule "^(.*)" "$1\.br" [QSA]
# Set the correct media type of the requested file. Otherwise,
# it will be served with the br media type since the file has
# the `.br` extension.
#
# Also, set the special purpose environment variables so
# that Apache doesn't recompress these files.
RewriteRule "\.(ico|cur)\.br$" "-" [T=image/x-icon,E=no-brotli:1,E=no-gzip:1]
RewriteRule "\.(md|markdown)\.br$" "-" [T=text/markdown,E=no-brotli:1,E=no-gzip:1]
RewriteRule "\.appcache\.br$" "-" [T=text/cache-manifest,E=no-brotli:1,E=no-gzip:1]
RewriteRule "\.atom\.br$" "-" [T=application/atom+xml,E=no-brotli:1,E=no-gzip:1]
RewriteRule "\.bmp\.br$" "-" [T=image/bmp,E=no-brotli:1,E=no-gzip:1]
RewriteRule "\.css\.br$" "-" [T=text/css,E=no-brotli:1,E=no-gzip:1]
RewriteRule "\.eot.\.br$" "-" [T=application/vnd.ms-fontobject,E=no-brotli:1,E=no-gzip:1]
RewriteRule "\.geojson\.br$" "-" [T=application/vnd.geo+json,E=no-brotli:1,E=no-gzip:1]
RewriteRule "\.html?\.br$" "-" [T=text/html,E=no-brotli:1,E=no-gzip:1]
RewriteRule "\.ics\.br$" "-" [T=text/calendar,E=no-brotli:1,E=no-gzip:1]
RewriteRule "\.json\.br$" "-" [T=application/json,E=no-brotli:1,E=no-gzip:1]
RewriteRule "\.jsonld\.br$" "-" [T=application/ld+json,E=no-brotli:1,E=no-gzip:1]
RewriteRule "\.m?js\.br$" "-" [T=text/javascript,E=no-brotli:1,E=no-gzip:1]
RewriteRule "\.otf\.br$" "-" [T=font/otf,E=no-brotli:1,E=no-gzip:1]
RewriteRule "\.rdf\.br$" "-" [T=application/rdf+xml,E=no-brotli:1,E=no-gzip:1]
RewriteRule "\.rss\.br$" "-" [T=application/rss+xml,E=no-brotli:1,E=no-gzip:1]
RewriteRule "\.svg\.br$" "-" [T=image/svg+xml,E=no-brotli:1,E=no-gzip:1]
RewriteRule "\.ttc\.br$" "-" [T=font/collection,E=no-brotli:1,E=no-gzip:1]
RewriteRule "\.ttf\.br$" "-" [T=font/ttf,E=no-brotli:1,E=no-gzip:1]
RewriteRule "\.txt\.br$" "-" [T=text/plain,E=no-brotli:1,E=no-gzip:1]
RewriteRule "\.vc(f|ard)\.br$" "-" [T=text/vcard,E=no-brotli:1,E=no-gzip:1]
RewriteRule "\.vtt\.br$" "-" [T=text/vtt,E=no-brotli:1,E=no-gzip:1]
RewriteRule "\.webmanifest\.br$" "-" [T=application/manifest+json,E=no-brotli:1,E=no-gzip:1]
RewriteRule "\.xhtml\.br$" "-" [T=application/xhtml+xml,E=no-brotli:1,E=no-gzip:1]
RewriteRule "\.xml\.br$" "-" [T=text/xml,E=no-brotli:1,E=no-gzip:1]
# Set the `Content-Encoding` header.
<FilesMatch "\.br$">
Header append Content-Encoding br
</FilesMatch>
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# 2) Zopfli
# If `Accept-Encoding` header contains `gzip` and the
# request is made over HTTP.
RewriteCond "%{HTTP:Accept-encoding}" "gzip"
# The Zopfli pre-compressed version of the file exists
# (e.g.: `script.js` is requested and `script.js.gz` exists).
RewriteCond "%{REQUEST_FILENAME}\.gz" "-s"
# Then serve the Zopfli pre-compressed version of the file.
RewriteRule "^(.*)" "$1\.gz" [QSA]
# Set the media types of the file, as otherwise, because
# the file has the `.gz` extension, it wil be served with
# the gzip media type.
#
# Also, set the special purpose environment variables so
# that Apache doesn't recompress these files.
RewriteRule "\.(ico|cur)\.gz$" "-" [T=image/x-icon,E=no-brotli:1,E=no-gzip:1]
RewriteRule "\.(md|markdown)\.gz$" "-" [T=text/markdown,E=no-brotli:1,E=no-gzip:1]
RewriteRule "\.appcache\.gz$" "-" [T=text/cache-manifest,E=no-brotli:1,E=no-gzip:1]
RewriteRule "\.atom\.gz$" "-" [T=application/atom+xml,E=no-brotli:1,E=no-gzip:1]
RewriteRule "\.bmp\.gz$" "-" [T=image/bmp,E=no-brotli:1,E=no-gzip:1]
RewriteRule "\.css\.gz$" "-" [T=text/css,E=no-brotli:1,E=no-gzip:1]
RewriteRule "\.eot.\.gz$" "-" [T=application/vnd.ms-fontobject,E=no-brotli:1,E=no-gzip:1]
RewriteRule "\.geojson\.gz$" "-" [T=application/vnd.geo+json,E=no-brotli:1,E=no-gzip:1]
RewriteRule "\.html?\.gz$" "-" [T=text/html,E=no-brotli:1,E=no-gzip:1]
RewriteRule "\.ics\.gz$" "-" [T=text/calendar,E=no-brotli:1,E=no-gzip:1]
RewriteRule "\.json\.gz$" "-" [T=application/json,E=no-brotli:1,E=no-gzip:1]
RewriteRule "\.jsonld\.gz$" "-" [T=application/ld+json,E=no-brotli:1,E=no-gzip:1]
RewriteRule "\.m?js\.gz$" "-" [T=text/javascript,E=no-brotli:1,E=no-gzip:1]
RewriteRule "\.otf\.gz$" "-" [T=font/otf,E=no-brotli:1,E=no-gzip:1]
RewriteRule "\.rdf\.gz$" "-" [T=application/rdf+xml,E=no-brotli:1,E=no-gzip:1]
RewriteRule "\.rss\.gz$" "-" [T=application/rss+xml,E=no-brotli:1,E=no-gzip:1]
RewriteRule "\.svg\.gz$" "-" [T=image/svg+xml,E=no-brotli:1,E=no-gzip:1]
RewriteRule "\.ttc\.gz$" "-" [T=font/collection,E=no-brotli:1,E=no-gzip:1]
RewriteRule "\.ttf\.gz$" "-" [T=font/ttf,E=no-brotli:1,E=no-gzip:1]
RewriteRule "\.txt\.gz$" "-" [T=text/plain,E=no-brotli:1,E=no-gzip:1]
RewriteRule "\.vc(f|ard)\.gz$" "-" [T=text/vcard,E=no-brotli:1,E=no-gzip:1]
RewriteRule "\.vtt\.gz$" "-" [T=text/vtt,E=no-brotli:1,E=no-gzip:1]
RewriteRule "\.webmanifest\.gz$" "-" [T=application/manifest+json,E=no-brotli:1,E=no-gzip:1]
RewriteRule "\.xhtml\.gz$" "-" [T=application/xhtml+xml,E=no-brotli:1,E=no-gzip:1]
RewriteRule "\.xml\.gz$" "-" [T=text/xml,E=no-brotli:1,E=no-gzip:1]
# Set the `Content-Encoding` header.
<FilesMatch "\.gz$">
Header append Content-Encoding gzip
</FilesMatch>
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Set the `Vary` header.
<FilesMatch "\.(br|gz)$">
Header append Vary Accept-Encoding
</FilesMatch>
</IfModule>
</IfModule>
<IfModule mod_deflate.c>
# 3) gzip
#
# [!] 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/json" \
"application/manifest+json" \
"application/rdf+xml" \
"application/rss+xml" \
"application/schema+json" \
"application/vnd.ms-fontobject" \
"application/xhtml+xml" \
"font/collection" \
"font/opentype" \
"font/otf" \
"font/ttf" \
"image/bmp" \
"image/svg+xml" \
"image/x-icon" \
"text/cache-manifest" \
"text/css" \
"text/html" \
"text/javascript" \
"text/plain" \
"text/vtt" \
"text/xml"
</IfModule>
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Special case: SVGZ
#
# If these files type would be served without the
# `Content-Enable: gzip` response header, user agents would
# not know that they first need to uncompress the response,
# and thus, wouldn't be able to understand the content.
<IfModule mod_mime.c>
AddEncoding gzip svgz
</IfModule>
</IfModule>
# ######################################################################
# # Caching (http-cache) #
# ######################################################################
# Serve resources with far-future expiration date.
# https://webhint.io/docs/user-guide/hints/hint-http-cache/
# [!] The following relies on Apache being configured to have
# the correct filename extensions to media types mappings
# (see apache `content-type` section).
#
# [!] Do not use or comment out the following if you are not
# using filename/path-based revving.
<IfModule mod_expires.c>
# Automatically add the `Cache-Control` header (as well as the
# equivalent `Expires` header).
ExpiresActive on
# By default, inform user agents to cache all resources for 1 year.
ExpiresDefault "access plus 1 year"
# Overwrite the previous for file types whose content usually changes
# very often, and thus, should not be cached for such a long period,
# or at all.
# AppCache manifest files
ExpiresByType text/cache-manifest "access plus 0 seconds"
# /favicon.ico (cannot be renamed!)
# [!] If you have access to the main Apache configuration
# file, you can match the root favicon exactly using the
# `<Location>` directive. The same cannot be done inside
# of a `.htaccess` file where only the `<Files>` directive
# can be used, reason why the best that can be done is match
# all files named `favicon.ico` (but that should work fine
# if filename/path-based revving is used)
#
# See also: https://httpd.apache.org/docs/current/sections.html#file-and-web.
<Files "favicon.ico">
ExpiresByType image/x-icon "access plus 1 hour"
</Files>
# 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 text/xml "access plus 0 seconds"
# HTML
ExpiresByType text/html "access plus 0 seconds"
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Where needed add `immutable` value to the `Cache-Control` header
<IfModule mod_headers.c>
# Because `mod_headers` cannot match based on the content-type,
# the following workaround needs to be done.
# 1) Add the `immutable` value to the `Cache-Control` header
# to all resources.
Header merge Cache-Control immutable
# 2) Remove the value for all resources that shouldn't be have it.
<FilesMatch "\.(appcache|cur|geojson|ico|json(ld)?|x?html?|topojson|xml)$">
Header edit Cache-Control immutable ""
</FilesMatch>
</IfModule>
</IfModule>
# ######################################################################
# # DOCUMENT MODES (highest-available-document-mode) #
# ######################################################################
# Force Internet Explorer 8/9/10 to render pages in the highest mode
# available in the various cases when it may not.
#
# https://webhint.io/docs/user-guide/hints/hint-highest-available-document-mode/
<IfModule mod_headers.c>
# Because `mod_headers` cannot match based on the content-type,
# and the `X-UA-Compatible` response header should only be sent
# for HTML documents and not for the other resources, the following
# workaround needs to be done.
# 1) Add the header to all resources.
Header set X-UA-Compatible "IE=edge"
# 2) Remove the header for all resources that should not have it.
<FilesMatch "\.(appcache|atom|bbaw|bmp|crx|css|cur|eot|f4[abpv]|flv|geojson|gif|htc|ic[os]|jpe?g|m?js|json(ld)?|m4[av]|manifest|map|markdown|md|mp4|oex|og[agv]|opus|otf|pdf|png|rdf|rss|safariextz|svgz?|swf|topojson|tt[cf]|txt|vcard|vcf|vtt|webapp|web[mp]|webmanifest|woff2?|xloc|xml|xpi)$">
Header unset X-UA-Compatible
</FilesMatch>
</IfModule>
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# If the `X-UA-Compatible` header is not needed, remove or comment
# out the section above. If it's still added from somewhere in the
# stack (e.g. the framework level, language level such as PHP, etc.),
# and that cannot be changed, the following may be used to remove it
# at the Apache level.
# <IfModule mod_headers.c>
# Header unset X-UA-Compatible
# </IfModule>
# ######################################################################
# # SECURITY #
# ######################################################################
# ----------------------------------------------------------------------
# | HTTP Strict Transport Security (strict-transport-security) |
# ----------------------------------------------------------------------
# Serve resources with the Strict-Transport-Security header.
# https://webhint.io/docs/user-guide/hints/hint-strict-transport-security/
#
# [!] Uncomment the following if the site supports HTTPS.
# <IfModule mod_headers.c>
# Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
# </IfModule>
# ----------------------------------------------------------------------
# | X-Content-Type-Options |
# ----------------------------------------------------------------------
# Serve resources with the x-content-type-options header set to `nosniff`.
# https://webhint.io/docs/user-guide/hints/hint-x-content-type-options/
# <IfModule mod_headers.c>
# Header always set X-Content-Type-Options nosniff
# </IfModule>
# ######################################################################
# # Unnedded / Disallowed headers #
# ######################################################################
# ----------------------------------------------------------------------
# | HTML only headers (no-html-only-headers) |
# ----------------------------------------------------------------------
# Do not send HTML only headers for non-HTML resources,
# https://webhint.io/docs/user-guide/hints/hint-no-html-only-headers/#page-heading
<IfModule mod_headers.c>
# Because `mod_headers` cannot match based on the content-type,
# the following workaround needs to be used.
<FilesMatch "\.(appcache|atom|bbaw|bmp|crx|css|cur|eot|f4[abpv]|flv|geojson|gif|htc|ic[os]|jpe?g|m?js|json(ld)?|m4[av]|manifest|map|markdown|md|mp4|oex|og[agv]|opus|otf|pdf|png|rdf|rss|safariextz|svgz?|swf|topojson|tt[cf]|txt|vcard|vcf|vtt|webapp|web[mp]|webmanifest|woff2?|xloc|xml|xpi)$">
Header unset Content-Security-Policy
Header unset X-Content-Security-Policy
Header unset X-Frame-Options
Header unset X-UA-Compatible
Header unset X-WebKit-CSP
Header unset X-XSS-Protection
</FilesMatch>
</IfModule>
# ----------------------------------------------------------------------
# | Disallowed headers (no-disallowed-headers) |
# ----------------------------------------------------------------------
# Remove unneeded headers.
# https://webhint.io/docs/user-guide/hints/hint-no-disallowed-headers/
# If the headers are sent, in most cases, to make Apache stop sending
# them requires removing the configurations that tells Apache to add
# them (e.g. for the `X-UA-Compatible` header, that would be mean
# removing something such as `Header set X-UA-Compatible "IE=edge"`).
# However, if the headers are added from somewhere in the stack (e.g.:
# the framework level, language level such as PHP, etc.), and that
# cannot be changed, you can try to remove them at the Apache level,
# using the following.
<IfModule mod_headers.c>
Header unset Expires
Header unset Host
Header unset P3P
Header unset Pragma
Header unset Public-Key-Pins
Header unset Public-Key-Pins-Report-Only
Header unset Via
Header unset X-AspNet-Version
Header unset X-AspNetMvc-version
Header unset X-Frame-Options
Header unset X-Powered-By
Header unset X-Runtime
Header unset X-Version
</IfModule>
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Prevent Apache from sending in the `Server` response header its
# exact version number, the description of the generic OS-type or
# information about its compiled-in modules.
#
# https://httpd.apache.org/docs/current/mod/core.html#servertokens
# [!] The following will only work in the main Apache configuration
# file, so do not uncomment the following if this is include it
# in a .htaccess file!
# ServerTokens Prod
# ######################################################################
# # Custom configurations #
# ######################################################################
# Add here your custom configurations.
```
<!-- Link labels: -->
[apache directory]: https://httpd.apache.org/docs/current/mod/core.html#directory
[how to enable apache modules]: https://github.com/h5bp/server-configs-apache/tree/7eb30da6a06ec4fc24daf33c75b7bd86f9ad1f68#enable-apache-httpd-modules
[htaccess is slow]: https://httpd.apache.org/docs/current/howto/htaccess.html#when
[main apache conf file]: https://httpd.apache.org/docs/current/configuring.html#main
[mod_deflate]: https://httpd.apache.org/docs/current/mod/mod_deflate.html
[mod_expires]: https://httpd.apache.org/docs/current/mod/mod_expires.html
[mod_filter]: https://httpd.apache.org/docs/current/mod/mod_filter.html
[mod_headers]: https://httpd.apache.org/docs/current/mod/mod_headers.html
[mod_mime]: https://httpd.apache.org/docs/current/mod/mod_mime.html
[mod_rewrite]: https://httpd.apache.org/docs/current/mod/mod_rewrite.html