You deploy, load the site, and get a plain white page: Not Found. The requested URL was not found on this server.
The site worked yesterday and the code is the same. Something about how the files landed, or how the web server finds them, has changed.
This guide covers what the message means and the causes that show up after a deploy, with fixes for Apache and Nginx, single-page apps, Laravel and WordPress.
What the error means
The requested URL was not found on this server
is the default 404 page of Apache, and it is what many frameworks and hosts show too. Nginx words it differently (404 Not Found
with nginx underneath), but the cause is the same: the web server received the request, looked for something to serve at that path, and found nothing.
That tells you the server is up and reachable. A 404 is a routing or file-location problem, not an outage. Compare that with a 502 Bad Gateway, where the web server cannot reach the application behind it.
Check these first
Run through these before changing any config. They find most deploy-related 404s in a few minutes.
- Does the file exist on the server? SSH in and list the web root. If
index.htmlorindex.phpis missing, the deploy did not put it where the server looks. - Is the home page broken, or only inner pages? If
/works but/aboutreturns 404, the problem is URL rewriting. If/also fails, the problem is the web root or the index file. - Read the error log. Apache usually logs to
/var/log/apache2/error.log(or/var/log/httpd/error_log), Nginx to/var/log/nginx/error.log. The log names the exact path the server tried to open. - Test from the command line.
curl -I https://example.com/aboutshows the status code without browser caching getting in the way.
The error log line is the most useful clue. A message such as File does not exist: /var/www/example.com/about shows you the path the server is checking, which you can compare with where your files actually are.
Cause 1: the web root points at the wrong folder
The most common deploy-related cause. Your server serves /var/www/example.com, but your project's public files live in /var/www/example.com/public (Laravel, Symfony), /var/www/example.com/dist or build (most JavaScript frameworks), or a release folder.
Signs: the home page fails, the error log shows the server looking in a folder that has your project in a subfolder.
Fix: point the web server at the right folder.
server {
listen 80;
server_name example.com;
root /var/www/example.com/public;
index index.php index.html;
}
<VirtualHost *:80>
ServerName example.com
DocumentRoot /var/www/example.com/public
</VirtualHost>
If you deploy each release into its own folder and switch a current link to the newest one, check the link points at a release that exists and that the web root follows it. A zero downtime deployment depends on that link being updated at the end of the release.
Cause 2: the build output was not deployed
You build a React, Vue, Next.js or Astro site, and the build step writes to dist/, build/ or out/. If the build did not run, or the output folder is ignored by your repository or deploy settings, the server receives source files and no site.
Fix: run the build before the files are transferred, and deploy the output folder. A build pipeline does this on every deploy, so the built files, not just the source, reach the server. Our guides to building and deploying a static site and deploying a Next.js static export show the full setup.
Cause 3: .htaccess is missing or ignored (Apache)
Apache reads per-folder rules from a file called .htaccess. Laravel, WordPress and many frameworks depend on it to send every request to one entry file such as index.php. If the file is missing, only exact file paths work and every pretty
URL returns 404.
Two things go wrong after a deploy:
- The file did not arrive. Files that start with a dot are easy to lose: they can be in
.gitignore, in an exclude list, or skipped by a manual upload. Check that.htaccessis committed to your repository and is not excluded from deployment. - Apache is not reading it. The folder needs
AllowOverride All(or at least the directives you use), andmod_rewritemust be on.
<Directory /var/www/example.com/public>
AllowOverride All
Require all granted
</Directory>
On Debian and Ubuntu, enable the module and reload:
sudo a2enmod rewrite
sudo apachectl configtest
sudo systemctl reload apache2
Cause 4: no rewrite rule for single-page apps and frameworks
A single-page app (React, Vue, Angular) has one real file, index.html. Routes like /dashboard exist only in JavaScript. A direct visit or a refresh on /dashboard makes the server look for a file called dashboard, find nothing and return 404. The home page works because / maps to index.html.
The fix is to send any path that is not a real file back to index.html.
Nginx:
location / {
try_files $uri $uri/ /index.html;
}
Apache (.htaccess):
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ /index.html [L]
PHP frameworks follow the same idea but send the request to index.php:
# Laravel
location / {
try_files $uri $uri/ /index.php?$query_string;
}
# WordPress
location / {
try_files $uri $uri/ /index.php?$args;
}
For a full Laravel setup, including the web server and release process, see our guide to deploying Laravel with build pipelines and zero downtime. On shared hosting without SSH, deploying Laravel to cPanel covers where the files need to go.
After changing Nginx config, test it and reload:
sudo nginx -t
sudo systemctl reload nginx
Cause 5: case-sensitive file names
macOS and Windows treat Logo.png and logo.png as the same file by default. Linux servers do not. A page that works on your laptop returns 404 on the server because the code asks for /images/logo.png and the file is Logo.png.
Fix: make the file name and every reference match exactly, and develop with the same case you will deploy. If Git has recorded the old case, rename the file with git mv, since a plain rename in the file manager may not register as a change on a case-insensitive system.
Cause 6: WordPress permalinks
After moving or deploying a WordPress site, posts and pages can return 404 while the home page works. WordPress writes its rewrite rules into .htaccess when permalinks are saved, and the file may not have come across with the deploy.
Fix: in the WordPress admin, go to Settings, then Permalinks, and click Save Changes without changing anything. That regenerates the rules. If the file is not writable, copy the rules WordPress shows you into .htaccess yourself. For agencies deploying many sites, a staged WordPress release workflow keeps these files under version control so they ship with every release.
Restore service first, then fix
If production is returning 404 right now, bring it back before you debug. A one-click rollback to the previous deployment puts the last working files back while you work out what changed. Then reproduce the problem on a staging server and fix it there.
Want deploys that carry your server config and build output every time? Start a free DeployHQ trial and deploy from Git on every push.
Stop it happening again
- Keep web server config in the repository (
.htaccess, an Nginx include, aCaddyfile) so it deploys with the code. Our comparison of Nginx, Apache and Caddy shows the equivalent rewrite config for each, and the Nginx cheatsheet covers the commands. - Run the build in the pipeline, not on a laptop, so the output always matches the commit.
- Add a post-deploy check. A request for the home page and one inner page, failing the deploy on any non-200, catches this class of error before a visitor does.
- Deploy from Git automatically with automatic deployments, so production is always built the same way.
Frequently asked questions
Why do I get a 404 only after refreshing the page?
Your site is a single-page app, and the server has no rule to send unknown paths back to index.html. Add the try_files rule (Nginx) or the rewrite rule (Apache) shown above.
Is not found on this server
an Apache or an Nginx error?
The exact wording is Apache's default. Nginx shows 404 Not Found
. Both mean the server received the request and found nothing to serve at that path.
My .htaccess is there but ignored. Why?
Usually AllowOverride is set to None for that folder, or mod_rewrite is not enabled. Set AllowOverride All, enable the module, then reload Apache.
Does a 404 hurt SEO?
A few 404s on removed pages are normal. A deploy that makes live pages return 404 is different. Google will drop those URLs if they keep failing, so fix it quickly or roll back.
Questions or feedback? Email support@deployhq.com or find us on X at @deployhq.