Apache Configuration Deep Dive — Modules, RewriteMap, Custom Logs, Security, and Performance
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 apache2Module 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.mapCustom 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 extendedConditional 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" combinedModSecurity 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] receivedCommon 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
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