Free tool · no signup

.htaccess security generator

Tick the protections you want and get a tested set of .htaccess rules for Apache: https redirect, hidden files, backups, security headers and a WordPress hardening block.

By the Bug Circuit security team · Last updated

What to switch on

Add to the .htaccess in your site's root folder
# Hardening rules generated by Bug Circuit. Test on a staging copy first and keep a backup of your old .htaccess.

# Send every http:// request to https://. The X-Forwarded-Proto test stops a redirect loop behind a proxy or CDN.
<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteCond %{HTTPS} !=on
  RewriteCond %{HTTP:X-Forwarded-Proto} !https
  RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</IfModule>

# Do not list the files in a folder that has no index file.
Options -Indexes

# Do not print the Apache version on error pages. (ServerTokens can only be set in the main server config.)
ServerSignature Off

# Refuse the TRACE and TRACK methods.
<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteCond %{REQUEST_METHOD} ^(TRACE|TRACK) [NC]
  RewriteRule .* - [F]
</IfModule>

# Hidden files such as .env, .htpasswd and .DS_Store must never be served.
<FilesMatch "^\.">
  Require all denied
</FilesMatch>

# Backup, database dump and log files left in the web root.
<FilesMatch "(\.(bak|backup|old|orig|save|sql|sqlite|swp|log|dist)|~)$">
  Require all denied
</FilesMatch>

# Source-control folders must not be reachable.
<IfModule mod_alias.c>
  RedirectMatch 404 "/\.(git|svn|hg)(/|$)"
</IfModule>

# Basic security headers (needs mod_headers).
<IfModule mod_headers.c>
  Header always set X-Content-Type-Options "nosniff"
  Header always set X-Frame-Options "SAMEORIGIN"
  Header always set Referrer-Policy "strict-origin-when-cross-origin"
  Header always set Permissions-Policy "camera=(), microphone=(), geolocation=()"
</IfModule>
  • Add the redirect only after https works on every page, or visitors will see certificate errors. WordPress also needs its Site Address set to https.
  • Options -Indexes needs AllowOverride Options (or All) in the server config. If the site returns a 500 error after you add it, remove that line or ask your host to allow it.
  • These rules work on Apache and compatible servers (LiteSpeed). Nginx and most managed hosts ignore .htaccess: use the security headers generator for nginx.
  • A typo can take the whole site down with a 500 error. Keep the old file so you can put it back, and check the site straight after saving.

Put these lines above any WordPress block (# BEGIN WordPress) so WordPress does not rewrite them.

What does this do? It writes the Apache rules that close the most common holes on a small site: plain http, folder listings, exposed .env and backup files, missing security headers and PHP running from the uploads folder. Add the rules to your .htaccess, test, and keep a copy of the old file.

How it works

What each rule protects

The https redirect sends every plain http request to https, with a check for the X-Forwarded-Proto header so it does not loop behind a CDN or proxy. Options -Indexes stops Apache listing the files in a folder that has no index page. The dotfile rule blocks files whose names start with a dot, such as .env, .htpasswd and .DS_Store, and a separate rule hides .git, .svn and .hg folders, so a deployed repository cannot be downloaded. The backup rule blocks leftovers such as backup.sql, site.old and error.log.

The headers block adds X-Content-Type-Options, X-Frame-Options, Referrer-Policy and Permissions-Policy, and optionally HSTS. TRACE and TRACK are refused, and the Apache version is hidden on error pages. These are safe defaults, not a complete policy: use the security headers generator for a Content-Security-Policy.

WordPress options

The WordPress block denies direct access to wp-config.php and to readme.html and license.txt, which reveal your WordPress version. You can also block xmlrpc.php, which attackers use for password guessing, but doing so breaks Jetpack, the mobile app and some publishing tools. The author scan rule stops /?author=1 requests that reveal usernames, and it leaves wp-admin alone because the admin screens use that parameter.

The most useful WordPress rule is the second file: a small .htaccess inside wp-content/uploads that stops files there running as PHP. Attackers who find an upload bug usually drop a PHP web shell into that folder, and this rule turns it into a download that does nothing.

Test before you trust it

A single typo in .htaccess returns a 500 error for the whole site. Keep the old file, add the new rules above any WordPress block, and load your home page and your admin login straight away. If you get a 500 error, remove the last block you added. The log, usually error.log in your hosting panel, names the line.

.htaccess works on Apache and compatible servers such as LiteSpeed. Nginx ignores it, and many managed WordPress hosts run Nginx, so ask your host first. On Nginx, use the security headers generator and your host's own settings.

Worked examples

Hide dotfiles and backups

Apache 2.4, the two blocking options ticked.

<FilesMatch "^\.">
  Require all denied
</FilesMatch>

<FilesMatch "(\.(bak|backup|old|orig|save|sql|sqlite|swp|log|dist)|~)$">
  Require all denied
</FilesMatch>

A request for /.env or /backup.sql now gets a 403 instead of your secrets.

Stop PHP running from uploads (WordPress)

Save this as wp-content/uploads/.htaccess.

<FilesMatch "\.(?i:php|phtml|phar|php[0-9])$">
  Require all denied
</FilesMatch>

Media files still load. A PHP file uploaded through a vulnerable plugin can no longer be run by visiting it.

Redirect to https behind a CDN

The https redirect option.

RewriteCond %{HTTPS} !=on
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

The second condition stops a redirect loop when a proxy talks to your server over http but the visitor used https.

Frequently asked questions

Does .htaccess work on Nginx?
No. Nginx ignores .htaccess files. Use the security headers generator for Nginx, and put access rules in the Nginx server block.
Why does my site show a 500 error after adding these rules?
Usually a typo, or a directive your host does not allow in .htaccess. Options -Indexes is the common one, because it needs AllowOverride Options. Remove the last block you added and check the error log for the line.
Where do I put the rules?
In the .htaccess file in your site's root folder, above any "# BEGIN WordPress" block. If the file does not exist, create it.
Is it safe to block xmlrpc.php?
It stops a common password-guessing route, but it also breaks Jetpack, the WordPress mobile app and some remote publishing tools. Block it only if you do not use them.
Should I turn on HSTS?
Only when https works on every page of the main domain and every subdomain you use. It tells browsers to refuse plain http for a year and is hard to undo.
Can I set ServerTokens here?
No. ServerTokens only works in the main server configuration. ServerSignature Off, which hides the version on error pages, does work in .htaccess.
Do these rules make my site secure?
They close common holes. They do not fix a vulnerable plugin, a weak password or an insecure application. Keep software updated and consider a manual test.

Keep reading

See what attackers see, for free

Run the free passive check on your website. No login, no impact on your site, results in seconds.

Ready for the full manual audit? See pricing

.htaccess Security Generator for Apache · Bug Circuit