How to Secure Your Apache Web Server

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:

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

Prerequisites

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)

Security Best Practices Checklist

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

References

Exit mobile version