cool tech graphics

Running Drupal Secure Pages behind a proxy

This article is one of Metal Toad's Top 20 Drupal Tips. Enjoy!

If you plan to use the securepages module behind a proxy that terminates SSL, there are some additional server configuration steps you need to take.

In order to detect what the protocol is in use, securepages tests the value of $_SERVER['HTTPS']. Out of the box, this merely reflects the immediate connection to your proxy. If this protocol differs from that used by the original client, then securepages can't work (the most likely outcome is a redirect loop).

To resolve this, you'll need to ask your proxy to send the X-Forwarded-Proto header. While you're free to use any header label you choose, X-Forwarded-Proto seems to have become the de facto standard.

Configure your web server

There are several possible approaches here; which one you choose is largely a matter of taste.

Apache SetEnvIf

I personally like this approach specifically because it doesn't require any changes to the application code, and makes the SSL proxy appear completely transparent to Drupal. The SetEnvIf directive can be placed in httpd.conf, a vhost configuration file, or in your .htaccess file.

SetEnvIf X_FORWARDED_PROTO https HTTPS=on

One note of caution: environment variables set this way work fine in PHP (and therefore the Secure Pages module), but are not accessible in RewriteCond directives due to the order in which rewrites are evaluated.

Modify $_SERVER directly

This approach involves directly modifying $_SERVER['HTTPS'] in settings.php. Since this file is loaded very early in the request (during DRUPAL_BOOTSTRAP_CONFIGURATION), any changes here will kick in before securepages initializes.

if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) &&
  $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') {
  $_SERVER['HTTPS'] = 'on';
}

Configure your proxy

What happens next depends entirely on what proxy software you have. Here are some some hints for several popular proxies (we use f5 load balancers at Metal Toad; the others have been collected from around the web but not tested):

Amazon Elastic Load Balancer (ELB)

ELBs support X-Forwarded headers by default.

f5

Inside an iRule:

when HTTP_REQUEST {
  if {([TCP::local_port] == 80) and !( [HTTP::header "X-Forwarded-Proto"] eq "http") }{
    HTTP::header insert X-Forwarded-Proto "http"
  } elseif {([TCP::local_port] == 443) and !( [HTTP::header "X-Forwarded-Proto"] eq "https") } {
    HTTP::header insert X-Forwarded-Proto "https"
  }
}

Pound

Inside a ListenHTTP / ListenHTTPS directive:

ListenHttp
  HeadRemove "X-Forwarded-Proto"
  AddHeader "X-Forwarded-Proto: http"
  ...
ListenHttps
  HeadRemove "X-Forwarded-Proto"
  AddHeader "X-Forwarded-Proto: https"
  ...

Apache

Inside a virtual host config:

<VirtualHost default:80>
RequestHeader set X-Forwarded-Proto "http"
...
</VirtualHost>
<VirtualHost default:443>
RequestHeader set X-Forwarded-Proto "https"
...
</VirtualHost>

nginx

Inside a location directive:

proxy_set_header X-Forwarded-Proto $scheme;

A note about forged headers

When using a proxy it's generally good advice to keep your web servers firewalled from the greater internet, and make sure headers such as this can't be forged. I've attempted to give examples that always override any value set by a mischief-making client.

That said, in this particular case I don't think a forged X-Forwarded-Proto creates any new vulnerabilities. While it might at first seem to make SSL stripping easier, the unfortunate reality is that SSL stripping will succeed either way.

Date posted: September 2, 2010

Comments

We're on a tight deadline to get our new configuration online - and this tip on how to configure an F5 to work with securepages was a blessing. Even the guys at the datacenter were surprised it worked. :) Thank you, thank you!

A follow up after a week with our F5:

After running it all through my head a couple times I realized that since we terminate SSL on the F5, we didn't even need mod_ssl or securepages for our front servers anymore. The F5 handles everything - the SSL termination (thus replacing mod_ssl), and our host was willing to write some http classes on the F5 itself to redirect certain URI's to https for us so we don't need securepages anymore either.

This was very helpful, but for our server we had to use a slightly different directive for Apache:

