Accept cookies for analytics, social media, and advertising, or learn more and adjust your preferences. These cookies are on by default for visitors outside the UK and EEA. Privacy Notice.
Using nginx-embedded-perl module on the same server as the imap/pop proxy as the auth backend
Note
This solution will block entire NGINX worker when reading user information from DB and therefore not recommended for real use.
This solution is being used at at ISP with 35000+ mailboxes for almost 2 years now fine. If you want shameful plug, the ISP is Worldsoft (http://www.worldsoft.info)
Start with the configuration from IMAP Proxy Example. For detail information about different configuration parameters, see the ngx_mail_core_module documentation.
Configure NGINX with embedded perl and mail
./configure --with-http_perl_module --with-mail
nginx/conf/nginx.conf
:
user nobody;
worker_processes 1;
error_log logs/error.log info;
pid logs/nginx.pid;
events {
worker_connections 1024;
multi_accept on;
}
http {
perl_modules perl/lib;
perl_require mailauth.pm;
server {
location /auth {
perl mailauth::handler;
}
}
}
mail {
auth_http 127.0.0.1:80/auth;
pop3_capabilities "TOP" "USER";
imap_capabilities "IMAP4rev1" "UIDPLUS";
server {
listen 110;
protocol pop3;
proxy on;
}
server {
listen 143;
protocol imap;
proxy on;
}
}
The ultrafast NGINX based authentifier, nginx/perl/lib/mailauth.pm
:
package mailauth;
use nginx;
use DBI;
my $dsn="DBI:mysql:database=DBNAME;host=HOSTNAME";
our $dbh=DBI->connect_cached($dsn, 'dbusername', 'dbpass', {AutoCommit => 1});
our $sth=$dbh->prepare("select password,mail_server from mailaccounts where username=? limit 1");
our $auth_ok;
our $mail_server_ip={};
our $protocol_ports={};
$mail_server_ip->{'mailhost01'}="192.168.1.22";
$mail_server_ip->{'mailhost02'}="192.168.1.33";
$protocol_ports->{'pop3'}=110;
$protocol_ports->{'imap'}=143;
sub handler {
my $r = shift;
$auth_ok=0;
$sth->execute($r->header_in("Auth-User"));
my $hash=$sth->fetchrow_hashref();
# assuming that the query results password and mail_server
# assuming that the password is in crypt format
if (crypt($r->header_in("Auth-Pass"), $hash->{'password'}) eq $r->header_in("Auth-Pass")){
$auth_ok=1;
}
if ($auth_ok==1){
$r->header_out("Auth-Status", "OK") ;
$r->header_out("Auth-Server", $mail_server_ip->{$hash->{'mail_server'}});
$r->header_out("Auth-Port", $protocol_ports->{$r->header_in("Auth-Protocol")});
} else {
$r->header_out("Auth-Status", "Invalid login or password") ;
}
$r->send_http_header("text/html");
return OK;
}
1;
__END__