Many PHP apps, WordPress included, ship an .htaccess file with rewrite rules for pretty URLs. On a fresh VPS those rules often do nothing, and every page except the home page returns 404. Two settings cause almost every case: the rewrite module is not loaded, or Apache is told to ignore .htaccess files. This guide fixes both and shows how to confirm it.
Before you start
- Apache running on Ubuntu, Debian, AlmaLinux or Rocky Linux.
- A working virtual host for your site. If you do not have one yet, follow Set up Apache virtual hosts.
- A user with
sudorights.
Why.htaccess is ignored
Apache reads .htaccess files only where the AllowOverride directive allows it. The stock Ubuntu and Debian config sets AllowOverride None for /var/www/, and the RHEL-family config does the same for /var/www/html. With None, Apache never even opens the file, so even a deliberate syntax error inside it does nothing.
Separately, RewriteEngine and RewriteRule come from mod_rewrite. If the module is not loaded and AllowOverride is on, you get a 500 error instead, because Apache does not recognise the directive.
Enable mod_rewrite
Ubuntu and Debian
sudo a2enmod rewriteThe command prints a reminder to restart Apache. Do that after the next step.
AlmaLinux and Rocky Linux
The module is loaded by default from /etc/httpd/conf.modules.d/00-base.conf. Confirm it:
httpd -M | grep rewriteYou should see rewrite_module (shared). On Ubuntu and Debian the same check is apache2ctl -M | grep rewrite.
Set AllowOverride in the Directory block
Edit your site's virtual host file, for example /etc/apache2/sites-available/example.com.conf or /etc/httpd/conf.d/example.com.conf. Add or change the <Directory> block so its path matches your DocumentRoot exactly:
<VirtualHost *:80>
ServerName example.com
DocumentRoot /var/www/example.com/public
<Directory /var/www/example.com/public>
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>
</VirtualHost>Points that trip people up:
- The path must be the folder that holds the
.htaccessfile, or a parent of it. A block for/var/www/htmldoes nothing for/var/www/example.com/public. AllowOverrideis only valid inside<Directory>. Putting it directly in<VirtualHost>gives a config error.+FollowSymLinks(or+SymLinksIfOwnerMatch) must be on for rewrite rules in.htaccessto run.- If you do not want to allow everything,
AllowOverride FileInfois enough for rewrite rules, and you can addAuthConfig,IndexesorLimitas needed.
Note: AllowOverride All costs a little speed, because Apache looks for .htaccess in every folder on the path for each request. On a busy site you can move the rules into the vhost and set AllowOverride None. For most sites the difference is small.
Restart and test the config
Check the syntax, then restart. A restart (not just a reload) is the safe choice after enabling a module:
sudo apachectl configtest
sudo systemctl restart apache2 # Ubuntu and Debian
sudo systemctl restart httpd # AlmaLinux and RockyIf configtest does not print Syntax OK, fix the reported line before restarting, or Apache will not come back up.
Check it works
Create a test rule. In your document root, add a file .htaccess with:
RewriteEngine On
RewriteRule ^rewrite-test$ /index.html [L]Now request the made-up URL:
curl -I http://example.com/rewrite-testA 200 OK means mod_rewrite and .htaccess both work: Apache served index.html for a path that does not exist. A 404 Not Found means the .htaccess file is still being ignored. A 500 Internal Server Error means the file is read but the module is missing or a line is wrong.
Remove the test rule afterwards, or replace it with your app's real rules. For WordPress, go to Settings → Permalinks and click Save Changes so it writes its own block.
Tip: A quick way to see whether Apache reads .htaccess at all is to put a line of nonsense in it. If the site still loads normally, the file is being ignored.
Troubleshooting
- Still 404 on every inner page: the
<Directory>path does not match yourDocumentRoot, or another, more specific<Directory>block setsAllowOverride None. Search for it withgrep -Rn AllowOverride /etc/apache2/(or/etc/httpd/). - 500 error right after adding
.htaccess: read the site's error log.Invalid command 'RewriteEngine'means the module is not loaded; anything else points at a bad line. See Fix 500 Internal Server Error on Apache. Options FollowSymLinks or SymLinksIfOwnerMatch is off: add+FollowSymLinksto theOptionsline in the<Directory>block.- Changes in
.htaccesswork locally but not on the server: the file was uploaded without the leading dot, or your FTP client hides dotfiles. Check withls -la. - A control panel or Nginx sits in front: Nginx ignores
.htaccesscompletely. If Nginx serves the site, convert the rules to Nginx syntax instead.
Next steps
- Write the rules you need: Apache redirects with.htaccess.
- Protect a folder with a password: Password protect a folder in Apache.
