Hardening Apache reduces the chance that routine internet noise—scanners, bots, and opportunistic exploits—turns a minor configuration mistake into data exposure or an avoidable outage.
Most Apache security work is about shrinking what the server advertises and accepts: loaded modules, reachable URLs, directory indexing, allowed HTTP methods, and the TLS/HTTP headers negotiated at the edge. Those controls live in the global config, per-virtual-host blocks, and sometimes per-directory rules, so the effective posture is the sum of many small decisions.
Configuration differs across platforms (for example, /etc/apache2/ on Debian-style systems versus /etc/httpd/ on RHEL-style systems), and even “safe” changes can break real applications. Apply one change at a time, validate syntax before reloads, and treat irreversible protections such as HSTS as a final step after HTTPS behavior is confirmed stable.
Related: How to redirect HTTP to HTTPS in Apache
Related: How to hide Apache server signatures
Related: How to analyze threats in Apache logs
Steps to secure Apache web server:
- Inventory loaded Apache modules.
$ apachectl -M Loaded Modules: core_module (static) so_module (static) watchdog_module (static) http_module (static) log_config_module (static) logio_module (static) version_module (static) unixd_module (static) access_compat_module (shared) alias_module (shared) auth_basic_module (shared) authn_core_module (shared) authn_file_module (shared) authz_core_module (shared) authz_host_module (shared) authz_user_module (shared) autoindex_module (shared) brotli_module (shared) ##### snipped #####
Remove or disable modules not required by the site to reduce exposed features and directive surface area.
On some systems the command is apache2ctl instead of apachectl.
Related: How to view a list of modules in Apache
Related: How to enable or disable Apache modules
Related: How to install Apache modules - Check exposed server identity headers from the client side.
$ curl -skI https://host.example.net/ | grep -iE '^(server|x-powered-by):' server: Apache
Some headers come from the application stack (for example, PHP), not Apache itself.
- Confirm clear HTTP requests redirect to HTTPS.
$ curl -I http://host.example.net/ HTTP/1.1 301 Moved Permanently Date: Mon, 29 Dec 2025 06:54:29 GMT Server: Apache/2.4.58 (Ubuntu) Location: https://host.example.net/ Content-Type: text/html; charset=iso-8859-1
HSTS should be enabled only after HTTPS and redirects are confirmed stable, because browsers cache the policy.
- Probe legacy TLS protocol negotiation to ensure old versions are disabled.
$ openssl s_client -connect host.example.net:443 -servername host.example.net -tls1 2070A397FFFF0000:error:0A0000BF:SSL routines:tls_setup_handshake:no protocols available:../ssl/statem/statem_lib.c:104: CONNECTED(00000003) --- no peer certificate available ##### snipped #####
A failure such as no protocols available indicates legacy TLS versions are disabled.
- Verify OCSP stapling status when using public certificates.
$ openssl s_client -connect host.example.net:443 -servername host.example.net -status CONNECTED(00000003) OCSP response: no response sent ##### snipped #####
Look for an OCSP response line to confirm whether stapling is active.
- Verify administrative endpoints are blocked or allowlisted.
$ curl -I http://192.0.2.40/server-status HTTP/1.1 403 Forbidden Date: Mon, 29 Dec 2025 08:27:17 GMT Server: Apache Content-Type: text/html; charset=iso-8859-1
Administrative endpoints should be blocked by default, or restricted to an allowlist.
- Confirm directory listings are disabled for served directories.
$ curl -i http://host.example.net/mysite/ HTTP/1.1 403 Forbidden Date: Mon, 29 Dec 2025 09:26:51 GMT Server: Apache Content-Length: 199 Content-Type: text/html; charset=iso-8859-1 <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html><head> <title>403 Forbidden</title> ##### snipped #####
Directory URLs should return application content, a controlled index page, or an error.
- Deny access to common sensitive files and hidden paths.
$ curl -I -H "Host: host.example.net" http://127.0.0.1/.env HTTP/1.1 403 Forbidden Date: Mon, 29 Dec 2025 09:16:31 GMT Server: Apache Content-Type: text/html; charset=iso-8859-1 $ curl -I -H "Host: host.example.net" http://127.0.0.1/.git/config HTTP/1.1 403 Forbidden Date: Mon, 29 Dec 2025 09:16:31 GMT Server: Apache Content-Type: text/html; charset=iso-8859-1
Start with common leak targets such as dotfiles, VCS directories, and config backups.
- Limit request bodies to the smallest practical size.
Oversized requests should fail quickly with 413 instead of consuming CPU, memory, or disk.
- Confirm unsafe HTTP methods are rejected when the application does not require them.
$ curl -i -X TRACE -H 'Host: host.example.net' http://127.0.0.1/ HTTP/1.1 405 Method Not Allowed Date: Mon, 29 Dec 2025 09:14:47 GMT Server: Apache Allow: Content-Length: 222 Content-Type: text/html; charset=iso-8859-1 ##### snipped #####
Unexpected 2xx responses on unsafe methods indicate the server accepts them.
- Verify browser-facing security headers are present on real responses.
$ curl -I -H 'Host: host.example.net' http://127.0.0.1/ | grep -iE '^(content-security-policy|x-frame-options|x-content-type-options|referrer-policy):' X-Frame-Options: SAMEORIGIN Content-Security-Policy: frame-ancestors 'self'
Header policies should match the application’s actual behavior to avoid breaking legitimate content.
- Configure basic abuse controls for hostile clients.
Rate limits and connection limits should be validated under load to avoid blocking legitimate traffic.
Related: How to protect Apache against DoS attacks
Related: How to block user agents in Apache
Related: How to prevent hotlinking in Apache
Related: How to limit connection bandwidth in Apache - Deploy a web application firewall when exposed to untrusted traffic.
Deploy in detection mode first when possible to reduce the risk of accidental outages.
Related: How to enable ModSecurity in Apache
- Review logs and rotation policies for security visibility.
Ensure rotation and retention are configured before enabling verbose logging.
- Validate configuration syntax after each change.
$ sudo apachectl configtest Syntax OK
Prefer reload or graceful restarts when supported by the change.
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.
