Post

Apache2 Comprehensive Guide - Installation, Configuration, and Security Hardening

Apache HTTP Server (Apache2) is one of the world's most popular web servers. Developed and maintained by the Apache Software Foundation, it's an open-source, cross-platform web server that powers a significant percentage of websites on the internet.

Apache2 Comprehensive Guide - Installation, Configuration, and Security Hardening

Apache2 Web Server Guide

Table of Contents

  1. Introduction
  2. Installation
  3. Basic Configuration
  4. Virtual Hosts
  5. Security Configurations
  6. Performance Tuning
  7. Complex Issues and Solutions
  8. Advanced Functionality
  9. Troubleshooting
  10. References

Installation

On Debian/Ubuntu Systems with Security Hardening

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# Update package lists
sudo apt update

# Install Apache2 with minimal modules for security
sudo apt install apache2

# Install security modules
sudo apt install libapache2-mod-security2 libapache2-mod-qos

# Enable only essential modules and disable unnecessary ones
sudo a2enmod ssl
sudo a2enmod headers
sudo a2enmod security2
sudo a2enmod rewrite
sudo a2enmod qos

# Disable dangerous or unnecessary modules
sudo a2dismod status
sudo a2dismod autoindex
sudo a2dismod userdir
sudo a2dismod info
sudo a2dismod cgi
sudo a2dismod env

# Create a directory with secure permissions for SSL certificates
sudo mkdir -p /etc/apache2/ssl
sudo chmod 700 /etc/apache2/ssl

# Modify default file permissions
sudo chmod 750 /var/www/html
sudo chmod 640 /var/www/html/index.html
sudo chown -R root:www-data /var/www/html/

# Set secure umask for Apache
echo 'umask 027' | sudo tee -a /etc/apache2/envvars

# Start Apache service
sudo systemctl start apache2

# Enable Apache to start at boot
sudo systemctl enable apache2

# Check status to verify it's running
sudo systemctl status apache2

# Perform post-installation security audit
sudo apt install lynis
sudo lynis audit system --no-colors

On Red Hat/CentOS/Fedora Systems

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Update package lists
sudo dnf update

# Install Apache (httpd package)
sudo dnf install httpd

# Start Apache service
sudo systemctl start httpd

# Enable Apache to start at boot
sudo systemctl enable httpd

# Check status to verify it's running
sudo systemctl status httpd

On Windows

For Windows, the simplest approach is to use a package like XAMPP, WampServer, or MAMP which bundle Apache with PHP and MySQL.

Alternatively, you can download and install Apache directly from the Apache Lounge website (unofficial Windows builds): https://www.apachelounge.com/download/

Basic Configuration

Apache’s configuration files are typically found in:

  • /etc/apache2/ (Debian/Ubuntu)
  • /etc/httpd/ (Red Hat/CentOS/Fedora)
  • /usr/local/etc/httpd/ (macOS with Homebrew)

Main Configuration Files

  • apache2.conf / httpd.conf: The main configuration file
  • ports.conf: Defines which ports Apache listens on
  • sites-available/: Directory containing site configurations
  • sites-enabled/: Directory containing symbolic links to enabled sites
  • mods-available/: Directory containing available modules
  • mods-enabled/: Directory containing enabled modules

Essential Configuration Commands

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Restart Apache (Debian/Ubuntu)
sudo systemctl restart apache2

# Reload configuration without restarting (Debian/Ubuntu)
sudo systemctl reload apache2

# Test configuration for syntax errors (Debian/Ubuntu)
sudo apache2ctl configtest

# Restart Apache (Red Hat/CentOS/Fedora)
sudo systemctl restart httpd

# Reload configuration without restarting (Red Hat/CentOS/Fedora)
sudo systemctl reload httpd

# Test configuration for syntax errors (Red Hat/CentOS/Fedora)
sudo apachectl configtest

Basic apache2.conf/httpd.conf Settings

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Specify the location of content files
DocumentRoot "/var/www/html"

# Set global server options
ServerName example.com
ServerAdmin [email protected]

# Control Apache process settings
Timeout 300
KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 5

# Set default directory permissions
<Directory "/var/www/html">
    # Options for this directory
    Options Indexes FollowSymLinks
    
    # Access control configuration
    AllowOverride All
    Require all granted
</Directory>

Virtual Hosts

Virtual hosts allow you to serve multiple websites from a single Apache instance. This is one of Apache’s most powerful features.

