McA has asked for the wisdom of the Perl Monks concerning the following question:
Hi all,
I'm pretty new to Plack and PSGI and need your recommendation/advice. I like the possibility to start a development server with using plackup in the foreground. Is there also an easy way to start a server listening on two ports, one with and the other without SSL? Do I have to start two servers? Or is there a PSGI aware server out there which can listen on two ports (SSL/no SSL) for the same app? Probably there is a nice way with Server::Starter.
How do I know which PSGI aware server is SSL enabled? E.g. when I look (perldoc) at HTTP::Server::PSGI there is no information concerning SSL. When you look at the code you can get the idea that this server is SSL capable. (Is starman SSL enabled?)
Best regards
McA
Re: PSGI, Plack et.al.
by Corion (Patriarch) on Oct 24, 2012 at 11:29 UTC
|
I have written a toy "enforce-https" middleware, and also a toy "run two servers" middleware, but not yet released onto CPAN.
To write a multiplexing server that can serve PSGI applications from two (or more) ports, you will have to look at the various backends. I chose AnyEvent, which is based on the idea of nonblocking handling. The existing implementations on CPAN (partially in Server::Starter I think) didn't work on Windows for me. One ugly part is that SSL does not work well on Windows+Strawberry+AnyEvent, I think because OpenSSL is linked to a different memory allocator than Strawberry Perl.
I think SSL-enabling a server is basically only the process of "replacing" the socket the server reads from by a socket that knows SSL. AnyEvent did that nicely, but I don't know what other servers/frameworks do.
Update: Plack::Handler::AnyEvent::HTTPD needs a small patch to allow SSL: https://github.com/miyagawa/Plack-Handler-AnyEvent-HTTPD/pull/2#issuecomment-7046948
| [reply] |
|
I found that multi-server implementation. It does not only use AnyEvent, it also relies on Coro to make switching between server loops easy when they get blocked. The code was developed under Windows, but the SSL problems alluded to above still apply.
#!perl -w
use strict;
use Coro;
use AnyEvent;
use AnyEvent::TLS;
use Plack::Handler::AnyEvent::HTTPD;
use Dancer ();
use App::Regexplain;
use Data::Dumper;
my %config = (
'http' => { host => '127.0.0.1', port => 8080, protocol => 'http',
+ proto => 'tcp' },
'https' => {
host => '127.0.0.1',
port => 8443,
ssl => {
cert_file => 'C:/Projekte/App-Regexplain/certs/testcert.pem',
key_file => 'C:/Projekte/App-Regexplain/certs/testkey-nopass.p
+em',
},
},
);
=begin other_api
__PACKAGE__->run(
port => [8080, "8443/ssl"],
ipv => '*', # IPv6 if available
SSL_key_file => '/my/key',
SSL_cert_file => '/my/cert',
);
=cut
for my $serverkey (sort keys %config) {
my $config = $config{ $serverkey };
my $runner = Plack::Runner::Multi->new;
$runner->parse_options(
'--server', 'AnyEvent::HTTPD',
'-p', $config->{port},
'-o', $config->{host},
'bin\\app.pl',
);
if( $config->{ssl} ) {
#$config->{ ssl } = AnyEvent::TLS->new(
# %{$config->{ ssl }}
#);
push @{$runner->{options}}, ssl => $config->{ssl}
};
my ($loader,$server,$app) = $runner->psgi_app();
async {
$loader->preload_app($app);
$loader->run($server);
};
};
# Kick off the event loop
AnyEvent->condvar->recv;
package Plack::Runner::Multi;
use strict;
use parent 'Plack::Runner';
use Coro;
use Data::Dumper;
# Paste from Plack::Runner::run except the $loader->run at the end
sub psgi_app {
my $self = shift;
#unless (ref $self) {
# $self = $self->new;
# $self->parse_options(@_);
# return $self->run;
#}
unless ($self->{options}) {
$self->parse_options(@_);
};
my @args = @{$self->{argv}};
$self->setup;
my $app = $self->locate_app(@args);
$ENV{PLACK_ENV} ||= $self->{env} || 'development';
if ($ENV{PLACK_ENV} eq 'development') {
$app = $self->prepare_devel($app);
}
if ($self->{access_log}) {
open my $logfh, ">>", $self->{access_log}
or die "open($self->{access_log}): $!";
$logfh->autoflush(1);
$app = $self->apply_middleware($app, 'AccessLog', logger => su
+b { $logfh->print( @_ ) });
}
my $loader = $self->loader;
#warn "Loading Server with " . Dumper $self->{options};
my $server = $self->load_server($loader);
#$loader->preload_app($app);
return ($loader, $server, $app);
#$loader->run($server);
}
1;
| [reply] [d/l] |
Re: PSGI, Plack et.al.
by Anonymous Monk on Oct 24, 2012 at 11:45 UTC
|
HTTP::Server::PSGI
• Plack Built-in
• Pure Perl
• Single-process, cross platform
• Experimental IPv6, SSL
• Automatic reloading with -r
plackup https -> Gepok - PSGI server with built-in HTTPS support, Unix sockets, preforking | [reply] |
|
Thank you, Anonymous Monk.
The last hint was helpful. I'll have a look at Gepok. It seems promising.
Update: I looked at it and as far as I can see it fulfills exactly what I want for development. Therefor a ++ to our Anonymous Monk.
Best regards
McA
| [reply] |
|
I really like Gepok. For Starman etc the advice is to place an HTTPS proxy (e.g. Apache) in front of the server. However, that means that the server misses out on all the transactional information in the HTTPS connection, such as client certificates. Gepok has the HTTPS built in, so you can use HTTPS certificates for authentication.
perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'
| [reply] |
|
|
|
Actually, it does not matter. HTTP or HTTPS, the underlying protocol is exactly the same. In Apache, a different <virtualHost> definition will correspond to each. What each one of them does, if need be, could be exactly the same. (If the FastCGI servers are static, the traffic from both VHosts could in fact be sent without error to the same pool. So it CAN be done, should you actually want to do it, and the Perl code does not have to know or care.
| [reply] |
|
| [reply] |
|
|
|
Re: PSGI, Plack et.al.
by sundialsvc4 (Abbot) on Oct 24, 2012 at 12:59 UTC
|
So far as I know, once the data gets through the HTTP/HTTPS layer, the FastCGI layer doesn’t care. But what I have always done is to nevertheless clearly-separate the HTTPS from the HTTP traffic handlers, since one is thought of as secure and the other is not. I want to keep them at arm’s length and maybe on a different set of servers, due to the classification of the data which each one handles. Both sets of handlers actually use (or require) duplicate copies of the same code-base, however.
| |
|
|