Hypnotoad Config Issue and Fix

646 views
Skip to first unread message

James B

unread,
May 3, 2013, 12:07:36 PM5/3/13
to mojol...@googlegroups.com
Hello,

I have a challenging production environment. The short version is that I am using trying to use a single hypnotoad instance to host multiple domain names. It was working great right up until I added my second https domain. After mucking about a while, I tried using the bare host name (blah.com instead of www.blah.com) and it worked. This was just totally non-obvious from the documentation, so I wanted to mention it here in case somebody else is running into the same thing. My config is:

{
    listen => ['http://*:80',
    'https://blah1.com:443:/usr/local/www/prod/doc/blah1.crt:/usr/local/www/prod/doc/blah1.key',
    'https://blah2.com:443:/usr/local/www/prod/doc/blah2.crt:/usr/local/www/prod/doc/blah2.key',
],
    workers => 4,
    pid_file => '/tmp/blah.pid',
};


Oh, and if you are using an intermediate certificate, you can just contatinate it to the end of your actual cert and it works.

James

Sebastian Riedel

unread,
May 3, 2013, 12:24:44 PM5/3/13
to mojol...@googlegroups.com
> ...so I wanted to mention it here in case somebody else is running into the same thing.

Since your motivation is to inform others, it might be worth mentioning that this config format is for old versions of Mojolicious only and not supported anymore for over a year.

--
Sebastian Riedel
http://twitter.com/kraih
http://mojolicio.us

James B

unread,
May 4, 2013, 10:32:42 AM5/4/13
to mojol...@googlegroups.com
That is a good point, I am using the stock version of Mojolicious that comes with Ubuntu 10.04 LTS, which isn't exactly the latest version. I currently have two production servers running Mojolicious (out of over a dozen that I currently administer) and I initially had issues with cpan. There are several other posts on this list with cpan issues, so I'm not exactly the only person with that opinion. I also value not having yet another thing to worry about, keep up on, and administer. And in my opinion stability trumps virtually every other concern on a production server.

So I don't use the latest version of Mojolicious, and I'm quite happy with that decision. In fact, I'm not looking forward to when Ubuntu 12.04 LTS comes out and I have to deal with all the changes to Mojolicious due to new features I neither need nor want. For example, right now I have a unified configuration file per server to manage various things, including several things outside of Mojolicious, and my understanding is that at some point I'm going to spend the time to figure out how the new configuration stuff in Mojolicious works, rewrite a good chunk of my code unrelated to Mojolicious, probably have a separate configuration file just for Mojolicious, and likely get no real benefit for going through any of that.

Thanks for your excellent point,

James

James B

unread,
May 6, 2013, 6:15:56 PM5/6/13
to mojol...@googlegroups.com
Whoops, looks like I didn't test enough and I really didn't get it working. So to recap, I have an application that serves multiple domain names, and depending on the domain name requested it shows different content. It has been working swimmingly, but now I need to add https support for more than one domain/host name on the same port (443) and hypnotoad does not seem to support that. It seems to translate the domain name into an IP address and then bind to that IP address and port. The end result is that if you listen on the same port with multiple host names that resolve to the same IP address, then whatever certificate is listed last is used for all the host names. And if you try to run another instance of hypnotoad or morbo then you get an error "Can't create listen socket: Address already in use at /usr/share/perl5/Mojo/IOLoop.pm line 166".

So, can anybody tell me if there is a way to do what I want in any version of Mojolicious? I just sort of assumed that since most web servers support this then Mojolicious would. If it is possible in a newer version of Molicious then I might have to upgrade after all.


James

On Friday, May 3, 2013 11:07:36 AM UTC-5, James B wrote:

Sebastian Riedel

unread,
May 6, 2013, 6:26:38 PM5/6/13
to mojol...@googlegroups.com
> So, can anybody tell me if there is a way to do what I want in any version of Mojolicious? I just sort of assumed that since most web servers support this then Mojolicious would. If it is possible in a newer version of Molicious then I might have to upgrade after all.

If what you want happens to be SNI, then no, we do not support it on the server side yet, patches welcome.

jay m

unread,
May 7, 2013, 10:56:44 AM5/7/13
to mojol...@googlegroups.com