Creating a Basic Virtual Host

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# /etc/apache2/sites-available/example.com.conf

<VirtualHost *:80>
    # The domain name this virtual host should respond to
    ServerName example.com
    ServerAlias www.example.com
    
    # Server admin email address for error messages
    ServerAdmin [email protected]
    
    # Root directory for this website's files
    DocumentRoot /var/www/example.com
    
    # Log file locations (crucial for debugging and monitoring)
    ErrorLog ${APACHE_LOG_DIR}/example.com_error.log
    CustomLog ${APACHE_LOG_DIR}/example.com_access.log combined
    
    # Directory-specific settings
    <Directory /var/www/example.com>
        Options Indexes FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>
</VirtualHost>

Enabling a Virtual Host (Debian/Ubuntu)

1
2
3
4
5
# Create symlink in sites-enabled directory
sudo a2ensite example.com.conf

# Reload Apache to apply changes
sudo systemctl reload apache2

Name-based vs. IP-based Virtual Hosting

Apache supports two types of virtual hosting:

  1. Name-based Virtual Hosting: Multiple domains share the same IP address (most common)
  2. IP-based Virtual Hosting: Each domain has its own IP address
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# Name-based virtual hosting example
<VirtualHost *:80>
    ServerName site1.example.com
    DocumentRoot /var/www/site1
</VirtualHost>

<VirtualHost *:80>
    ServerName site2.example.com
    DocumentRoot /var/www/site2
</VirtualHost>

# IP-based virtual hosting example
<VirtualHost 192.168.1.10:80>
    ServerName site1.example.com
    DocumentRoot /var/www/site1
</VirtualHost>

<VirtualHost 192.168.1.11:80>
    ServerName site2.example.com
    DocumentRoot /var/www/site2
</VirtualHost>

Security Configurations

Implementing ModSecurity (Web Application Firewall)

ModSecurity is a powerful Web Application Firewall (WAF) for Apache that provides protection against various attacks including SQL injection, cross-site scripting, and other OWASP Top 10 vulnerabilities.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# Install ModSecurity (Debian/Ubuntu)
sudo apt install libapache2-mod-security2

# Enable the module
sudo a2enmod security2

# Copy the recommended configuration
sudo cp /etc/modsecurity/modsecurity.conf-recommended /etc/modsecurity/modsecurity.conf

# Enable ModSecurity in blocking mode (not just detection)
sudo sed -i 's/SecRuleEngine DetectionOnly/SecRuleEngine On/' /etc/modsecurity/modsecurity.conf

# Install the OWASP Core Rule Set (CRS) for comprehensive protection
sudo apt install modsecurity-crs
sudo ln -s /usr/share/modsecurity-crs/rules/ /etc/modsecurity/

# Configure to use the CRS
echo 'Include /etc/modsecurity/rules/*.conf' | sudo tee -a /etc/apache2/mods-enabled/security2.conf

# Set paranoia level to 3 (high protection, low false positives)
echo 'SecRuleEngine On' | sudo tee -a /etc/modsecurity/crs-setup.conf
echo 'SecAction "id:900000,phase:1,pass,t:none,nolog,setvar:tx.paranoia_level=3"' | sudo tee -a /etc/modsecurity/crs-setup.conf

# Restart Apache
sudo systemctl restart apache2

SSL/TLS Configuration with Let’s Encrypt

Always use TLS to encrypt all web traffic. Let’s Encrypt provides free, automated certificates.

1
2
3
4
5
6
7
8
9
10
11
# Install Certbot (Debian/Ubuntu)
sudo apt install certbot python3-certbot-apache

# Obtain and install certificate with secure parameters
sudo certbot --apache -d example.com -d www.example.com --rsa-key-size 4096

# Configure auto-renewal with a post-renewal hook to reload Apache
echo "0 0,12 * * * root python3 -c 'import random; import time; time.sleep(random.random() * 3600)' && certbot renew --quiet --post-hook 'systemctl reload apache2'" | sudo tee -a /etc/crontab > /dev/null

# Test automatic renewal
sudo certbot renew --dry-run

