Apache and nginx fail in similar ways but name things differently, and an administrator who knows one often loses time on the other. When a site is down, you need the same four answers fast: is the server running, is it listening, what does the config say, and what does the error log say. This guide puts the commands for both servers side by side, then covers the most common errors and the difference between restarting and reloading.
Paths below follow typical packages. Debian and Ubuntu use apache2, while RHEL, Rocky, AlmaLinux and Fedora use httpd. Always confirm on your own system.
The four-question checklist
- Is the process running?
- Is it listening on the expected ports?
- Does the configuration pass its syntax test?
- What does the error log say?
1. Is it running?
# nginx
sudo systemctl status nginx --no-pager
# Apache (Debian/Ubuntu)
sudo systemctl status apache2 --no-pager
# Apache (RHEL family)
sudo systemctl status httpd --no-pager
# If the service failed to start, the journal usually has the reason
sudo journalctl -u nginx -n 50 --no-pager
sudo journalctl -u apache2 -n 50 --no-pager
2. Is it listening?
sudo ss -ltnp | grep -E ':(80|443)\b'
You should see nginx, apache2, or httpd in the process column. If another program owns the port, you have a conflict (see "Address already in use" below). From outside the server, use the पोर्ट चेकर to see whether ports 80 and 443 are reachable through your firewall.
3. Does the config pass its test?
| Task | nginx | Apache | |
|---|---|---|---|
| Syntax test | sudo nginx -t | sudo apachectl configtest or sudo apache2ctl -t or sudo httpd -t | |
| Dump full effective config | sudo nginx -T | sudo apachectl -S (virtual hosts), -M (modules), httpd -t -D DUMP_INCLUDES | |
| Show version and build options | nginx -V | apachectl -V | |
| List loaded modules | `nginx -V 2>&1 \ | grep -o 'with-[a-z_]*'` | apachectl -M |
Always test before applying changes. nginx -t reports the file and line of an error. Apache's configtest prints Syntax OK when it passes.
apachectl -S is especially valuable. It shows which virtual host answers for each name and port, plus the main config file locations. A surprising number of "wrong site shows up" problems are visible there:
sudo apachectl -S
sudo nginx -T | grep -E "server_name|listen"
4. What does the log say?
| Log | nginx | Apache (Debian) | Apache (RHEL) |
|---|---|---|---|
| Error log | /var/log/nginx/error.log | /var/log/apache2/error.log | /var/log/httpd/error_log |
| Access log | /var/log/nginx/access.log | /var/log/apache2/access.log | /var/log/httpd/access_log |
Per-site logs are common, so check the ErrorLog and CustomLog directives (Apache) or error_log and access_log directives (nginx) in the vhost.
sudo tail -f /var/log/nginx/error.log
sudo tail -f /var/log/apache2/error.log
# Top status codes in the last 10,000 requests (default combined format)
sudo tail -n 10000 /var/log/nginx/access.log | awk '{print $9}' | sort | uniq -c | sort -rn
The HTTP स्टेटस चेकर shows the code as the outside world sees it, which you can compare with the log.
Restart vs reload
| Action | nginx | Apache | Effect |
|---|---|---|---|
| Reload | sudo systemctl reload nginx | sudo systemctl reload apache2 | Re-reads config, workers finish current requests gracefully |
| Restart | sudo systemctl restart nginx | sudo systemctl restart apache2 | Stops and starts the service, dropping active connections |
Use reload for configuration changes. It is the graceful option: nginx starts new workers with the new config and lets old workers finish, and Apache's graceful reload does the equivalent. If the new config has a syntax error, a reload leaves the old config running, which is why you test first.
Use restart when:
- Loading or unloading a module that reload does not handle.
- Changing something that requires a full process restart, such as listening addresses or ports in some setups.
- The process is wedged and not responding.
- You've changed the user or the main-process-level limits.
A habit worth building:
sudo nginx -t && sudo systemctl reload nginx
sudo apachectl configtest && sudo systemctl reload apache2
Common startup errors
Address already in use
nginx: bind() to 0.0.0.0:80 failed (98: Address already in use) Apache: (98)Address already in use: AH00072: make_sock: could not bind to address [::]:80
Another process holds the port, often the other web server, or an old instance.
sudo ss -ltnp | grep ':80\b'
Stop the conflicting service or change the listen port. Installing both Apache and nginx on one box without changing ports is a classic cause.
Unknown directive or invalid command
nginx: unknown directive "xyz" in /etc/nginx/sites-enabled/site:12 Apache: Invalid command 'RewriteEngine', perhaps misspelled or defined by a module not included in the server configuration
A typo, or a missing module. For Apache, enable it:
sudo a2enmod rewrite headers ssl proxy_fcgi
sudo systemctl restart apache2
In nginx, some directives need modules compiled in. Check nginx -V.
Certificate or key problems
nginx: cannot load certificate "...": BIO_new_file() failed or key values mismatch Apache: AH02562: Failed to configure certificate
Check the paths, permissions, and that the certificate and private key belong together. A mismatch means one was replaced without the other. Test with the SSL Checker once running, and read SSL/TLS certificate errors explained.
openssl x509 -noout -modulus -in cert.pem | openssl md5
openssl rsa -noout -modulus -in key.pem | openssl md5
The two hashes must match for RSA keys.
Common runtime errors
403 Forbidden
- nginx:
directory index of "/var/www/site/" is forbiddenmeans no index file and autoindex is off.open() "..." failed (13: Permission denied)means the nginx user cannot read the path, including every parent directory. - Apache:
AH01630: client denied by server configurationorAH01276: Cannot serve directory ...: No matching DirectoryIndex. Check the<Directory>block hasRequire all grantedand the rightDirectoryIndex.
Check filesystem access as the web user:
sudo -u www-data stat /var/www/site/index.html
namei -l /var/www/site/index.html
namei -l reveals which parent directory lacks the execute bit.
404 where the file exists
- Wrong
root(nginx) orDocumentRoot(Apache), or the wrong vhost answering. Check which block matched withapachectl -Sor by adding a temporaryadd_header X-Debug $server_name;in nginx. - Missing rewrite rules for a framework or CMS: nginx needs
try_files $uri $uri/ /index.php?$args;, and Apache needsAllowOverride Allfor.htaccessrules to work, along withmod_rewriteenabled.
500 Internal Server Error
- Apache: a bad
.htaccessis the top cause, shown in the error log as.htaccess: Invalid commandorRewriteRule: bad flag delimiters. Rename it temporarily to confirm. - nginx: a 500 comes from a rewrite loop (
rewrite or internal redirection cycle) or from the upstream. See fix 500 internal server error.
502 and 504
These come from proxying and are covered in nginx 502 and 504 timeout tuning और fix 502 bad gateway. On Apache, the equivalent log messages include AH01114: HTTP: failed to make connection to backend and AH00957, and the timeout is ProxyTimeout (or Timeout as the default fallback).
503 and worker exhaustion
Apache logs AH00161: server reached MaxRequestWorkers setting, consider raising the MaxRequestWorkers setting. All workers are busy, and new requests wait or fail. Check your MPM and limits:
apachectl -V | grep -i mpm
sudo apachectl -M | grep mpm
Raising MaxRequestWorkers without enough RAM leads to swapping or out-of-memory kills. Compute it from memory per worker. With the event MPM and PHP-FPM, memory per request is much lower than with prefork and mod_php. nginx uses worker_processes auto; and worker_connections rather than a worker-per-request model, and logs worker_connections are not enough when exhausted. See fix 503 service unavailable.
Configuration differences that trip people up
| Topic | nginx | Apache |
|---|---|---|
| Per-directory overrides | Not supported; edit config and reload | .htaccess (needs AllowOverride) |
| Enable a site | Symlink into sites-enabled (Debian) and reload | a2ensite site.conf and reload |
| Request matching | server_name plus location blocks, with specific matching rules for order | <VirtualHost> and <Directory>/<Location> merged in a defined order |
| PHP | Always via FastCGI (PHP-FPM) | mod_php or PHP-FPM through proxy_fcgi |
| Config changes take effect | On reload | On reload (and .htaccess changes take effect immediately) |
The .htaccess row explains many "my change did nothing" reports: moving a site from Apache to nginx means translating rewrite rules into nginx config, since nginx ignores .htaccess entirely.
When the server is fine but the site is down
Don't assume the web server is at fault. Work outward:
curl -I http://127.0.0.1/ -H "Host: example.com"on the server confirms the web server answers locally.- If it does, test from outside with the HTTP Header Checker to find firewall, DNS, or CDN issues.
- Verify DNS and the certificate. See why is my website down.
- Check the disk:
df -handdf -i. A full disk stops logging and can crash services.
curl -sI http://127.0.0.1/ -H "Host: example.com"
df -h; df -i
free -m
अगले कदम
- Check ports and status from outside with the पोर्ट चेकर और HTTP स्टेटस चेकर.
- Tune proxy timeouts in nginx 502 and 504 timeout tuning.
- Walk through why is my website down for the full diagnosis.
- Get alerted with the अपटाइम मॉनिटर.
सामान्य प्रश्न
Should I restart or reload after editing the config?
Reload, after a successful syntax test. Reload applies changes without dropping active connections, and keeps the old config if the new one fails to load.
Why does my .htaccess do nothing on nginx?
nginx does not read .htaccess files. Translate the rules into nginx location and rewrite or try_files directives in the server config.
How do I find which virtual host is answering?
On Apache, run apachectl -S. On nginx, run nginx -T and search for server_name and listen, or add a temporary response header showing $server_name.
Where are the logs if I don't see them in /var/log?
They may be configured per site or sent to the journal. Run nginx -T or apachectl -S, look for error_log or ErrorLog directives, and check journalctl -u <service>.
Get notified when this guide updates
Plus occasional practical tips on uptime and monitoring, nothing else. Unsubscribe anytime.
यह पेज सामान्य जानकारी है, जिसे हमारी संपादकीय टीम ने लिखा है और दस्तावेज़ीकरण बदलने पर अपडेट किया जाता है। सर्वर और प्रदाता अलग-अलग होते हैं, इसलिए बदलाव पहले सुरक्षित तरीके से जाँचें। देखें: संपादकीय नीति और अस्वीकरण.