How to Secure Your Apache Web Server

How to secure your Apache Web Server

I’ve inherited more than one Apache server that had been running untouched for years — default configuration, ancient module list, version numbers broadcast in every response header. Nothing had gone wrong yet, but it was only a matter of time. Securing Apache isn’t a box I check once during setup; it’s a habit I keep up for as long as the server stays online.

Here’s the layered approach I use every time: shrinking the attack surface, hardening the configuration, controlling access, encrypting traffic, and keeping an eye on things afterward.

Why I Take Apache Security Seriously

An insecure Apache server can end up:

  • Serving malware to visitors
  • Leaking files it was never supposed to expose (backups, .env files, source code)
  • Acting as a pivot point into the rest of my network
  • Getting conscripted into a botnet
  • Quietly tanking SEO rankings and user trust once something goes wrong

Because Apache is often the public front door to an entire stack, its security posture affects everything sitting behind it.

Prerequisites

  • Root or sudo access
  • Apache already installed (httpd on RHEL-based systems, apache2 on Debian-based)
  • Familiarity with config locations:
    • RHEL/CentOS: /etc/httpd/conf/httpd.conf, /etc/httpd/conf.d/
    • Debian/Ubuntu: /etc/apache2/apache2.conf, /etc/apache2/sites-available/

Step 1: Keep Apache and Modules Updated

Most real-world Apache compromises I’ve read about — and the one I helped clean up once — exploited vulnerabilities that already had patches available.

# Debian/Ubuntu
sudo apt update && sudo apt upgrade apache2

# RHEL/CentOS
sudo dnf update httpd

I enable automatic security updates where policy allows, and at minimum I subscribe to security advisories for my distro and for Apache itself.

Step 2: Hide Version Information

By default, Apache happily tells everyone its version and OS in the response headers and error pages — a head start I don’t want to give attackers.

ServerTokens Prod
ServerSignature Off

ServerTokens Prod trims the Server header down to just Apache. ServerSignature Off removes the version footer on error pages.

Step 3: Disable Modules I Don’t Need

Every enabled module is more attack surface. I list what’s active:

apache2ctl -M          # Debian/Ubuntu
httpd -M                # RHEL/CentOS

Then I disable anything unused, especially mod_status, mod_info, mod_userdir, and mod_autoindex:

sudo a2dismod status
sudo a2dismod autoindex
sudo systemctl restart apache2

On RHEL-based systems I comment out the matching LoadModule lines instead.

Step 4: Restrict Directory Access

I set a strict default in the main config, then explicitly open up only what’s needed:

<Directory />
    AllowOverride None
    Require all denied
</Directory>

<Directory /var/www/html>
    Options -Indexes -Includes
    AllowOverride None
    Require all granted
</Directory>

Step 5: Disable Directory Listing and Symlink Following

<Directory /var/www/html>
    Options -Indexes -FollowSymLinks
</Directory>

Directory listing can expose files I never meant to publish; FollowSymLinks can be abused to escape the intended document root if something else is misconfigured.

Step 6: Protect Sensitive Files

<FilesMatch "^\.">
    Require all denied
</FilesMatch>

<FilesMatch "(\.bak|\.old|\.orig|\.save|~)$">
    Require all denied
</FilesMatch>

<DirectoryMatch "/\.git">
    Require all denied
</DirectoryMatch>

Step 7: Enforce HTTPS

I install a TLS certificate (Let’s Encrypt covers most of my sites for free) and redirect all HTTP to HTTPS:

<VirtualHost *:80>
    ServerName example.com
    Redirect permanent / https://example.com/
</VirtualHost>

I’ve got a dedicated post walking through full SSL/HTTPS setup if you want the details.

Step 8: Add Security Headers

sudo a2enmod headers
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
Header always set Content-Security-Policy "default-src 'self'"

I always test Content-Security-Policy carefully — an overly strict one has broken legitimate functionality on me more than once.

