Search code examples
apachecentoshttp-headersamazon-cloudfront

How to can I use custom headers from CloudFront in Apache virtualhost


I have been given a task that I am not really sure how to handle. What I am requested to do is add a custom header to CloudFront and make Apache use this custom header to serve the site. I also need a fallback to normal use when the header is not set.

I have my main website: www.domain.com that is setup on CloudFront with the origin set to prod.domain.com. The site is setup on the server as www.domain.com (this cannot be changed)

What I want to do is set a custom header in CloudFront that will define the site name and use this header in my virtualhost to load the correct site.

For sake of example, I have added the header: company-host-name and set the value to www.domain.com. CloudFront origin is prod.domain.com and have updated the DNS to point to the server IP for this new domain. So far so good but this is now trying to load the prod.domain.com from the server.

What I want to do is use the custom header to load the site instead of the default way Apache handles this. Although I still need the fallback if no header is set. I think simply setting this header to the HOST header should suffice.

My Server Specs:

# cat /etc/centos-release
CentOS release 6.8 (Final)

# httpd -v 
Server version: Apache/2.2.15 (Unix)
Server built:   May 11 2016 19:28:33

I will need to know how to do this in Apache 2.4 also but for now 2.2 is essential.

I have tried playing with the headers and added this to my http.conf

<IfModule mod_headers.c>
<IfDefine company_host_name>
    Header set Host "%{company_host_name}e"
</IfDefine>
</ifModule>

I was hoping to override the Host header with the custom header value. I think this should suffice but I cannot seem to get this to work.

Perhaps I am over-complicating it and need to take a step back. So I am here asking for help on something I didn't think would be too difficult.

Thanks for any help you can provide.

Virtualhost

<VirtualHost *:80>
    ServerName www.domain.com
    ServerAlias prod.domain.com

    RequestHeader set Host "www.domain.com"

    DocumentRoot /var/www/vhosts/domain.com/public_html

    <Directory /var/www/vhosts/domain.com/public_html>
    Options -Indexes +FollowSymLinks -MultiViews
    AllowOverride All
    </Directory>

    ErrorLog /var/www/vhosts/domain.com/logs/error.log

    # Possible values include: debug, info, notice, warn, error, crit,
    # alert, emerg.
    LogLevel warn

    CustomLog /var/www/vhosts/domain.com/logs/access.log combined

    <IfModule mod_php5.c>
    php_value error_log /var/www/vhosts/domain.com/logs/php_error.log
    php_value newrelic.appname "domain.com - PHP"
    </IfModule>

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


    #INCLUDES

</VirtualHost>

Solution

  • From your problem description I understand that you want the origin server prod.domain.com to be able to serve content for www.domain.com.
    Apache selects the correct DocumentRoot to deliver the content by comparing the ServerName/ServerAlias value in each VirtualHost block with the "Host" Request Header sent by the client in the request. CloudFront will always act as an end user for the origin server and will always send prod.domain.com as Host header to the origin server.

    Host: CloudFront sets the value to the domain name of the origin that is associated with the requested object.

    http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/RequestAndResponseBehaviorCustomOrigin.html#request-custom-headers-behavior

    So, there should be 1 VirtualHost block for prod.domain.com on the origin server that can handle requests from Cloudfront. But, as you stated the website can only run as www.domain.com, both the domains should be served by the same VirtualHost block. Here, I am assuming that the application uses the "Host" header value "www.domain.com" to generate content.

    So, in your existing VirtualHost for www.domain.com, add a ServerAlias and RequestHeader set directive as follows:

    <VirtualHost *:80>
    
       ServerName www.domain.com
       ServerAlias prod.domain.com
    
       RequestHeader set Host "www.domain.com"
    
       DocumentRoot /path/to/webserver
       ..
    </VirtualHost>
    

    Now, as the ServerAlias is prod.domain.com, the requests from Cloudfront will be served from this DocumentRoot. Also as the Host request header will always be overwritten to www.domain.com, your application should be able to generate content.

    You don't have to add a custom header using Cloudfront, but just beacuse you asked in the question, it can be done as follows:

    In the AWS console, select CloudFront and then select the "Web Distribution" in question. From the tab on the top, select "Distribution Settings". Next Select "Origins" tab and click on "Edit". Add the custom header company-host-name in the field Origin Custom Headers, Header Name and the value www.domain.com in the "Header Value" field. It will be sent to the origin with every request.

    enter image description here