Create a gist now

Instantly share code, notes, and snippets.

@hayajo /MyApp.pm
Last active Dec 28, 2015

「MojoliciousでHTTP(S)の振り分けをリバースプロキシのバックエンドでも出来るようにしてみる」の例(Apache + mod_proxy)
<VirtualHost _default_:443>
ServerName localhost.myapp
... ssl conf ...
<Proxy *>
Order deny,allow
Allow from all
</Proxy>
ProxyRequests Off
ProxyPreserveHost On
ProxyPass / http://localhost:8080/
ProxyPassReverse / http://localhost:8080/
RequestHeader set X-Forwarded-HTTPS "1"
# 環境に応じて適宜設定
SetEnv proxy-initial-not-pooled 1
SetEnv force-proxy-request-1.0 1
SetEnv proxy-nokeepalive 1
</VirtualHost>
<VirtualHost *:80>
ServerName localhost.myapp
<Proxy *>
Order deny,allow
Allow from all
</Proxy>
ProxyRequests Off
ProxyPreserveHost On
ProxyPass / http://localhost:8080/
ProxyPassReverse / http://localhost:8080/
RequestHeader set X-Forwarded-HTTPS "0"
# 環境に応じて適宜設定
SetEnv proxy-initial-not-pooled 1
SetEnv force-proxy-request-1.0 1
SetEnv proxy-nokeepalive 1
</VirtualHost>
package MyApp;
use Mojo::Base 'Mojolicious';
# This method will run once at server start
sub startup {
my $self = shift;
# Router
my $r = $self->routes;
# https onry
my $ssl_r = $r->under(
sub {
my $self = shift;
return 1 if $self->req->is_secure;
$self->redirect_to($self->req->url->to_abs->scheme('https'));
}
);
# http onry
my $not_ssl_r = $r->under(
sub {
my $self = shift;
return 1 unless $self->req->is_secure;
$self->redirect_to($self->req->url->to_abs->scheme('http'));
}
);
$r->get('/')->to('example#index')->name('index');
$not_ssl_r->get('/not_ssl')->to('example#not_ssl')->name('not_ssl');
$ssl_r->get('/ssl')->to('example#ssl')->name('ssl');
}
1;
package MyApp::Example;
use Mojo::Base 'Mojolicious::Controller';
# This action will render a template
sub index {}
sub not_ssl { $_[0]->render('example/index') }
sub ssl { $_[0]->render('example/index') }
1;
upstream app {
server localhost:8080;
}
server {
listen 80;
listen 443 ssl;
server_name localhost.proxy;
ssl on;
ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;
ssl_session_timeout 5m;
ssl_protocols SSLv3 TLSv1;
ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv3:+EXP;
ssl_prefer_server_ciphers on;
location / {
proxy_pass http://app;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
set $mode 0;
if ($scheme = "https") {
set $mode 1;
}
proxy_set_header X-Forwarded-HTTPS $mode;
}
}
% layout 'default';
% title 'SSL/NOT_SSL ROUTE - Mojolicious ' . $Mojolicious::VERSION;
<h2><%= $self->req->url->to_abs %></h2>
<ul>
<li>
<a href="<%= url_for('not_ssl') %>">not_ssl</a>
</li>
<li>
<a href="<%= url_for('ssl') %>">ssl</a>
</li>
</ul>
<pre><%= dumper $self->req->headers->to_hash %></pre>
@hayajo
Owner
hayajo commented Nov 12, 2013

ディレクトリセパレータは「_」(アンダースコア)どす。

@hayajo
Owner
hayajo commented Nov 12, 2013

ちょいと修正

@hayajo
Owner
hayajo commented Nov 13, 2013

Apache 2.2.22-6ubuntu2 + Mojolicious 3.97, 4.28, 4.57 の morbo と hypnotoad で動作確認

@hayajo
Owner
hayajo commented Nov 15, 2013

Nginx 1.2.1-2.2ubuntu でも動作確認

@clicktx
clicktx commented Nov 15, 2013

自分の不具合は

proxy_set_header Host $host;

が設定していなかったからのようでした。

ちなみに、

server {
    listen       80;
    listen       443 ssl;
    server_name  localhost.proxy;

    ... ssl conf ...

    location / {
        proxy_pass http://app;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        #set $mode 0;
        if ($scheme = "https"){
          set $mode "on";
        }
        proxy_set_header X-Forwarded-HTTPS $mode;
    }
}

とconfigをまとめた場合でも動作確認出来ました!感謝!

@hayajo
Owner
hayajo commented Nov 15, 2013

@clicktx コメントありがとうございます。まとめたほうがスッキリして良いですね。参考にさせていただきます。

@hayajo
Owner
hayajo commented Nov 18, 2013

MOJO_REVERSE_PROXY=1 して起動すること。

じゃないと HTTPS リクエストの場合に req->base->scheme が https にならないよ。

# e.g.
MOJO_REVERSE_PROXY=1 hypnotoad script/my_app

リバースプロキシを利用したときにホスト名、ポート番号、パスが正しく認識されるようにする / Mojoliciousリファレンス - サンプルコードによるPerl入門

@clicktx
clicktx commented Sep 8, 2014

http://mojolicio.us/perldoc/Mojolicious/Guides/Cookbook#Nginx
にあるように、

proxy_set_header X-Forwarded-Proto "http";

と、最近のmojolicious(v5.35時点)では proxy_set_header X-Forwarded-Proto で検知するように仕様変更された(?)のでしょうか。

nginxの設定で言うと、

server {
    listen       80;
    listen       443 ssl;
    server_name  localhost.proxy;

    ... ssl conf ...

    location / {
        proxy_pass http://app;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        #set $mode 0; ← 不要
        #if ($scheme = "https"){ ← 不要
        #  set $mode "on"; ← 不要
        #} ← 不要
        #proxy_set_header X-Forwarded-HTTPS $mode; ← 不要
        proxy_set_header X-Forwarded-Proto $scheme;  ←追加
    }
}

でうごくようになりました。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment