Skip to content
Apache Configuration Deep Dive — Modules, RewriteMap, Custom Logs, Security, and Performance

Apache Configuration Deep Dive — Modules, RewriteMap, Custom Logs, Security, and Performance

DodaTech Updated Jun 20, 2026 8 min read

Apache HTTP Server powers millions of websites with its modular architecture. This deep-dive covers advanced module management, RewriteMap for dynamic rewrites, custom logging, mod_security integration, GZip compression tuning, IP-based access control, and performance optimization beyond the basics.

What You’ll Learn

You’ll master Apache module management (enabling, disabling, writing custom modules), use RewriteMap for database-driven URL rewrites, build custom log formats with conditional logging, integrate ModSecurity for WAF protection, tune GZip compression and caching, implement IP-based access control with Allow/Deny and mod_authz, and profile Apache performance. DodaZIP distribution servers use these advanced Apache features for access control and request routing.

Apache Advanced Configuration

    flowchart LR
  A[Apache Basics] --> B[Module Management]
  B --> C[RewriteMap & Advanced Rewrite]
  C --> D[Custom Logging]
  D --> E[ModSecurity & Security]
  E --> F[Performance Tuning]
  F --> G[Advanced Apache<br/>You are here]
  style G fill:#f90,color:#fff
  

Module Management

Enable and Disable Modules

# List all available and enabled modules
sudo a2enmod --list

# Common modules for production
sudo a2enmod rewrite
sudo a2enmod ssl
sudo a2enmod headers
sudo a2enmod expires
sudo a2enmod proxy proxy_http
sudo a2enmod deflate      # compression
sudo a2enmod remoteip     # trusted proxy IPs
sudo a2enmod http2        # HTTP/2 support
sudo a2enmod security2    # ModSecurity

# Disable unused modules to reduce attack surface
sudo a2dismod autoindex   # directory listings
sudo a2dismod status      # if not monitoring externally
sudo a2dismod info        # server info disclosure

systemctl reload apache2

Module Configuration Files

# /etc/apache2/mods-available/remoteip.conf
<IfModule remoteip_module>
    RemoteIPHeader X-Forwarded-For
    RemoteIPTrustedProxy 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16
    RemoteIPInternalProxy 10.0.0.0/8
</IfModule>

RewriteMap — Dynamic Rewrite Rules

RewriteMap allows rewrites from external sources — a file, database query, or script:

# /etc/apache2/apache2.conf
RewriteEngine On

# Map from a plain text file
RewriteMap redirects txt:/etc/apache2/maps/redirects.txt

# Map from a database (via script)
RewriteMap userlinks prg:/usr/local/bin/userlink-map.pl

# Map from a hash file (fast lookups)
RewriteMap domains dbm:/etc/apache2/maps/domains.map

# Usage in RewriteRule
RewriteCond ${redirects:$1|NOT_FOUND} !NOT_FOUND
RewriteRule ^/(.+)$ ${redirects:$1} [R=301,L]

The redirects file format:

# /etc/apache2/maps/redirects.txt
old-page   /new-page/
about-us   /about/
products   /shop/
contact    /contact-us/

For DBM maps:

# Generate the DBM map from a text file
sudo httxt2dbm -i domains.txt -o domains.map

Custom Log Formats

# /etc/apache2/apache2.conf
# LogFormat: "%h %l %u %t \"%r\" %>s %b"

# Detailed JSON format for analytics
LogFormat "{ \
    \"time\":\"%{%Y-%m-%dT%H:%M:%S}t\", \
    \"client\":\"%a\", \
    \"host\":\"%{Host}i\", \
    \"method\":\"%m\", \
    \"path\":\"%U%q\", \
    \"protocol\":\"%H\", \
    \"status\":\"%>s\", \
    \"size\":%B, \
    \"referer\":\"%{Referer}i\", \
    \"ua\":\"%{User-agent}i\", \
    \"duration_usec\":%D \
}" json

# Combined with response time
LogFormat "%h %l %u %t \"%r\" %>s %b %Dus \"%{Referer}i\" \"%{User-agent}i\"" extended

# Apply to a virtual host
CustomLog ${APACHE_LOG_DIR}/api.example.com-access.log extended

Conditional Logging

# Skip logging for static assets
SetEnvIf Request_URI "\.(css|js|png|jpg|gif|ico|svg)$" static_request

# Skip health check endpoints
SetEnvIf Request_URI "^/health$" health_check

# CustomLog with env filter
CustomLog ${APACHE_LOG_DIR}/access.log combined env=!static_request

# Separate log for errors only
CustomLog ${APACHE_LOG_DIR}/errors-only.log extended env=!static_request

# Log to syslog
CustomLog "|/usr/bin/logger -t apache -p local6.info" combined

ModSecurity WAF

sudo apt install libapache2-mod-security2 -y
sudo mv /etc/modsecurity/modsecurity.conf-recommended \
       /etc/modsecurity/modsecurity.conf