SetEnvIf X-Forwarded-Proto https HTTPS=on

Note the dashes as opposed to underscores.

Thank you very much!

Thank you!

I followed this advice (with Will's change) using Lighttpd 1.4.28 as a proxy for Apache 2.2.20. Lighttpd didn't require any configuration to set X-Forwarded-Proto - it seems to do it out of the box - which is nice as I'm using Lighttpd to serve static content.

Dylan,
thanks for the info! I spent a few weeks trying to get everything working right behind our load-balance until I can across your directions. I simplified a bit though since the LB is run by a separate group. I simply put
$_SERVER['HTTPS'] = 'on';
into my settings.php which took care of what ailed me (users seeing http URLs in response to https requests).
--Tim

Wills comments were a lifesaver !!

SetEnvIf X-Forwarded-Proto https HTTPS=on

Worked like a charm :) Thanks Will and Dylan!.

Hi - Why can't Drupal live in http (non-secure) behind the firewall if its load balancer proxy is negotiating SSL for the site?

Yes it can – that's the subject of this post.

Thanks for your reply, Dylan. I guess what has always eluded me all these years, then, is why is it that the application behind the reverse proxy (Drupal in this case) ever needs to know how the request came in and that it is operating in anything other than http?

In the configuration described above, the application (Drupal) is making the decisions about when to redirect visitors to HTTP or HTTPS. The responses might also vary in other ways depending on the protocol (for example on this web site the CDN URL changes on HTTPS). Implementing this logic in the application is often advantageous because the app has a lot more knowledge about the the request than the proxy. Keeping all the logic contained in the app also makes it more portable.

Ok super -- that makes sense. The application (Drupal) can receive and respond in http for all requests, but it is telling the proxy "by the way make this next one https for the client.. You and I are cool, though." The proxy would otherwise make all requests http (or https).

Thanks!

Just wanted to add my thanks here too. I'd spent all day trying stuff, to no avail, until I stumbled across this. Problem solved (thanks also to Will for his comment)!

Hello,

We have been using this with our Drupal 6 site and F5 load balancer successfully for a couple of months. We've noticed some errors in our logs though. We are running BIG-IP 11.3.0 Build 3144.0 Hotfix HF8.

We are getting TCL errors in our load balancer logs:

TCL error: /Common/www.*****.com-X-Forwarded-Proto <HTTP_REQUEST> - Operation not supported (line 3) invoked from within "HTTP::header insert X-Forwarded-Proto "https""
 
TCL error: /Common/www.*****.com-X-Forwarded-Proto <HTTP_REQUEST> - Operation not supported (line 5) invoked from within "HTTP::header insert X-Forwarded-Proto "http""

We setup ours as follows:

when HTTP_REQUEST {
  if {([HTTP::host] equals "*****.com" || [HTTP::host] equals "www.*****.com)}{
	  if {([TCP::local_port] == 80) and !( [HTTP::header "X-Forwarded-Proto"] eq "http") }{
		HTTP::header insert X-Forwarded-Proto "http"
	  } elseif {([TCP::local_port] == 443) and !( [HTTP::header "X-Forwarded-Proto"] eq "https") } {
		HTTP::header insert X-Forwarded-Proto "https"
	  }
  }
}

Except for the additional check on the hostname our code is basically the same as what is outlined in this article. Does anyone see why there would be a TCL error? Thanks!

I ended up having to use SetEnvIf X-Forwarded-Proto https HTTPS=on instead to get it to work..

wonderful information you've got at this point what are you're opinion on our
web site on the subject of click me

Nice information. Worked for me

Thx

Add new comment

Restricted HTML

  • Allowed HTML tags: <a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • You can enable syntax highlighting of source code with the following tags: <code>, <blockcode>, <cpp>, <java>, <php>. The supported tag styles are: <foo>, [foo].
  • Web page addresses and email addresses turn into links automatically.
  • Lines and paragraphs break automatically.

Metal Toad is an Advanced AWS Consulting Partner. Learn more about our AWS Managed Services

Schedule a Free Consultation

Speak with our team to understand how Metal Toad can help you drive innovation, growth, and success.