On Apache servers, the .htaccess file at the root of the WordPress directory is responsible for two critical things: URL rewriting (pretty permalinks) and a range of local directives (headers, blocks, redirects). When it is missing or empty, the site can look fine on the home page - but every internal URL returns 404.
Why this matters
WordPress lets you create pretty URLs like /about-us/ instead of /?page_id=42. For that to work on Apache, mod_rewrite rules translate the request to the internal URL. Those rules live in .htaccess. Without the file - or with empty/corrupt content - every permalink returns 404: post pages, category pages, author pages, search pages. Only the home page works because it loads index.php directly.
Beyond that, .htaccess is where most plugins and security configurations add rules: blocking xmlrpc.php, disabling directory listings, security headers (X-Frame-Options, Content-Security-Policy), HTTP-to-HTTPS redirects, hotlink protection. Without the file all of those vanish. Common reasons it goes missing: accidental deletion, a deploy that did not copy hidden files, or a switch from Apache to Nginx/LiteSpeed where .htaccess is no longer relevant.
How to detect
First confirm the server is actually Apache. On Nginx or LiteSpeed the file is not required (LiteSpeed honours it, Nginx ignores it entirely). Over SSH:
apache2 -v || httpd -v
ls -la /path/to/wordpress/.htaccessIf this is Apache and the file is absent there is a problem. Via the host's File Manager: enable Show Hidden Files. If only an empty 0-byte file exists, that too is broken. RankPlus checks file existence via realpath and verifies a reasonable size.
How to fix
- Go to Settings > Permalinks in WordPress.
- Click Save Changes without changing anything. WordPress will rewrite
.htaccessif the root directory is writable. - If nothing is created, check permissions (
chmod 755on the root;644on the file itself). Confirm there is no.htaccessinwp-adminblocking writes. - If WordPress cannot write, create the file manually via SFTP and add the standard block:
# BEGIN WordPress <IfModule mod_rewrite.c> RewriteEngine On RewriteBase / RewriteRule ^index\.php$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.php [L] </IfModule> # END WordPress - For LiteSpeed/OpenLiteSpeed - add the same block; they honour the syntax.
- For Nginx - do not create
.htaccess. Instead make surenginx.confor thesites-availablefile containstry_files $uri $uri/ /index.php?$args;.
Common mistakes
- Pasting the WordPress block twice: produces conflicting rules. Keep one block between
# BEGIN WordPressand# END WordPress. - Editing inside the markers: WordPress rewrites that section. Custom directives must live outside the markers, above or below them.
- chmod 777: an attack vector - any user can edit the file. Use 644 for the file and 755 for the directory.
- AllowOverride None in Apache config: even with the file in place, if the vhost has
AllowOverride None, it is not loaded. SetAllowOverride Allin the vhost.
Verifying the fix
Visit an existing post via its pretty permalink (for example /sample-post/) - it should load, not 404. Inspect the file via FTP - it should contain the # BEGIN WordPress block. Re-run the RankPlus scan and the status returns to green. If you have plugins that modify .htaccess (Wordfence, Yoast), re-enable them so they re-add their rules.
.htaccess before edits. A syntax error there produces a site-wide 500. If that happens, delete the file temporarily and regenerate it via Settings > Permalinks.