🗂️ .htaccess Security Snippet Generator
Check the protections you want and copy the generated Apache .htaccess snippet.
What the checkboxes write
Each box adds one commented block to a snippet you copy into a
.htaccess file - nothing is checked against your server. The
"basic security headers" box emits three, not the two in its label:
<IfModule mod_headers.c>
Header set X-Content-Type-Options "nosniff"
Header set X-Frame-Options "SAMEORIGIN"
Header set Referrer-Policy "strict-origin-when-cross-origin"
</IfModule>
The rules use Apache 2.4 access syntax - Require all denied. On an
Apache 2.2 host that line is a fatal error and the whole site returns 500; there
you need Order allow,deny with Deny from all
instead.
Before you paste it
- The dotfile rule matches file names, not directories. It
blocks
/.envand/.htaccess, but a request for/.git/configasks for a file called "config" and sails through. AddRedirectMatch 404 /\.gitif that directory is on the server. - Change example.com in the hotlink rule to your own domain, or you will serve 403s for your own images.
- The file has to be allowed to work. Apache ignores
.htaccessunlessAllowOverridepermits it, which is off by default. On a server you control, put these directives in the virtual host instead - same effect, without a directory scan on every request.
Frequently asked questions
Why is my .htaccess file being ignored?
Usually AllowOverride None in the server config, which has been
the default since Apache 2.3.9. Check the error log too - a directive from a
module that is not loaded gives a 500 rather than silence, unless it is wrapped
in IfModule as the header block above is.
Does blocking dotfiles protect an exposed .git folder?
Not on its own, because the files inside it have ordinary names. Test it: ask
for /.git/config and see whether you get the contents back. The
real fix is not deploying the directory at all.
Why does the HTTPS redirect loop?
Behind a load balancer or CDN the connection to Apache is plain HTTP, so
%{HTTPS} is always off and the rule redirects forever. Test the
forwarded header instead: RewriteCond %{HTTP:X-Forwarded-Proto} !https.