CORS on Apache

⚠️ Security Warning: Using Access-Control-Allow-Origin: * allows any website to access your resources. Always specify exact origins in production.

Method 1: Simple Configuration (Least Secure)

To add CORS authorization to all responses, add the following inside either the <Directory>, <Location>, <Files> or <VirtualHost> sections of your server config (usually located in a *.conf file, such as httpd.conf or apache.conf), or within a .htaccess file:

<IfModule mod_headers.c>
  Header set Access-Control-Allow-Origin "*"
</IfModule>
    

Method 2: Single Origin (Recommended)

For production environments, always specify exact allowed origins and include the Vary: Origin header for proper caching:

<IfModule mod_headers.c>
  Header set Access-Control-Allow-Origin "https://example.com"
  Header set Vary "Origin"
</IfModule>
    

Method 3: Multiple Origins with Validation

To allow multiple specific origins, use SetEnvIf to validate the origin (issue #146):

<IfModule mod_headers.c>
  # Allow from multiple specific origins
  SetEnvIf Origin "^https?://(www\.example\.com|app\.example\.com|staging\.example\.com)$" ORIGIN_MATCH=$0

  Header set Access-Control-Allow-Origin "%{ORIGIN_MATCH}e" env=ORIGIN_MATCH
  Header set Vary "Origin" env=ORIGIN_MATCH
</IfModule>
    

Method 4: With Credentials (Cookies/Auth)

When using credentials, you must specify exact origins (wildcards are not allowed):

<IfModule mod_headers.c>
  SetEnvIf Origin "^https?://(www\.example\.com|app\.example\.com)$" ORIGIN_MATCH=$0

  Header set Access-Control-Allow-Origin "%{ORIGIN_MATCH}e" env=ORIGIN_MATCH
  Header set Access-Control-Allow-Credentials "true" env=ORIGIN_MATCH
  Header set Vary "Origin" env=ORIGIN_MATCH
</IfModule>
    

Method 5: With Preflight Support

For APIs that use custom headers or methods like PUT/DELETE, handle preflight OPTIONS requests:

<IfModule mod_headers.c>
  # Validate origin
  SetEnvIf Origin "^https?://(www\.example\.com|app\.example\.com)$" ORIGIN_MATCH=$0

  # CORS headers for all requests
  Header set Access-Control-Allow-Origin "%{ORIGIN_MATCH}e" env=ORIGIN_MATCH
  Header set Vary "Origin" env=ORIGIN_MATCH

  # Preflight OPTIONS request handling
  <If "%{REQUEST_METHOD} == 'OPTIONS'">
    Header set Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
    Header set Access-Control-Allow-Headers "Content-Type, Authorization, X-Requested-With"
    Header set Access-Control-Max-Age "86400"

    # Return 204 No Content for preflight
    RewriteEngine On
    RewriteCond %{REQUEST_METHOD} OPTIONS
    RewriteRule ^(.*)$ $1 [R=204,L]
  </If>
</IfModule>
    

Configuration and Testing

To ensure that your changes are correct, it is strongly recommended that you use apachectl -t to check your configuration changes for errors. After this passes, reload Apache to apply your changes:

# Test configuration
apachectl -t

# Reload Apache
sudo service apache2 reload
# or
apachectl -k graceful
    

Altering headers requires the use of mod_headers. Mod_headers is enabled by default in Apache, however, you may want to ensure it's enabled:

a2enmod headers
    

Note: You can also use add rather than set, but be aware that add can add the header multiple times, so it's safer to use set. Also, for Apache 2.4+, always can be used (e.g., Header always set) to ensure headers are set even for error responses.

Using .htaccess Files

If you're using .htaccess files to configure CORS headers, you must ensure that AllowOverride is enabled in your Apache server configuration. Without this, your .htaccess file will be ignored.

Add the following to your server configuration file (usually httpd.conf, apache.conf, or a VirtualHost configuration):

<Directory "/path/to/your/webroot">
  AllowOverride All
</Directory>
		

Note: For security reasons, you may want to use AllowOverride FileInfo instead of AllowOverride All to only allow header modifications. After making changes to server configuration files, remember to test with apachectl -t and reload Apache.

Testing Your CORS Configuration

For comprehensive testing instructions including curl commands, browser DevTools usage, and troubleshooting common CORS errors, see the CORS Testing Guide.

Who’s behind this

Monsur Hossain and Michael Hausenblas

Contribute

The content on this site stays fresh thanks to help from users like you! If you have suggestions or would like to contribute, fork us on GitHub.

Buy the book

Save 39% on CORS in Action with promotional code hossainco at manning.com/hossain