Common causes
- The hidden .htaccess file was not copied because the FTP client or archive skipped dotfiles
- mod_rewrite is disabled or AllowOverride None is set, so Apache ignores .htaccess
- The new server runs Nginx or OpenLiteSpeed with no try_files rule for the front controller
- Document root points to the wrong folder, such as public_html instead of public/ for Laravel
- Moving from Windows/macOS to Linux exposed filename case mismatches (Image.JPG vs image.jpg)
- Old domain or subfolder still stored in the database, so links point to paths that do not exist
How to fix it
- Check that .htaccess exists. Enable "show hidden files" in File Manager or your FTP client and confirm .htaccess is in the site root. For WordPress, saving Settings > Permalinks regenerates it if the folder is writable.
- Confirm rewrites are allowed (Apache). On a VPS run sudo a2enmod rewrite and set AllowOverride All (or FileInfo) for the site directory, then restart Apache. Shared hosts normally have this on already.
- Add a front-controller rule (Nginx). Nginx ignores .htaccess. Add try_files $uri $uri/ /index.php?$args; to the location / block, run sudo nginx -t and reload.
- Verify the document root. Make sure the domain points to the folder holding index.php. Laravel and Symfony apps must point to public/; a subfolder install may need RewriteBase adjusted.
- Update URLs in the database. If links still use the old domain or path, run a serialization-safe search and replace (WP-CLI wp search-replace or a dump tool) instead of a plain SQL REPLACE.
- Check filename case. Linux file systems are case-sensitive. Rename files or fix references so the case matches exactly, especially images and includes.
.htaccess (standard WordPress rules)
# 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 How to stop it happening again
- Migrate with a full archive (tar or ZIP) that includes dotfiles, then verify .htaccess
- Check the target server type (Apache, Nginx, LiteSpeed) before moving
- Run a link check right after DNS switches