Last updated: March 22, 2026

Apache httpd configuration is notoriously verbose and error-prone. Getting VirtualHost configs, mod_rewrite rules, SSL settings, and security headers right requires memorizing obscure directives. AI tools dramatically reduce the lookup time. but accuracy varies. This guide tests Claude, GPT-4, and Copilot on real Apache configuration tasks.

Task 1 - HTTPS VirtualHost with HTTP Redirect

Prompt - “Write an Apache httpd config for example.com that redirects HTTP to HTTPS, serves from /var/www/example.com, enables PHP-FPM via proxy, and sets modern TLS settings.”

Claude’s output:

/etc/apache2/sites-available/example.com.conf

HTTP → HTTPS redirect
<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com

    # Redirect all HTTP traffic to HTTPS
    RewriteEngine On
    RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
</VirtualHost>

HTTPS VirtualHost
<VirtualHost *:443>
    ServerName example.com
    ServerAlias www.example.com
    DocumentRoot /var/www/example.com/public

    # SSL Configuration
    SSLEngine On
    SSLCertificateFile      /etc/letsencrypt/live/example.com/fullchain.pem
    SSLCertificateKeyFile   /etc/letsencrypt/live/example.com/privkey.pem

    # Modern TLS. TLS 1.2+ only, strong ciphers
    SSLProtocol             -all +TLSv1.2 +TLSv1.3
    SSLCipherSuite          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:\
                            DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
    SSLHonorCipherOrder     Off
    SSLSessionTickets       Off

    # PHP-FPM via Unix socket proxy
    <FilesMatch \.php$>
        SetHandler "proxy:unix:/run/php/php8.2-fpm.sock|fcgi://localhost"
    </FilesMatch>

    # Security headers
    Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
    Header always set X-Content-Type-Options "nosniff"
    Header always set X-Frame-Options "DENY"
    Header always set Referrer-Policy "strict-origin-when-cross-origin"
    Header always set Permissions-Policy "geolocation=(), microphone=(), camera=()"

    # Directory configuration
    <Directory /var/www/example.com/public>
        Options -Indexes +FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>

    # Deny access to hidden files
    <FilesMatch "^\.">
        Require all denied
    </FilesMatch>

    ErrorLog  ${APACHE_LOG_DIR}/example.com-error.log
    CustomLog ${APACHE_LOG_DIR}/example.com-access.log combined
</VirtualHost>

Claude includes PHP-FPM via Unix socket (faster than TCP), correct HSTS with preload, disables directory listing, and uses the SSLHonorCipherOrder Off setting required for TLS 1.3 forward secrecy. GPT-4 produces similar output but sometimes uses ProxyPassMatch instead of the SetHandler approach, which is less efficient.

Task 2 - mod_rewrite for SPA Routing

Single-page applications need all routes to serve index.html:

Prompt - “Write Apache mod_rewrite rules for a React SPA at /var/www/app. Serve index.html for all routes except actual files and API calls under /api/.”

Claude’s .htaccess:

/var/www/app/public/.htaccess
Options -MultiViews
RewriteEngine On
RewriteBase /

Don't rewrite actual files or directories
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]

Don't rewrite API calls
RewriteCond %{REQUEST_URI} ^/api/ [NC]
RewriteRule ^ - [L]

Serve index.html for everything else (SPA routing)
RewriteRule ^ index.html [L]

GPT-4’s version often includes RewriteRule ^ /index.html [L] with the leading slash, which causes an infinite redirect loop in some Apache configurations. Claude correctly omits the leading slash in the target.

Task 3 - Reverse Proxy with Load Balancing

Prompt - “Configure Apache as a reverse proxy load balancer for 3 Node.js backend servers (ports 3001, 3002, 3003). Use leastconn balancing, health checks, and sticky sessions.”

Claude:

/etc/apache2/sites-available/loadbalancer.conf

Load balancing modules required:
a2enmod proxy proxy_http proxy_balancer lbmethod_byleastconn headers

<VirtualHost *:443>
    ServerName api.example.com

    SSLEngine On
    SSLCertificateFile    /etc/letsencrypt/live/api.example.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/api.example.com/privkey.pem

    # Define the load balancer cluster
    <Proxy "balancer://nodejs_cluster">
        BalancerMember http://127.0.0.1:3001 route=node1
        BalancerMember http://127.0.0.1:3002 route=node2
        BalancerMember http://127.0.0.1:3003 route=node3

        # Least connections balancing
        ProxySet lbmethod=byleastconn

        # Health check: probe every 5s, mark down after 2 failures
        ProxySet nofailover=Off
        BalancerMember http://127.0.0.1:3001 status=+H ping=5
        BalancerMember http://127.0.0.1:3002 status=+H ping=5
        BalancerMember http://127.0.0.1:3003 status=+H ping=5
    </Proxy>

    # Sticky sessions via cookie
    Header add Set-Cookie "ROUTEID=.%{BALANCER_WORKER_ROUTE}e; path=/" env=BALANCER_ROUTE_CHANGED

    ProxyPass        / balancer://nodejs_cluster/ stickysession=ROUTEID|.routeid nofailover=Off
    ProxyPassReverse / balancer://nodejs_cluster/

    # Pass real client IP
    ProxyPreserveHost On
    RequestHeader set X-Forwarded-Proto "https"
    RequestHeader set X-Real-IP "%{REMOTE_ADDR}s"

    ErrorLog  ${APACHE_LOG_DIR}/lb-error.log
    CustomLog ${APACHE_LOG_DIR}/lb-access.log combined
</VirtualHost>

Task 4 - Security Headers and CSP

Prompt - “Generate Apache security headers for a banking application. Include strict CSP, HSTS, and disable all unsafe methods.”

