Apache22+mod_proxy+mongrel+ssl

I am trying to move a Rails application, that uses SSL, from an
Apache/FastCGI stack, that works fine, to Apache22 and mongrel
working with a single mongrel instance (i.e., not mongrel cluster, yet.)

I have a single mongrel instance demonized and working fine on http,
on port 3000. Apache/OpenSSL/certs working fine.

Here is my test http.conf (deliberately kept as simple as possible):

<VirtualHost 69.1.254.101:80>
ServerName new.identry.com
ErrorLog “/var/log/www/new.identry.com-error.log”
CustomLog “/var/log/www/new.identry.com-access.log” combined

#DocumentRoot “/home/identry/public_html”
ProxyPass / http://new.identry.com:3000/
ProxyPassReverse / http://new.identry.com:3000/
ProxyPreserveHost on

<VirtualHost 69.1.254.101:443>
ServerName new.identry.com
ErrorLog “/var/log/www/new.identry.com-error.log”
CustomLog “/var/log/www/new.identry.com-access.log” combined
SSLEngine on
SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:
+SSLv2:+EXP:+eNULL
SSLCertificateKeyFile “/usr/local/etc/apache22/certs/
new.identry.com/server.key
SSLCertificateFile “/usr/local/etc/apache22/certs/new.identry.com/
server.crt”

#DocumentRoot “/home/identry/public_html”
RequestHeader set X_FORWARDED_PROTO ‘https’
ProxyPass / https://new.identry.com:3000/
ProxyPassReverse / https://new.identry.com:3000/
ProxyPreserveHost on

The two commented-out DocumentRoot lines let me test the Apache SSL
config with static content. If I use the DocumentRoot lines instead
of the Proxy lines, then Apache serves up the static test content
with both http and https addresses, no problem. So I believe Apache/
SSL is working fine.

Furthermore, using the configuration as written above, the http
connection to mongrel (and the Rails app behind it) also works fine.
So a the plain Apache/mod_proxy/mongrel/Rails stack also seems to be
working fine.

What I’m having trouble with is the Apache/SSL/mod_proxy/mongrel/
Rails stack. If I try to reach the site with https://new.identry.com,
I get the following error in the mongrel.log:

Thu Jan 17 09:10:57 -0500 2008: HTTP parse error, malformed request
(75.127.142.66): #<Mongrel::HttpParserError: Invalid HTTP format,
parsing fails.>
Thu Jan 17 09:10:57 -0500 2008: REQUEST DATA: “\200=\001\003\000\000$
\000\000\000\020\000\0009\000\0008\000\0005\000\0003\000\0002\000\000
\004\000\000\005\000\000/\000\000\026\000\000\023\000\376\377\000\000
\n\243?S\376???|\255?ɇy”

PARAMS: {}

I get exactly the same error if I bypass Apache and go to https://
new.identry.com:3000.

I am guessing that the above error message is Mongrel choking on
encrypted data. So, I am guessing that Mongrel simply can’t handle an
https connection. Therefore, redirecting to an https instance is a
bad idea.

The problem is, if I redirect to an http instance, like so:

<VirtualHost 69.1.254.101:443>
… snip …

RequestHeader set X_FORWARDED_PROTO ‘https’
ProxyPass / http://new.identry.com:3000/
ProxyPassReverse / http://new.identry.com:3000/
ProxyPreserveHost on

I don’t get a secure connection on the browser. I type https://…
and get redirected to http://

Obviously I am doing something wrong. I’ve googled all over the
place, and can’t find a good answer. Any help, much appreciated.

Brgds: John

~

Websites for On-line Collectible Dealers

Identry, LLC
John A.
(631) 546-5079
[email protected]
www.identry.com

So I just found this in the mongrel FAQ (a good place for it, too!):

Q: Does Mongrel have SSL?
No, having a Ruby web server do complex SSL cryptography is stupid
when you can get any of the major web servers to do it faster.
Q: Why are Apache & SSL – Redirects going to http:// not https://?
Basically, you need to pass in a header so Rails knows what to do.
Read the bottom of the Apache Documentation for instructions on how
to do this.

So I guess the correct approach is to redirect to http://
address.of.mongrel:3000, and to use the RequestHeader to signal to
Rails that this is an https request.

Can someone confirm that my understanding is correct?

I’m asking because this config doesn’t work for me, yet, but if I’m
on the right track, I should be able to find the problem eventually.

Thanks: John

It’s amazing how often you figure out a problem, simply by writing it
down in the form of a question!

Okay! I’ve got it working. I was actually testing a non-https page,
so Rails very correctly redirected me back to http. This is one of
the things that threw me.

When I tried it on an ‘ssl_required’ page, it worked fine.

Hopefully these emails will help someone in the future.

Brgds: John

On Jan 17, 2008, at 10:43 AM, John A. wrote:

So I guess the correct approach is to redirect to http://


Mongrel-users mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/mongrel-users

Websites for On-line Collectible Dealers

Identry, LLC
John A.
(631) 546-5079
[email protected]
www.identry.com

On Jan 17, 2008 11:04 AM, John A. [email protected] wrote:

Brgds: John

Awesome!

~Wayne

On 1/18/08, Wayne E. Seguin [email protected] wrote:

It certainly helped me! Thanks a lot.

Ronan

For me this solution wasn’t working.
I dunno if it is a change from Rails3 or not, but the method checking
for ssl requests expects a different request header:

  def ssl?
    @env['HTTPS'] == 'on' || @env['HTTP_X_FORWARDED_PROTO'] == 

‘https’
end

I modified my proxy config to set the correct header (this is the
resulting line)

 # Set header to indentify https requests for Mongrel
 RequestHeader set HTTP_X_FORWARDED_PROTO "https"

After this, everything was working. This is how my config looks in the
end:

<VirtualHost *:80>
Include sites-available/common/my_site

Include sites-available/common/my_site

SSLProxyEngine on

The values for these three checks are already like this by default

Just know that they can be used for more complicated configs

SSLProxyCheckPeerCN off

SSLProxyCheckPeerExpire off

SSLProxyVerify none

Set header to indentify https requests for Mongrel

RequestHeader set HTTP_X_FORWARDED_PROTO “https”

SSLEngine on

Server Certificate

SSLCertificateFile /etc/apache2/ssl/my_certificate.crt

Server Private Key

SSLCertificateKeyFile /etc/apache2/ssl/my_private.key

… othere SSL settings …

Content of sites-available/common/my_site

ServerName my_site
ServerAlias my_site *.my_site

DocumentRoot /path/to/public/folder/of/my/app

<Directory /path/to/public/folder/of/my/app>
AllowOverride all
Options -MultiViews

<Proxy *>
# Review this if you need more restrictive access
Order Allow,Deny
Allow from all
Deny from none

Even for https, we redirect to http

We already set HTTP_X_FORWARDED_PROTO to https in the 443 virtual host

ProxyPass / http://localhost:3000/
ProxyPassReverse / http://localhost:3000/
ProxyPreserveHost on

I hope this helps other people too!