.htaccess explainer

Paste the file and every line gets a sentence saying what it does. Rewrite patterns are taken apart piece by piece, and rules that match known infection patterns are marked for a closer look.

Look for it in the top folder of the site, usually public_html, httpdocs or www. Because the name begins with a dot, file managers and FTP programs hide it until you enable “show hidden files”.

Samples

🔒 Your browser does the reading. The file is not uploaded.

Configuration that lives in the folder

A web server has a main configuration file that only its administrator can edit. On shared hosting that’s not you, so Apache gives you another way in. It’s a plain text file named .htaccess, placed in a folder of the site, and its instructions apply to that folder and everything below it. LiteSpeed servers read the same file. nginx doesn’t, and ignores it completely.

The server reads the file again on every request, so a change takes effect the moment you save it. So does a mistake. One misspelled directive and every page answers with a 500 error until you correct the line. Keep a copy before each edit.

You’re rarely the only author. WordPress writes a block between # BEGIN WordPress and # END WordPress, and caching, security and image plugins add their own marked blocks. The explainer recognizes the markers of about 25 of them, including WP Rocket, LiteSpeed Cache, Wordfence and Really Simple SSL, and names the owner of each block.

Reading a rewrite rule out loud

mod_rewrite is where most people get lost. Take this pair:

RewriteCond %{HTTP_HOST} ^shop\.example\.com$ [NC]
RewriteRule ^products/(\d+)$ https://www.example.com/item?id=$1 [R=301,L]

It reads as a sentence: “If the requested host is shop.example.com, in any letter case, and the path is products/ followed by digits, send the visitor permanently to the new address with those digits as id, and stop processing.”

  • A RewriteCond is a condition on a server variable. It only applies to the next RewriteRule. Several in a row all have to be true, unless one ends with [OR].
  • The first part of a RewriteRule is a regular expression tested against the path. Parentheses capture text, and $1, $2 reuse it in the destination. %1 reuses a capture from the last condition.
FlagEffect
LLast rule of this pass. END stops for good.
R=301Answer with a redirect. 301 is permanent, 302 temporary. Without R, the rewrite is internal and the visitor’s address bar doesn’t change.
NCIgnore upper and lower case.
QSAKeep the original query string and append it.
F, GRefuse with 403, or answer 410 Gone.
PProxy: fetch the content from another server and serve it as your own.

What gets flagged

Attackers who get write access to a site often go for .htaccess, because a few lines there can redirect visitors or keep a hidden script reachable. The explainer compares each line with patterns seen in real infections and gives it one of two labels.

Suspicious, shown in red:

  • a redirect to another domain that only applies to visitors arriving from a search engine, or only to phones. The owner, who types the address directly on a computer, never sees it;
  • a different PHP script served to search engine crawlers;
  • AddHandler, AddType or SetHandler making image or text files run as PHP, or ordinary files run as CGI scripts;
  • php_value auto_prepend_file or auto_append_file loading a file before or after every script, and allow_url_include;
  • a FilesMatch block that denies every .php, .py and .exe file, followed by a block that allows a short list of PHP files WordPress doesn’t ship.

Check, shown in orange: lines inside the WordPress block that aren’t part of its standard rules, conditions aimed only at crawlers or referrers, the [P] flag, an error page hosted on another domain, directory listing switched on, PHP errors displayed to visitors, a disabled application firewall, lines longer than 400 characters or filled with base64 or encoded characters, and invisible characters.

Two structural errors get reported too, since both cause a 500: a block such as <IfModule> that’s never closed, and directives that are only legal in the main server configuration, such as DocumentRoot or <VirtualHost>.

The explainer reads text. It doesn’t run the rules, it can’t know which modules your server has loaded, and it doesn’t see other .htaccess files in parent folders or the main configuration, all of which change the outcome. A flag means “find out who added this”, and legitimate plugins set one off now and then. A file with no flags doesn’t prove the site is clean.

If a line is flagged and you didn’t write it

  1. Download a copy of the file as evidence before you touch anything.
  2. Check the file’s modification date and look for other files changed at the same time, especially PHP files in upload folders and the names listed in the flagged rules.
  3. Remove the hostile lines, then reload the file a few minutes later. If they’re back, a script on the server is rewriting it and deleting lines won’t be enough.
  4. Change the hosting, FTP or SSH, database and CMS administrator passwords, and update the CMS with all its plugins and themes.
  5. Run the unsafe-site lookup to see whether the site is already on a browser blocklist, and the redirect trace to confirm that visitors end up where they should.

Questions people ask

Where is the .htaccess file located?

In the top folder of the site, often called public_html, httpdocs or www. Subfolders can have their own. Names that start with a dot are hidden by default, so turn on “show hidden files” in your host’s file manager or FTP program.

Why does my site show a 500 error after I edited .htaccess?

Apache stops at the first line it can’t interpret. It’s usually a typo in a directive name, a block that was opened and never closed, a directive your host doesn’t allow in .htaccess, or a module that isn’t installed. Restore your copy, then add your changes back one at a time.

What does [L,R=301] mean in a RewriteRule?

R=301 tells the browser to go to the new address and remember it as permanent. L stops the server from applying any more rewrite rules to this request. Put together, they’re the standard permanent redirect.

How can I tell if my .htaccess file has been hacked?

Look for rules you didn’t add: redirects to unfamiliar domains, conditions on HTTP_REFERER or HTTP_USER_AGENT, handlers that run images as PHP, and auto_prepend_file. Compare the WordPress block with the default one. This page flags those patterns for you.

Does .htaccess work on nginx?

No. nginx has no per-folder configuration files. Whoever administers the server has to translate the rules into its own configuration. Some hosts run nginx in front of Apache, and in that case .htaccess still applies to the requests that reach Apache.

Is the file I paste sent to your server?

No. The analysis is a script that runs in your browser. Even so, get into the habit of removing passwords and secret keys from anything you paste into a web page.