Hardened Apache SSL Configuration Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
<VirtualHost *:443>
    ServerName example.com
    DocumentRoot /var/www/example.com
    
    # SSL Certificate Configuration
    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
    
    # Maximum security TLS settings - only TLS 1.3 and 1.2
    SSLProtocol -all +TLSv1.3 +TLSv1.2
    
    # Use secure ciphers only - Mozilla's "Modern" cipher list
    SSLCipherSuite TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305
    SSLHonorCipherOrder on
    
    # Enable OCSP Stapling (faster and more private certificate validation)
    #SSLUseStapling on
    #SSLStaplingCache "shmcb:logs/ssl_stapling(32768)"
    #SSLStaplingResponseMaxAge 86400
    
    # HSTS (HTTP Strict Transport Security)
    # Tell browsers to only connect via HTTPS for 2 years
    Header always set Strict-Transport-Security "max-age=63072000; includeSubdomains; preload"
    
    # Prevent clickjacking - only allow your site to be framed by itself
    Header always set X-Frame-Options SAMEORIGIN
    
    # Prevent MIME-type sniffing (browser guessing file types)
    Header always set X-Content-Type-Options nosniff
    
    # Enable Cross-Site Scripting filter in browsers
    Header always set X-XSS-Protection "1; mode=block"
    
    # Control information sent in referrer header
    Header always set Referrer-Policy strict-origin-when-cross-origin
    
    # Content Security Policy - restrict what resources can be loaded
    # This is a basic example - customize based on your site's requirements
    Header always set Content-Security-Policy "default-src 'self'; script-src 'self'; img-src 'self'; style-src 'self'; font-src 'self'; frame-ancestors 'self'; form-action 'self'"
    
    # Enable Feature Policy/Permissions Policy
    Header always set Permissions-Policy "geolocation=(), microphone=(), camera=(), payment=()"
    
    # Disable caching for sensitive resources
    <FilesMatch "\.(html|htm|php)$">
        Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate"
        Header set Pragma "no-cache"
        Header set Expires "0"
    </FilesMatch>
    
    # Limit SSL session cache to enhance performance while maintaining security
    SSLSessionCache shmcb:/var/lib/apache2/ssl_scache(512000)
    SSLSessionCacheTimeout 300
</VirtualHost>

Comprehensive Directory and Server Hardening

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# Global server hardening - apply these in apache2.conf
ServerTokens Prod         # Don't reveal Apache version in headers
ServerSignature Off       # Don't show Apache info in error pages
TraceEnable Off           # Disable TRACE method to prevent XST attacks
FileETag None             # Disable ETag headers (privacy concern)
Timeout 30                # Reduce timeout to prevent DoS attacks
MaxKeepAliveRequests 100  # Limit connections per client
KeepAliveTimeout 2        # Shorter keepalive timeout

# Enable only required modules
# Run this to disable unused modules:
# a2dismod autoindex status info cgi alias env userdir negotiation

# Secure directory configurations
<Directory />
    # Default deny for the entire filesystem
    Options None
    AllowOverride None
    Require all denied
</Directory>

<Directory /var/www/example.com>
    # Provide minimum required permissions
    Options -Indexes -Includes -ExecCGI -FollowSymLinks
    AllowOverride None
    Require all granted
    
    # Set secure default permissions
    <FilesMatch "^\.">
        Require all denied
    </FilesMatch>
    
    # Only allow specific file types
    <FilesMatch "(?i)\.(gif|jpe?g|png|css|js|html?|xml|txt)$">
        Require all granted
    </FilesMatch>
    
    # Block access to sensitive files
    <FilesMatch "(?i)\.(bak|config|sql|tar|zip|gz|tgz|ini|log|sh|inc|sw[op]|ya?ml)$">
        Require all denied
    </FilesMatch>
    
    # Disable execution of scripts in uploaded content
    <Directory /var/www/example.com/uploads>
        # Prohibit script execution
        Options -ExecCGI
        SetHandler none
        
        # Disable PHP entirely in this directory
        php_flag engine off
        RemoveHandler .php .phtml .php3 .php4 .php5 .php7
        RemoveType .php .phtml .php3 .php4 .php5 .php7
        
        # Treat all files as plain text
        AddType text/plain .php .phtml .php3 .php4 .php5 .php7 .html .htm
        
        # Set very restrictive permissions
        <FilesMatch ".+">
            SetHandler default-handler
        </FilesMatch>
    </Directory>
    
    # Protect configuration files
    <Files ~ "^\.ht">
        Require all denied
        # Ensure proper MIME type handling
        Header unset Content-Type
        Header always set Content-Type "text/plain"
    </Files>
    
    # Implement rate limiting for sensitive areas
    <Location "/login">
        ErrorDocument 429 "Too many requests, please try again later."
        # Limit to 15 requests per minute
        LimitRequestRate 15 
    </Location>
