Apache .htaccess CORS Configuration
Set up CORS headers in Apache using mod_headers and .htaccess. Covers single origin, dynamic origin with SetEnvIf, and handling preflight requests.
Detailed Explanation
Apache CORS with mod_headers
Apache's mod_headers module provides the Header directive for adding response headers. Combined with SetEnvIf, you can implement dynamic origin validation similar to Nginx's map block.
Prerequisites
Ensure mod_headers is enabled:
a2enmod headers
systemctl reload apache2
Simple .htaccess — Single Origin
<IfModule mod_headers.c>
Header always set Access-Control-Allow-Origin "https://app.example.com"
Header always set Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
Header always set Access-Control-Allow-Headers "Content-Type, Authorization"
Header always set Access-Control-Max-Age "3600"
Header always set Access-Control-Allow-Credentials "true"
Header always set Vary "Origin"
</IfModule>
# Handle preflight
RewriteEngine On
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule ^(.*)$ $1 [R=204,L]
Dynamic Origin with SetEnvIf
<IfModule mod_headers.c>
SetEnvIf Origin "^https://(app|admin)\.example\.com$" CORS_ORIGIN=$0
Header always set Access-Control-Allow-Origin "%{CORS_ORIGIN}e" env=CORS_ORIGIN
Header always set Access-Control-Allow-Credentials "true" env=CORS_ORIGIN
Header always set Vary "Origin" env=CORS_ORIGIN
Header always set Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" env=CORS_ORIGIN
Header always set Access-Control-Allow-Headers "Content-Type, Authorization" env=CORS_ORIGIN
Header always set Access-Control-Max-Age "3600" env=CORS_ORIGIN
</IfModule>
How SetEnvIf Works
SetEnvIf Origin "regex" CORS_ORIGIN=$0 captures the entire matched Origin header value into an environment variable. The env=CORS_ORIGIN condition on each Header directive means headers are only set when the variable exists — i.e., when the origin matched the regex.
Key Differences from Nginx
- Apache evaluates
.htaccessper-request, which is slower than Nginx's compiled config but more flexible for shared hosting. - The
alwayskeyword in Apache'sHeaderdirective works similarly to Nginx — it adds headers even on error responses. - Apache's
RewriteRulehandles the OPTIONS response, whereas Nginx usesreturn 204.
Use Case
A developer hosting a PHP API on shared hosting (cPanel, Plesk) where they only have access to .htaccess files, not the main Apache config. They need CORS headers for their JavaScript frontend hosted on a different domain.