Step 9: Limit Request Sizes and Timeouts

LimitRequestBody 10485760
Timeout 30
KeepAliveTimeout 5

Step 10: Run Apache as a Restricted User

I never let Apache run as root for normal request handling:

# /etc/apache2/envvars (Debian) or httpd.conf (RHEL)
User www-data
Group www-data

I make sure web root files are owned appropriately and not writable by the Apache user unless a specific app genuinely needs it.

Step 11: Tune Logging

LogLevel warn
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined

Logs are what let me piece together what happened after the fact, and they feed tools like fail2ban.

Step 12: Add a Web Application Firewall

mod_security with the OWASP Core Rule Set gives me application-layer protection against SQL injection, XSS, and similar attacks:

sudo apt install libapache2-mod-security2
sudo a2enmod security2
sudo cp /etc/modsecurity/modsecurity.conf-recommended /etc/modsecurity/modsecurity.conf

I only flip SecRuleEngine On once I’ve tuned the rules enough to avoid blocking legitimate traffic.

Mistakes I See (and Have Made)

  • Leaving ServerTokens Full, broadcasting exact version numbers.
  • Forgetting to remove default sample content and admin pages.
  • Running Apache with overly permissive file ownership.
  • Enabling mod_security in blocking mode without testing first, which rejects legitimate traffic.
  • Not monitoring logs, missing early warning signs of a compromise.

Security Best Practices Checklist

  • Keep Apache, modules, and the OS patched.
  • Minimize enabled modules.
  • Enforce HTTPS everywhere.
  • Apply strict directory permissions, disable indexing.
  • Use security headers and a WAF.
  • Pair with fail2ban and a host firewall.
  • Regularly audit configuration with apachectl -t and vulnerability scanners.

Performance Considerations

Security and performance aren’t opposites in my experience. Disabling unused modules cuts memory footprint per worker. Enabling mod_deflate and mod_expires improves performance without weakening security. Rate limiting protects both security and availability under load.

Troubleshooting

Site broken after adding Content-Security-Policy I temporarily switch to Content-Security-Policy-Report-Only to test without enforcing, then tighten gradually.

mod_security blocking legitimate requests I check /var/log/apache2/modsec_audit.log for the rule ID triggered and add a targeted exception rather than disabling the module wholesale.

Configuration won’t reload I always test before restarting:

sudo apachectl configtest
sudo systemctl restart apache2

FAQs

Is Apache inherently less secure than Nginx? Not in my view — both can be equally secure or insecure depending on configuration. Apache’s flexibility means more configuration surface, which needs more deliberate hardening.

Do I need mod_security for a small personal site? It adds value but isn’t mandatory for low-risk sites. I prioritize HTTPS, updates, and basic hardening first.

How often should I audit my Apache configuration? At minimum after every major update, and I like to revisit it quarterly alongside a broader security review.

Summary and Key Takeaways

  • Securing Apache is layered: patch management, minimal attack surface, strict access controls, encryption, and monitoring.
  • Small changes — hiding version tokens, disabling directory listing, adding security headers — meaningfully cut risk for very little effort.
  • A WAF and fail2ban give me active defense against automated attacks.
  • I revisit hardening regularly instead of treating it as a one-time setup task.

References

  • Apache HTTP Server Security Tips: https://httpd.apache.org/docs/current/misc/security_tips.html
  • OWASP ModSecurity Core Rule Set: https://owasp.org/www-project-modsecurity-core-rule-set/
  • Mozilla SSL Configuration Generator: https://ssl-config.mozilla.org/
  • fail2ban Documentation: https://www.fail2ban.org/
Total
1
Shares

Leave a Reply

Previous Post
How to set up server-side includes (SSI) in Apache

How to Set Up Server-Side Includes (SSI) in Apache

Next Post
How to configure a firewall for Apache

How to Configure a Firewall for Apache

Related Posts