</Directory>

# Mitigate clickjacking with CSP frame-ancestors (stronger than X-Frame-Options)
Header always append Content-Security-Policy "frame-ancestors 'self';"

# Set appropriate file permissions on disk
# Run these commands:
# find /var/www/example.com -type d -exec chmod 750 {} \;
# find /var/www/example.com -type f -exec chmod 640 {} \;
# chown -R root:www-data /var/www/example.com

Performance Tuning

Enable and Configure Caching

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# Load caching modules
LoadModule cache_module modules/mod_cache.so
LoadModule cache_disk_module modules/mod_cache_disk.so

# Configure disk cache
<IfModule mod_cache_disk.c>
    CacheRoot /var/cache/apache2/mod_cache_disk
    CacheEnable disk /
    CacheDirLevels 2
    CacheDirLength 1
    # Cache files up to 100MB for up to 1 hour
    CacheMaxFileSize 104857600
    CacheMinFileSize 1
    CacheDefaultExpire 3600
    CacheMaxExpire 86400
    CacheQuickHandler on
</IfModule>

# Set expiration headers for static content
<IfModule mod_expires.c>
    ExpiresActive On
    ExpiresByType image/jpg "access plus 1 year"
    ExpiresByType image/jpeg "access plus 1 year"
    ExpiresByType image/gif "access plus 1 year"
    ExpiresByType image/png "access plus 1 year"
    ExpiresByType text/css "access plus 1 month"
    ExpiresByType application/javascript "access plus 1 month"
    ExpiresDefault "access plus 2 days"
</IfModule>

Configure MPM (Multi-Processing Module)

Apache can use different MPMs to handle connections. The most common are:

  • prefork: Uses multiple child processes with one thread each (legacy)
  • worker: Uses multiple child processes with multiple threads each
  • event: Improved version of worker, recommended for high-traffic sites
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Use the Event MPM (best for modern high-traffic sites)
<IfModule mpm_event_module>
    # Number of child server processes created at startup
    StartServers             3
    
    # Desired minimum number of idle child server processes
    MinSpareThreads         25
    
    # Desired maximum number of idle child server processes
    MaxSpareThreads         75
    
    # Maximum number of connections that will be processed simultaneously
    MaxRequestWorkers      400
    
    # Maximum number of requests a child process serves before terminating
    MaxConnectionsPerChild   0
</IfModule>

Optimize for High Traffic

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# Increase timeouts for busy servers
Timeout 60

# Configure keep-alive settings
KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 5

# Enable compression for text-based content
<IfModule mod_deflate.c>
    # Compress HTML, CSS, JavaScript, Text, XML and fonts
    AddOutputFilterByType DEFLATE application/javascript
    AddOutputFilterByType DEFLATE application/rss+xml
    AddOutputFilterByType DEFLATE application/vnd.ms-fontobject
    AddOutputFilterByType DEFLATE application/x-font
    AddOutputFilterByType DEFLATE application/x-font-opentype
    AddOutputFilterByType DEFLATE application/x-font-otf
    AddOutputFilterByType DEFLATE application/x-font-truetype
    AddOutputFilterByType DEFLATE application/x-font-ttf
    AddOutputFilterByType DEFLATE application/x-javascript
    AddOutputFilterByType DEFLATE application/xhtml+xml
    AddOutputFilterByType DEFLATE application/xml
    AddOutputFilterByType DEFLATE font/opentype
    AddOutputFilterByType DEFLATE font/otf
    AddOutputFilterByType DEFLATE font/ttf
    AddOutputFilterByType DEFLATE image/svg+xml
    AddOutputFilterByType DEFLATE image/x-icon
    AddOutputFilterByType DEFLATE text/css
    AddOutputFilterByType DEFLATE text/html
    AddOutputFilterByType DEFLATE text/javascript
    AddOutputFilterByType DEFLATE text/plain
    AddOutputFilterByType DEFLATE text/xml
    
    # Remove browser bugs
    BrowserMatch ^Mozilla/4 gzip-only-text/html
    BrowserMatch ^Mozilla/4\.0[678] no-gzip
    BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
</IfModule>

Complex Issues and Solutions

Problem: Handling High Traffic Spikes

Issue: Server becomes unresponsive during traffic spikes.

Solution:

  1. Implement a proper MPM configuration
  2. Use rate limiting to prevent abuse