serving multiple https "vhosts" on the same IP/port is an age-old chicken and egg problem. the web server doesn't know what the host name is until after the SSL/TLS handshake is partly done, but it can't choose a certificate until it knows the hostname. it's explained pretty well here: http://wiki.apache.org/httpd/NameBasedSSLVHostsWithSNI

the SNI extension designed to solve this problem is pretty new -- wasn't built into openssl until 2010, and browser support is still iffy. i wouldn't necessarily expect this feature in Mojolicious, which is an application framework that happens to have an http server, as opposed to apache which is an http server that happens to support applications (via cgi or mod_whatever).

a common ("correct"?) way to handle your situation in a production environment is to run your mojo apps via separate hypnotoad instances on different ports (probably without SSL), with an apache or nginx (or whatever) reverse proxy in front directing traffic and handling SSL/TLS/SNI duties. alternately you can use an apache front end with your mojo apps running via psgi/plack or fastCGI.

these setups have some other advantages as well, since you can do additional security, access logging, static file serving, etc. at the front end web server. the apache configurations for all these scenarios are fairly straight forward

James B

unread,
May 7, 2013, 12:31:05 PM5/7/13
to mojol...@googlegroups.com
Thank you so much for the reply, that makes things a lot more clear. Unfortunately I tried my hand before at using apache to proxy requests and failed miserably. I spent a large amount of time trying to do that and ended up with an open proxy for my troubles. I only need a secure transaction for credit card submissions, so what I decided to do was use one generic domain for that and force a non secure connection for everything else. It's not a great solution but it was relatively quick and easy to implement.

James

Roland Lammel

unread,
May 7, 2013, 1:07:24 PM5/7/13
to mojol...@googlegroups.com
Using nginx (same for Apache) with Mojolicious is quite painless actually. You only need to make sure, that the schema and host that was externally requested is known to your application and the base_url of your mojo app is updated accordingly.

External: https://myapp.company.com/subdir/login => NGINX vhost with SSL doing proxy_pass to http://app1.internal.company.com:4001 => hypnotoad listening on http://app1.internal.com:4001 for this particular application

The nginx config looks something like this:
server {
    listen 443;
    server_name myapp.company.com;
    location / {
        proxy_pass http://app1.internal.company.com:4001;
        proxy_set_header    X-Forwarded-For $remote_addr;
        proxy_set_header    X-Forwarded-Base $scheme://$server_name;
    }
    root /var/empty;

    ssl on;
    ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
    ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;
}

And in your mojo app you need to handle X-Forwarded-Base header. Please note that the header X-Forwarded-Base is no official standard and could be also achieved using (the sometimes more common) X-Forwarded-Scheme, X-Forwarded-Host, X-Forwarded-Path. I prefer the simpler X-Forwarded-Base

So in your app, ensure the request base url is corrected, so url_for will do what you mean:

    $self->app->hook(before_dispatch => sub {
        my $self = shift;
        my $forward_base = $self->req->headers->header('X-Forwarded-Base');
        $self->req->url->base(Mojo::URL->new($forward_base) if $forward_base;
    });


That works fine for me, of course you could optimize caching of static files in your nginx config too.
Apache is very similar using:
    RequestHeader set "X-Forwarded-Base" "https://myapp.company.com/subdir/"

Hope that helps, cheers

+rl

MfG

+rl
--
Roland Lammel
QuikIT - IT Lösungen - flexibel und schnell
Web: http://www.quikit.at
Phone: +43 (676) 9737845
Email: r...@quikit.at

"Enjoy your job, make lots of money, work within the law. Choose any two."


2013/5/7 James B <mstr...@gmail.com>
--
You received this message because you are subscribed to the Google Groups "Mojolicious" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mojolicious...@googlegroups.com.
To post to this group, send email to mojol...@googlegroups.com.
Visit this group at http://groups.google.com/group/mojolicious?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

James B

unread,
May 8, 2013, 2:49:43 PM5/8/13
to mojol...@googlegroups.com
Thanks, that's some good information to have. Like I said before, I went looking for this before and didn't find it (especially the X-Forwarded-Base bit). My work around seems to be working, so I'm not going to change it right now. When I have some spare time I will definitely give this a shot, though.

James
Reply all
Reply to author
Forward
0 new messages