Claude:

Security headers module. requires: a2enmod headers

<IfModule mod_headers.c>
    # Strict Transport Security (2 years + preload)
    Header always set Strict-Transport-Security \
        "max-age=63072000; includeSubDomains; preload"

    # Content Security Policy. strict mode for financial app
    Header always set Content-Security-Policy \
        "default-src 'none'; \
         script-src 'self' 'nonce-{NONCE}'; \
         style-src 'self' 'nonce-{NONCE}'; \
         img-src 'self' data: https:; \
         font-src 'self'; \
         connect-src 'self' https://api.example.com; \
         frame-ancestors 'none'; \
         form-action 'self'; \
         base-uri 'self'; \
         upgrade-insecure-requests"

    Header always set X-Content-Type-Options "nosniff"
    Header always set X-Frame-Options "DENY"
    Header always set Referrer-Policy "no-referrer"
    Header always set Cross-Origin-Opener-Policy "same-origin"
    Header always set Cross-Origin-Embedder-Policy "require-corp"
    Header always set Cross-Origin-Resource-Policy "same-origin"

    # Remove server information headers
    Header always unset X-Powered-By
    Header always unset Server
    ServerTokens Prod
    ServerSignature Off
</IfModule>

Disable unsafe HTTP methods
<LimitExcept GET POST PUT PATCH DELETE OPTIONS HEAD>
    Require all denied
</LimitExcept>

Claude notes that the CSP nonce requires server-side generation and suggests a PHP snippet or Apache module for dynamic nonce injection.

Task 5 - Rate Limiting and IP-Based Access Control

A common need for APIs and admin panels: rate limiting by IP using mod_ratelimit and mod_evasive, plus granular IP-based access control.

Prompt - “Configure Apache to rate limit the /api/ endpoint to 100 req/s per IP, block known bad IPs, and allow the /admin/ path only from a specific subnet.”

Claude:

Rate limiting. requires - a2enmod ratelimit

<Location /api/>
    # Limit response rate to 100KB/s per connection (mod_ratelimit)
    SetOutputFilter RATE_LIMIT
    SetEnv rate-limit 100

    # mod_evasive settings (if installed)
    DOSHashTableSize    3097
    DOSPageCount        10
    DOSSiteCount        100
    DOSPageInterval     1
    DOSSiteInterval     1
    DOSBlockingPeriod   60
</Location>

IP allowlist for admin panel. only internal subnet + VPN
<Location /admin/>
    Require ip 10.0.0.0/8
    Require ip 192.168.1.0/24
    Require ip 203.0.113.42    # ops workstation static IP
</Location>

Blocklist specific IPs (load from file for large lists)
<RequireAll>
    Require all granted
    Require not ip 198.51.100.1
    Require not ip 198.51.100.2
</RequireAll>

For large blocklists (thousands of IPs), Claude recommends using mod_authz_host with an external file or switching to fail2ban integration rather than inline Apache config, which would become unmanageable.

GPT-4 produces similar rate limiting config but sometimes uses the deprecated mod_bandwidth or forgets to mention the a2enmod commands needed to activate modules.

Task 6 - .htaccess for WordPress Multisite

WordPress Multisite has specific rewrite requirements that differ from single-site WordPress. This is a common source of AI config errors.

Prompt - “Write .htaccess rules for WordPress Multisite in subdirectory mode.”

Claude’s output:

WordPress Multisite. subdirectory mode
/var/www/wordpress/.htaccess

Protect wp-config.php
<Files wp-config.php>
    Require all denied
</Files>

Protect .htaccess itself
<Files .htaccess>
    Require all denied
</Files>

Options -Indexes

BEGIN WordPress Multisite
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]

Uploaded files. must come before the main WP rules
RewriteRule ^([_0-9a-zA-Z-]+/)?files/(.+) wp-includes/ms-files.php?file=$2 [L]

Add trailing slash to /wp-admin
RewriteRule ^([_0-9a-zA-Z-]+/)?wp-admin$ $1wp-admin/ [R=301,L]

Don't rewrite real files or directories
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]

Rewrite network subsites
RewriteRule ^([_0-9a-zA-Z-]+/)?(wp-(content|admin|includes).*) $2 [L]
RewriteRule ^([_0-9a-zA-Z-]+/)?(.*\.php)$ $2 [L]

Route everything else through index.php
RewriteRule . index.php [L]
END WordPress Multisite

GPT-4 often generates the single-site WordPress rules and misses the ms-files.php upload handling rule, which breaks media uploads on subsites.

Tool Comparison

Task Claude GPT-4 Copilot
VirtualHost SSL config Excellent. correct TLS settings Good Weak
mod_rewrite for SPA Correct (no leading slash bug) Sometimes buggy No
Load balancer config Excellent. leastconn, health checks Good No
Security headers Excellent. COEP/COOP included Good No
Rate limiting config Strong. recommends fail2ban for scale Good No
WordPress Multisite Includes ms-files.php rule Misses multisite rules No
.htaccess password protection Strong Strong Moderate
mod_wsgi for Python Strong Strong No

Module Activation Cheat Sheet

One consistently useful pattern - Claude always includes the a2enmod commands needed to activate referenced modules. Both GPT-4 and Copilot sometimes skip this, leaving you with configs that silently do nothing because the module isn’t loaded.

Enable all modules referenced in this guide
sudo a2enmod rewrite ssl headers proxy proxy_http proxy_balancer \
             lbmethod_byleastconn ratelimit

Verify modules are loaded
apache2ctl -M | sort

Test config before reloading
apache2ctl configtest

Reload without dropping connections
sudo systemctl reload apache2

Related Reading


Built by theluckystrike. More at zovo.one