1
2
3
4
5
6
7
8
9
10
11
# Install and enable mod_ratelimit
sudo a2enmod ratelimit

# Configure rate limiting in your virtual host
<IfModule mod_ratelimit.c>
    # Limit bandwidth to 400KB/s for specific content
    <Location /downloads>
        SetOutputFilter RATE_LIMIT
        SetEnv rate-limit 400
    </Location>
</IfModule>

Problem: Handling SSL Termination with High Traffic

Issue: SSL processing is CPU-intensive and can slow down your server.

Solution: Offload SSL processing using Apache’s mod_proxy with a reverse proxy setup.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# Enable required modules
sudo a2enmod proxy
sudo a2enmod proxy_http
sudo a2enmod proxy_balancer
sudo a2enmod lbmethod_byrequests

# Configure load balancing and proxy
<VirtualHost *:443>
    ServerName example.com
    
    # SSL Configuration
    SSLEngine On
    SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
    
    # Define proxy backend servers
    <Proxy "balancer://mycluster">
        BalancerMember "http://backend1.example.com:8080"
        BalancerMember "http://backend2.example.com:8080"
        ProxySet lbmethod=byrequests
    </Proxy>
    
    # Proxy all requests to the backend
    ProxyPreserveHost On
    ProxyPass / balancer://mycluster/
    ProxyPassReverse / balancer://mycluster/
</VirtualHost>

Problem: Handling Slow Application Responses

Issue: Long-running applications cause Apache to tie up worker processes.

Solution: Use asynchronous processing with mod_proxy and timeout controls.

1
2
3
4
5
6
7
8
9
# Set stricter timeouts for proxied connections
ProxyTimeout 60
TimeOut 60

# Configure specific timeouts for slow endpoints
<Location "/api/slow-endpoint">
    ProxyPass http://backend.example.com/api/slow-endpoint timeout=180
    ProxyPassReverse http://backend.example.com/api/slow-endpoint
</Location>

Advanced Functionality

Security-First Dynamic Content Negotiation

Content negotiation allows serving different versions of resources based on client preferences. Here’s a secure implementation:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# Enable content negotiation with security focus
<IfModule mod_negotiation.c>
    # Define languages and map to file extensions
    AddLanguage en .en
    AddLanguage fr .fr
    AddLanguage de .de
    
    # Define which quality factor to assign to each language
    LanguagePriority en fr de
    
    # SECURITY: Avoid using MultiViews in security-sensitive contexts
    # Instead use explicit type maps when possible
    # Options +MultiViews
    
    # Use explicit type maps for negotiation (more secure than MultiViews)
    AddHandler type-map .var
    
    # SECURITY: Prevent path traversal by implementing strict directory restrictions
    <DirectoryMatch ".*">
        # Disable potentially dangerous options
        Options -Indexes -Includes -FollowSymLinks
        # Only allow specific file types to be negotiated
        <FilesMatch "(?i)\.var$">
            Require all granted
        </FilesMatch>
    </DirectoryMatch>
    
    # SECURITY: Implement content-type enforcement
    # Prevent browsers from MIME-sniffing away from declared content-type
    Header always set X-Content-Type-Options "nosniff"
</IfModule>

Secure Implementation of Rewrite Rules with mod_rewrite

The mod_rewrite module is powerful for URL manipulation and redirection, but requires careful security implementation:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# Enable rewrite module
LoadModule rewrite_module modules/mod_rewrite.so