# /etc/modsecurity/modsecurity.conf
SecRuleEngine On

# Request body limits
SecRequestBodyLimit 13107200
SecRequestBodyInMemoryLimit 13107200

# OWASP Core Rule Set
IncludeOptional /usr/share/modsecurity-crs/rules/*.conf

# Custom rule: block SQL injection patterns
SecRule ARGS "@rx (select|union|insert|drop|delete).*from" \
    "id:1000,phase:2,deny,status:403,log,\
     msg:'SQL Injection blocked'"

# Custom rule: block common exploit scanners
SecRule REQUEST_URI "@rx /wp-admin|/admin|/phpmyadmin|\.env$" \
    "id:1001,phase:1,deny,status:403,log,\
     msg:'Admin path access blocked'"

# Rate limit: max 100 requests in 60 seconds per IP
SecRule IP:REQUEST_RATE "@gt 100" \
    "id:1002,phase:5,deny,status:429,log,\
     msg:'Rate limit exceeded'"

SecAction \
    "id:1003,phase:5,pass,\
     setvar:IP.REQUEST_RATE=+1,\
     expirevar:IP.REQUEST_RATE=60"

GZip Compression

# /etc/apache2/mods-available/deflate.conf
<IfModule mod_deflate.c>
    # Compress HTML, CSS, JavaScript, Text, XML, fonts
    AddOutputFilterByType DEFLATE text/html text/plain
    AddOutputFilterByType DEFLATE text/xml application/xml
    AddOutputFilterByType DEFLATE text/css text/javascript
    AddOutputFilterByType DEFLATE application/javascript
    AddOutputFilterByType DEFLATE application/json
    AddOutputFilterByType DEFLATE image/svg+xml
    AddOutputFilterByType DEFLATE application/x-font-ttf
    AddOutputFilterByType DEFLATE application/x-font-woff

    # Exclude already compressed content
    SetEnvIfNoCase Request_URI \
        \.(?:gif|jpe?g|png|zip|gz|mp4|webm)$ no-gzip

    # Browser workarounds
    BrowserMatch ^Mozilla/4 gzip-only-text/html
    BrowserMatch ^Mozilla/4\.0[678] no-gzip
    BrowserMatch \bMSIE !no-gzip !gzip-only-text/html

    # Log compression ratio
    DeflateFilterNote Input instream
    DeflateFilterNote Output outstream
    DeflateFilterNote Ratio ratio
    LogFormat '"%r" %{outstream}n/%{instream}n (%{ratio}n%%)' deflate
    CustomLog ${APACHE_LOG_DIR}/deflate.log deflate
</IfModule>

IP-Based Access Control

# Modern syntax (Apache 2.4+)
<Location /admin>
    Require ip 10.0.0.0/8
    Require ip 192.168.0.0/16
    Require ip 203.0.113.0/24
    Require all denied
</Location>

# Allow specific countries using GeoIP
<IfModule mod_maxminddb.c>
    MaxMindDBEnable On
    MaxMindDBFile DB /etc/maxmind/GeoLite2-Country.mmdb
    MaxMindDBEnv MM_COUNTRY_CODE DB/country/iso_code

    <Location /api/>
        Require env MM_COUNTRY_CODE US CA GB
        Require all denied
    </Location>
</IfModule>

# Block known bad IPs from a file
<IfModule mod_remoteip.c>
    Include /etc/apache2/blocked-ips.conf
</IfModule>

Performance Profiling

# Apache Bench (ab) — basic load test
ab -n 10000 -c 100 http://localhost/

# With KeepAlive
ab -n 10000 -c 100 -k http://localhost/

# Test over HTTPS
ab -n 1000 -c 10 https://example.com/

# Test a specific endpoint
ab -n 5000 -c 50 \
   -H "Accept-Encoding: gzip" \
   http://localhost/api/health

# Output includes:
# Requests per second, Time per request,
# Transfer rate, Connection times (connect/processing/waiting)

Interpreting Results

Server Software:        Apache/2.4.62
Server Hostname:        localhost
Server Port:            80

Document Path:          /
Document Length:        11321 bytes
Concurrency Level:      100
Time taken for tests:   3.452 seconds
Complete requests:      10000
Failed requests:        0
Requests per second:    2896.54 [#/sec] (mean)
Time per request:       34.524 [ms] (mean)
Transfer rate:          31927.41 [Kbytes/sec] received

Common Errors

1. RewriteMap Not Working

Check the map file exists, is readable by the Apache user, and the format is correct. Syntax: ${mapname:key|default}. If the key isn’t found and no default is specified, the URL remains unchanged.

2. ModSecurity Blocks Legitimate Traffic

Set SecRuleEngine DetectionOnly initially. Monitor the audit log at /var/log/modsec_audit.log. Add exclusions SecRuleRemoveById for false positive rules.

3. CustomLog Permission Denied

The Apache user must have write permission on the log directory. Use sudo chown www-data:www-data /var/log/apache2 and ensure rotatelogs pipe works: CustomLog "|/usr/sbin/rotatelogs /var/log/apache2/access.%Y-%m-%d.log 86400" combined.

4. GZip Compression Not Applied

Verify the deflate module is enabled. Check the response headers: curl -I -H "Accept-Encoding: gzip" http://localhost/. Look for Content-Encoding: gzip in the response.

5. AllowOverride All Not Working in .htaccess

The virtual host’s <Directory> block must have AllowOverride All. This must be in the server config (not .htaccess itself) because .htaccess is the override mechanism.

6. mod_remoteip Not Forwarding Correct IPs

The RemoteIPTrustedProxy directive must list all proxy/load balancer IPs. Without this, the client IP is always the proxy IP. Place this in the global config or the virtual host.

7. HTTP/2 Not Working

Requires mod_http2 and the Protocols h2 http/1.1 directive in the virtual host. Ensure SSL is configured (HTTP/2 requires TLS in practice). Check with curl -I --http2 https://example.com/.

Practice Questions

1. What is RewriteMap used for? RewriteMap provides dynamic URL rewriting from external sources (text files, databases, scripts) rather than static RewriteRule patterns. It’s used for large redirect lists, user-based rewrites, and A/B testing.

2. How do you exclude static files from Apache access logs? Use SetEnvIf Request_URI "\.(css|js|png)$" static_request then CustomLog access.log combined env=!static_request to exclude matching requests.

3. What is the difference between mod_security DetectionOnly and On modes? DetectionOnly logs violations without blocking. On actively blocks matching requests. Use DetectionOnly during initial deployment to tune rules before enforcing.

4. How do you configure Apache’s event MPM for high concurrency? Set StartServers=3, MinSpareThreads=25, MaxSpareThreads=75, ThreadLimit=64, ThreadsPerChild=25, MaxRequestWorkers=400, MaxConnectionsPerChild=10000. The event MPM handles keep-alive connections better than prefork.

5. Challenge: Set up a maintenance mode page that returns HTTP 503 with a Retry-After header, only for non-local IPs, using Apache config (not .htaccess). Answer: Use RewriteCond %{REMOTE_ADDR} !^127\.|!^10\.|!^192\.168\. then RewriteRule .* /maintenance.html [R=503,L] and add Header always set Retry-After "3600".

Mini Project: Secure API Proxy Stack

# /etc/apache2/sites-available/api-proxy.conf
<VirtualHost *:443>
    ServerName api.dodatech.com

    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/api.dodatech.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/api.dodatech.com/privkey.pem

    Protocols h2 http/1.1

    # Security headers
    Header always set X-Content-Type-Options "nosniff"
    Header always set X-Frame-Options "DENY"
    Header always set X-XSS-Protection "1; mode=block"
    Header always set Referrer-Policy "strict-origin-when-cross-origin"

    # Forward real IPs from load balancer
    RemoteIPHeader X-Forwarded-For
    RemoteIPTrustedProxy 10.0.0.0/8

    # Proxy to backend
    ProxyPreserveHost On
    ProxyPass / http://127.0.0.1:8080/ timeout=60
    ProxyPassReverse / http://127.0.0.1:8080/

    # Compression
    AddOutputFilterByType DEFLATE application/json text/plain

    # Rate limiting via ModSecurity
    SecRule IP:API_RATE "@gt 200" \
        "id:2000,phase:5,deny,status:429,log,msg:'API rate limit'"
    SecAction "id:2001,phase:5,pass,\
        setvar:IP.API_RATE=+1,expirevar:IP.API_RATE=60"

    # Access logs in JSON
    CustomLog ${APACHE_LOG_DIR}/api-dodatech-access.log json
</VirtualHost>

FAQ

How do I migrate from Apache 2.2 to 2.4?
The biggest change is access control: Order Allow,Deny becomes Require all granted. Use apachectl configtest and check the migration guide. Enable mod_access_compat for backward compatibility if needed.
What is the best MPM for PHP applications?
Prefork is required for mod_php (not thread-safe). For PHP-FPM, use event or worker MPM with ProxyPassMatch to forward PHP requests to the FPM socket.
How do I debug slow Apache requests?
Enable mod_log_forensic with ForensicLog to log request timing. Or add %D (microseconds) to your LogFormat to see response times per request.
Can Apache serve WebSocket connections?
Yes — use mod_proxy_wstunnel. Add ProxyPass /ws/ ws://backend:8080/ws/ in the virtual host for WebSocket upgrade support.
How do I rotate Apache logs?
Use rotatelogs (built-in): CustomLog "|/usr/sbin/rotatelogs /var/log/apache2/access.%Y-%m-%d.log 86400" combined. Or use logrotate with the default config in /etc/logrotate.d/apache2.
What is the maximum file size Apache can serve?
Limited by available memory and disk. For uploads, set LimitRequestBody (default unlimited). For downloads, Apache streams files efficiently up to several GB.

What’s Next

Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro. Updated 2026-06-20.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro