SadServers
  • Scenarios
  • Labs
    All Labs Linux & Bash Web Servers Databases Data Processing Docker Kubernetes CI/CD Infrastructure as Code Tooling / Applications
  • Dashboard
  • Solutions
    For Individuals For Businesses
  • Ranking
  • Newsletter
  • Documentation
    FAQ Support Pro Accounts Pro+ Accounts Business Accounts Gift API CLI/TUI Privacy Troubleshooting Interviews
  • Blog
  • Pricing
  • Gift
    Gift Purchase Gift Redeem
  • About
Log In - Sign Up
  1. Labs
  2. Apache
  3. Troubleshooting

Guide

Concepts and learning path

Troubleshooting

Failure modes and fixes

Cheatsheet

Commands to keep handy

Apache troubleshooting

Tip: apache2 vs httpd

Debian/Ubuntu use the apache2 service and apache2ctl; RHEL/CentOS use httpd and httpd -t. Examples below may use either name — systemctl status apache2 vs systemctl status httpd, journalctl -u apache2 vs journalctl -u httpd.

Service won't start after config change

Run apache2ctl configtest or httpd -t. Look for duplicate Listen directives, bad DocumentRoot paths, or syntax errors. Check the journal: journalctl -u apache2 -n 50.

403 Forbidden on a valid URL

Check directory permissions, missing Require all granted in the <Directory> block, SELinux contexts on RHEL (restorecon -Rv /var/www/), or a wrong DocumentRoot. Confirm the request hits the intended vhost — match ServerName to the Host header.

Missing index file — Apache may return 403 if Options -Indexes (directory listing disabled) and no index.html or other DirectoryIndex target exists in that folder.

502 Bad Gateway / 504 Gateway Timeout

When Apache is configured as a reverse proxy, 502/504 usually indicate backend behind ProxyPass availability or timeout issues. Verify the upstream is listening (ss -tlnp | grep 8000). Check error_log for AHxxxx proxy errors or grep 'proxy' error_log. Confirm firewall rules allow Apache to reach the backend. On RHEL/CentOS, SELinux may block outbound proxy connections — see SELinux below.

SELinux blocking Apache (RHEL/CentOS)

On Red Hat systems with SELinux enforcing, Apache may fail to serve files or reach backends even when permissions and firewall look correct. Check denials:

getenforce ausearch -m avc -ts recent | grep httpd grep httpd /var/log/audit/audit.log | tail -20

Proxy / upstream connections — allow httpd to connect to network backends:

setsebool -P httpd_can_network_connect 1

File access — wrong context on DocumentRoot often causes 403; fix with restorecon -Rv /var/www/ (see 403 Forbidden above). Prefer adjusting booleans and contexts over disabling SELinux.

Wrong site or default page served

The first matching vhost for a port acts as the default. Run apache2ctl -S to see order and names. On Debian, disable 000-default with a2dissite 000-default if it steals traffic.
Also, requests may be landing on the wrong vhost because the Host header does not match any configured ServerName or ServerAlias.

Changes made but Apache still serves old content

Config or files updated on disk, but the browser or client still sees the old page. Common causes:

  • Browser cache — hard refresh or test with curl
  • CDN or cache layer — edge still serving a cached copy
  • Reverse proxy cache — nginx, Varnish, or Cloudflare in front of Apache
  • Wrong vhost being edited — change applied to a site that is not handling the request

Useful checks:

apache2ctl -S curl -I https://site curl -I -H "Cache-Control: no-cache" https://site

Confirm Apache reloaded (systemctl reload apache2), then bypass caches: curl directly to the origin, compare DocumentRoot from apache2ctl -S to the path you edited.

Address already in use (Listen conflict)

Another process holds port 80 or 443 — often nginx, a stale Apache instance, or a duplicate Listen in config. Find it with ss -tlnp and remove the conflicting directive or stop the other service.

Module not found / invalid command

A directive requires a module that is not loaded. Run apache2ctl -M to list loaded modules. On Debian: a2enmod proxy proxy_http rewrite ssl then reload. On RHEL, confirm LoadModule lines are uncommented in the main config.

.htaccess not taking effect

A very common Apache issue — .htaccess files are silently ignored unless AllowOverride is set to something other than None in the <Directory> block for that path. This is distinct from 403 errors: the server responds, but redirects, rewrites, and auth rules in .htaccess never run.

Diagnostic: find the effective vhost and check AllowOverride in its config:

apache2ctl -S # Note the config file path for your vhost, then: grep -n AllowOverride /etc/apache2/sites-enabled/example.conf # RHEL: grep -n AllowOverride /etc/httpd/conf.d/example.conf

Set AllowOverride All (or FileInfo for rewrites only) inside <Directory /var/www/html>, run apache2ctl configtest, and reload. If still ignored, confirm the request hits that vhost (apache2ctl -S) and the .htaccess file is in the correct directory under DocumentRoot.

Rewrite rules not behaving as expected

Symptoms: URLs not rewriting, redirect loops, or WordPress/Laravel/Django front-controller routing broken (404 on clean URLs).

Checks:

apache2ctl -M | grep rewrite # or: httpd -M | grep rewrite

Verify:

  • LoadModule rewrite_module is present (or a2enmod rewrite on Debian)
  • AllowOverride allows .htaccess — see .htaccess not taking effect above
  • Rules in .htaccess or the vhost are actually loaded — no typo in RewriteBase, wrong vhost, or overridden by a later RewriteRule

After changes: apache2ctl configtest and reload. For redirect loops, check RewriteCond guards and HTTPS redirects fighting each other.

TLS / certificate issues

HTTPS failures often show in error_log as certificate or handshake errors:

# Check cert paths in the vhost SSLCertificateFile /etc/ssl/certs/example.crt SSLCertificateKeyFile /etc/ssl/private/example.key # Test TLS from the client openssl s_client -connect example.com:443 -servername example.com # Check certificate expiry openssl x509 -in cert.pem -noout -dates


On Apache 2.4.8+, the full chain can be concatenated into SSLCertificateFile, making SSLCertificateChainFile unnecessary — but many real-world configs still use separate chain files, and omitting it is a very common cause of TLS errors (handshake succeeds but browsers show "certificate not trusted").

Permission denied on logs

Apache cannot start if it cannot write to ErrorLog or CustomLog paths. Verify the Apache user (www-data, apache, or httpd depending on distro) can write to the configured log path.

ls -ld /var/log/apache2 grep -E '^(User|Group)' /etc/apache2/apache2.conf

Debugging workflow

1. Config test and vhost map

apache2ctl configtest apache2ctl -S

2. Error log while reproducing

tail -f /var/log/apache2/error.log curl -v -H "Host: www.example.com" http://127.0.0.1/

3. Confirm listeners and service

systemctl status apache2 ss -tlnp | grep ':80'

4. TLS troubleshooting

curl -vk https://127.0.0.1/

Practice scenarios

Hands-on Apache scenarios on live Linux VMs: apache

Cheatsheet →
SadServersSadServers

Real-world Linux and DevOps scenarios for hands-on learning and technical assessment.

Uptime Robot ratio (30 days)
Product
  • Scenarios
  • For Individuals
  • For Businesses
  • Pricing
Resources
  • FAQ
  • Blog
  • Newsletter
Company
  • About Us
  • Support
  • Privacy Policy
  • Terms of Service
  • Contact
Connect With Us
info@sadservers.com

Made in Canada 🇨🇦
Updated: 2026-06-13 16:06 UTC – 2d2950a