<VirtualHost *:80>
    ServerName example.com
    DocumentRoot /var/www/example.com
    
    # Enable rewrite engine for this virtual host
    RewriteEngine On
    RewriteOptions Inherit
    
    # SECURITY: Force HTTPS with proper headers - redirect all HTTP traffic to HTTPS
    # Add HSTS header in the HTTPS virtual host, not here
    RewriteCond %{HTTPS} off
    RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301,NE]
    
    # SECURITY: Block access to sensitive files and directories
    # Block access to any hidden files and directories
    RewriteRule "(^|/)\." - [F]
    # Block access to backup and source files
    RewriteRule ".(bak|config|dist|fla|inc|ini|log|orig|psd|sh|sql|swp|txt|tpl|xml|yml|md|lock|json)$" - [F,NC]
    
    # SECURITY: Prevent access to wp-config.php and other sensitive files
    RewriteRule ^wp-config.php$ - [F,L,NC]
    RewriteRule ^xmlrpc.php$ - [F,L,NC]
    
    # SECURITY: Prevent host header attacks
    # Only allow your domains to be used in Host: header
    RewriteCond %{HTTP_HOST} !^(example\.com|www\.example\.com)$ [NC]
    RewriteRule .* - [F]
    
    # SECURITY: Block bots/scanners/malicious traffic with extensive patterns
    RewriteCond %{HTTP_USER_AGENT} (360Spider|acapbot|acoonbot|ahrefs|alexibot|asterias|attackbot|baiduspider|blackwidow|bot|bots|collector|cmd|curl|c99|dts|email|extract|exploit|ezooms|fhscan|floodgate|flybots|havij|harvest|httrack|indy|infotekies|libwww|majestic|masses|morfeus|nikto|nmap|nutch|petalbot|planetwork|pocketparser|pycurl|python|scan|scraper|security|seekerspider|semalt|urllib|webalta|webbandit|webcopier|webcopy|websleuth|webleacher|winhttp|xaldon) [NC]
    RewriteRule .* - [F,L]
    
    # Create clean URLs for a blog with input validation
    # Changes /blog.php?id=123 to /blog/123
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    # SECURITY: Strictly validate input parameters to prevent injection
    RewriteRule ^blog/([0-9]+)$ /blog.php?id=$1 [L,QSA]
    
    # SECURITY: Block SQL injection attempts
    RewriteCond %{QUERY_STRING} [^a-z0-9._-]*(union|select|insert|drop|update|md5|benchmark|or|and|if)[^a-z0-9._-]* [NC]
    RewriteRule .* - [F,L]
    
    # SECURITY: Block PHP-injection attempts
    RewriteCond %{QUERY_STRING} (base64_encode|eval\() [NC,OR]
    RewriteCond %{QUERY_STRING} (\<|%3C).*script.*(\>|%3E) [NC]
    RewriteRule .* - [F,L]
    
    # SECURITY: Set X-Content-Type-Options header
    Header always set X-Content-Type-Options nosniff
    
    # Handle missing pages - redirect old site structure to new
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_URI} ^/old-section/(.*)$
    # SECURITY: Validate destination to prevent open redirect
    RewriteRule ^old-section/([a-zA-Z0-9_-]+)$ /new-section/$1 [L,R=301]
    
    # SECURITY: Implement rate limiting for important endpoints
    # This requires mod_ratelimit and mod_env
    <If "%{REQUEST_URI} =~ m#^/(login|admin|api)#">
        SetEnv rate-limit 5
    </If>
</VirtualHost>

WebSocket Proxying

WebSockets allow for real-time communication, and Apache can proxy these connections.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Enable required modules
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so

<VirtualHost *:80>
    ServerName example.com
    
    # Proxy WebSocket connections
    RewriteEngine On
    RewriteCond %{HTTP:Upgrade} =websocket [NC]
    RewriteRule /(.*)           ws://localhost:8080/$1 [P,L]
    
    # Proxy regular HTTP traffic
    ProxyPass        /socket http://localhost:8080/socket
    ProxyPassReverse /socket http://localhost:8080/socket
</VirtualHost>

Custom Logging and Analytics

Create custom log formats to capture specific information.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Define a custom log format with additional fields
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %D %{X-Forwarded-For}i" combined_with_timing

# Use the custom format in a virtual host
<VirtualHost *:80>
    ServerName example.com
    CustomLog ${APACHE_LOG_DIR}/example.com_access.log combined_with_timing
    
    # Log specific events to a separate file
    # Log all 404 errors separately
    LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\"" notfound
    CustomLog ${APACHE_LOG_DIR}/notfound.log notfound env=not_found
    
    # Set an environment variable for 404 errors
    <LocationMatch "/">
        ErrorDocument 404 /404.php
        SetEnvIf status 404 not_found=1
    </LocationMatch>
</VirtualHost>

Troubleshooting and Security Auditing

Common Issues and Security Solutions

1. Apache Won’t Start After Security Configurations

Symptoms: Service fails to start after implementing security changes.

Secure Debugging Steps:

1
2
3
4
5
6
7
8
9
10
11
# Check for syntax errors in configuration (without revealing full paths in logs)
sudo apache2ctl configtest

# Look at Apache error logs in a secure manner
sudo grep -v "password\|key\|secret\|token" /var/log/apache2/error.log | tail -100

