WordPress on Apache needs a short .htaccess block in the site root that sends every request for a file or folder that does not exist to index.php, which is what makes pretty permalinks work. Paste the block between # BEGIN WordPress and # END WordPress, and put your own rules above those markers.
| Line | Job |
|---|---|
| RewriteEngine On | Turns on mod_rewrite for this folder |
| RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] | Passes the Authorization header through to PHP |
| RewriteBase / | Rewrites are relative to the site root |
| RewriteRule ^index\.php$ - [L] | Requests for index.php itself are left alone |
| RewriteCond %{REQUEST_FILENAME} !-f | Only if no real file matches |
| RewriteCond %{REQUEST_FILENAME} !-d | And no real folder matches |
| RewriteRule . /index.php [L] | Hand everything else to WordPress |
Updated
A broken .htaccess usually shows up as every page except the homepage returning 404, or the whole site returning a 500 error after a plugin edit. Pick your install type below, choose the extras you want, and copy a complete file. The WordPress part matches the rules published in the WordPress developer documentation.
WordPress install type: Single site, Multisite, subfolders, Multisite, subdomains.
Extras placed above the WordPress block:
Only turn on the HTTPS redirect once your certificate works, or visitors will hit a browser warning.
Your .htaccess file
# Block web access to sensitive files
<FilesMatch "^(wp-config\.php|\.htaccess|\.htpasswd|debug\.log)$">
Require all denied
</FilesMatch>
# BEGIN WordPress
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
# END WordPress
These are the rules WordPress documents for each install type. Use exactly one of them.
The block for a normal WordPress site installed in the web root.
# BEGIN WordPress
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
# END WordPressFor networks where each site lives at a path such as example.com/shop/.
# BEGIN WordPress Multisite
# Using subfolder network type: https://wordpress.org/documentation/article/htaccess/#multisite
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index\.php$ - [L]
# add a trailing slash to /wp-admin
RewriteRule ^([_0-9a-zA-Z-]+/)?wp-admin$ $1wp-admin/ [R=301,L]
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
RewriteRule ^([_0-9a-zA-Z-]+/)?(wp-(content|admin|includes).*) $2 [L]
RewriteRule ^([_0-9a-zA-Z-]+/)?(.*\.php)$ $2 [L]
RewriteRule . index.php [L]
# END WordPress MultisiteFor networks where each site has its own subdomain such as shop.example.com.
# BEGIN WordPress Multisite
# Using subdomain network type: https://wordpress.org/documentation/article/htaccess/#multisite
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index\.php$ - [L]
# add a trailing slash to /wp-admin
RewriteRule ^wp-admin$ wp-admin/ [R=301,L]
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
RewriteRule ^(wp-(content|admin|includes).*) $1 [L]
RewriteRule ^(.*\.php)$ $1 [L]
RewriteRule . index.php [L]
# END WordPress MultisiteEach of these goes above # BEGIN WordPress. Add one at a time and reload the site after each.
Uses the Apache 2.4 Require directive, so an older 2.2 server would need the old Order and Deny syntax instead.
# Block web access to sensitive files
<FilesMatch "^(wp-config\.php|\.htaccess|\.htpasswd|debug\.log)$">
Require all denied
</FilesMatch>A permanent 301 redirect that keeps the host and path. If your host offers an HTTPS switch in its panel, use that and skip this.
# Send http:// requests to https://
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
Apache reads the conditions top to bottom. A request for a real image or stylesheet matches -f and is served directly, a request for a real folder matches -d, and anything else falls through to index.php, where WordPress looks up the post, page or archive for that address.
The HTTP_AUTHORIZATION line copies the Authorization header into a variable PHP can read. On some server setups PHP never sees that header otherwise, which breaks logins made through it.
Put redirects, HTTPS rules and access blocks above # BEGIN WordPress. Rules run in order, so a redirect placed after the WordPress block would never be reached for most URLs.
Keep additions few and tested. Each rule runs on every request, and a typo anywhere in the file takes the whole site down with a 500 error.
In the root folder of the WordPress install, next to wp-config.php and the wp-content folder. Its name starts with a dot, so file managers and FTP clients often hide it until you turn on hidden files.
Replace the file's contents with the single-site block on this page, or rename the broken file and visit Settings, Permalinks in the admin and click Save. WordPress writes a fresh block when it can write to the file.
Almost always the rewrite rules are missing or mod_rewrite is off. The homepage loads because it is index.php itself; every pretty permalink needs the rule that sends unknown paths to index.php.
The one matching how the network was installed. Sites at example.com/shop use the subfolder block; sites at shop.example.com use the subdomain block. The two differ in how they strip the site prefix from wp-admin and file paths.
Yes. PHP reads wp-config.php from disk, not over the web, so denying web requests to it does not affect the site. The WordPress documentation suggests the same FilesMatch rule shown here.
Related: Redirect rules generator, Redirect checker, Fix too many redirects, We.Inc vs WordPress, WordPress alternatives.
Start for free or see all free tools. We.Inc is free to start, with no card needed. AI building is on paid plans from $20 a month.
We.Inc is an AI-powered website builder you can resell under your own brand. Launch a branded client dashboard, bill on Stripe Connect, and deliver AI-generated websites in minutes. White-label plans start at $99 a month for 25 client sites, with a 7-day free trial and no per-site fees.