# Check for port conflicts securely
sudo ss -tulwn | grep -E ':80|:443'

# Check process status without exposing command line arguments
sudo systemctl status apache2 --no-pager

Security-Focused Solutions:

  • Fix syntax errors while maintaining strict security configurations
  • Resolve port conflicts and validate listening only on required interfaces
  • Verify file permissions (SSL certificates should be 600, config files 640)
  • Validate all custom security rules before deploying to production

2. 403 Forbidden Errors After Hardening

Symptoms: Browser shows “403 Forbidden” after implementing security measures.

Secure Debugging Steps:

1
2
3
4
5
6
7
8
9
# Check directory permissions (minimally required)
ls -la /var/www/html/ | grep -v "config\|password\|key"

# Check Apache configuration for the directory without exposing sensitive paths
grep -r --include="*.conf" "/var/www/html" /etc/apache2/ | grep -v "password\|key\|secret"

# Verify SELinux/AppArmor contexts if applicable
sudo sestatus
sudo aa-status

Security-Focused Solutions:

1
2
3
4
5
6
7
8
9
10
11
12
13
# Allow access to the directory with minimal permissions
<Directory /var/www/html/restricted>
    # Disable all dangerous options
    Options None
    # Only allow specific overrides if needed
    AllowOverride None
    # Grant access with minimal exposure
    Require all granted
    # Enable logging of all access
    LogLevel info
    # Implement content security policy
    Header always set Content-Security-Policy "default-src 'self';"
</Directory>

3. Security Scanning and Hardening Validation

Symptoms: Need to verify your security configuration is effective.

Secure Testing Steps:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Install security scanning tools
sudo apt install nikto lynis

# Scan your own server (only in testing/staging environments)
nikto -h localhost

# Perform system security audit
sudo lynis audit system

# Check for vulnerable Apache modules and configurations
sudo apt install wapiti
wapiti -u http://localhost/ -v 2

# Test SSL/TLS security configuration
sudo apt install sslscan
sslscan --no-failed example.com:443

# Verify HTTP security headers
curl -I https://example.com/ | grep -E 'Strict-Transport-Security|Content-Security-Policy|X-Frame-Options'

Security Improvement Solutions:

  • Document all findings and remediate vulnerabilities
  • Implement regular security scanning in your maintenance routine
  • Create a security incident response plan
  • Implement file integrity monitoring ```bash

    Install AIDE (Advanced Intrusion Detection Environment)

    sudo apt install aide

Configure AIDE to monitor Apache configuration files

echo “/etc/apache2/ Rule=VarFile” | sudo tee -a /etc/aide/aide.conf

Initialize the AIDE database

sudo aideinit

Run regular checks

sudo aide –check

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#### 4. SSL/TLS Security Issues

**Symptoms**: Low scores on SSL/TLS testing sites or security warnings.

**Security Validation Steps**:
```bash
# Test SSL configuration thoroughly
sudo openssl s_client -connect example.com:443 -servername example.com -tls1_3

# Check for weak ciphers (none should be allowed)
sudo openssl ciphers -v 'LOW:EXP:!DH:!ADH:!kDH' | wc -l

# Validate certificate security
sudo openssl x509 -in /etc/letsencrypt/live/example.com/cert.pem -noout -text | grep "Signature Algorithm\|Public Key"

# Check certificate permissions (should be restricted)
sudo find /etc/letsencrypt/live -type f -name "*.pem" -exec ls -la {} \;

Advanced Security Solutions:

  • Implement certificate transparency monitoring
  • Configure OCSP Must-Staple for enhanced revocation checking
  • Use DNS CAA records to restrict which CAs can issue certificates
  • Implement encrypted SNI if your infrastructure supports it
  • Set up automated security header testing with Mozilla Observatory CLI
1
2
# Fix permissions if certificates are overly accessible
sudo find /etc/letsencrypt/live -type f -name "*.pem" -exec chmod 600 {} \;

5. Security Incident Response

Symptoms: Unexpected behavior, unusual log entries, or compromise indicators.

Secure Incident Response Steps: ```bash

Check for unauthorized processes

sudo ps aux | grep -v whoami | grep apache2

Look for unusual network connections

sudo netstat -tunap | grep httpd

Search for recently modified files

sudo find /var/www -type f -mtime -1 -ls

Check for unauthorized users/groups

sudo grep apache /etc/passwd /etc/group

Examine Apache access logs

References

This post is licensed under CC BY 4.0 by the author.