基于nginx的pop3/imap/smtp的反向代理解决方案

2011年8月31日 发表评论 阅读评论

本文介绍基于nginx的邮局反向代理配置方案。nginx对来源于客户端的pop3/smtp/imap请求予以转发到后端postfix,后端邮件服务器采用postfix 2.8.0,已配置并正常运行。

本方案参考 Using a php script on apache server as the auth backend ,并基于此方案进行改进,并增加了对smtp的代理。

环境配置:centos 5.5 + nginx 1.0.4

软件安装

yum groupinstall 'Development Tools' -y
rpm -Uhv http://apt.sw.be/redhat/el5/en/i386/rpmforge/RPMS/rpmforge-release-0.3.6-1.el5.rf.i386.rpm
yum install libxml2-devel libxslt-devel pcre-devel libtool-ltdl libtool-ltdl-devel

cd /usr/src
wget http://nginx.org/download/nginx-1.0.4.tar.gz
tar -zxf nginx-1.0.4.tar.gz
cd nginx-1.0.4
./configure –prefix=/usr/local/nginx –with-mail –without-http
make && make install

配置nginx.conf

#user  nobody;
worker_processes  1;
error_log  logs/error.log  info;
events {
    worker_connections  1024;
}
mail {
    auth_http  指定IP:80/auth.php;
    pop3_capabilities  "TOP"  "USER";
    imap_capabilities  "IMAP4rev1"  "UIDPLUS";
   
    server {
            listen     110;
            protocol   pop3;
            proxy      on;
    }
    server {
            listen     143;
            protocol   imap;
            proxy      on;
    }
    server {
        listen    25;
        protocol    smtp;
        proxy    on;
        smtp_auth login plain;
        xclient    off;
    }
}

说明:
1.安装nginx时禁掉了http(–without-http),因为我们的目标只是转发pop3/smtp/imap请求,故nginx.conf也是相当简单,只有mail模块。如果还需要代理80端口(例如webmail),可以自行编译对http的支持。

2.smtp的配置模块里必须加入xclient off,否则当nginx向后转发smtp请求时,postfix将报“lost connection after XCLIENT”,同时nginx报“550 5.7.0 Error: insufficient authorization”. nginx对smtp的代理,与pop3/imap是不同的,详细见后文。

3.指定IP是用于认证的,需要放认证脚本auth.php. 认证脚本的作用就是验证用户和密码,一般自定义,可以放在任意的服务器上。本方案中选择放在后端邮件服务器上,便于管理。

这里有一个问题,postfix本身已经集成了认证机制(本人采用的是cyrus sasl2+courier-authlib),为什么加了反向代理,认证过程就要移动到反向代理上呢?这样岂不是就变成非透明代理了吗?为什么不作纯碎的透明代理呢?
根据测试,如果这个认证脚本不设验证,直接透传所有pop3/imap请求到后端,在后端邮件服务器还会进行一次认证,但是对于smtp请求,将不再认证,而直接按照转发规则进行转发(因为反向代理的ip加到了postfix的mynetworks中,见后文)。这两种不同的差异应该是跟协议有关。
为了保持统一,在本文的方案中,auth.php集成了pop3/imap/smtp的三种认证。这样的功能架构类似于游戏服务器的,登录服务器和游戏服务器是分开的。

4.在邮件服务器postfix/etc/main.cf中,修改mynetworks值,加入本反向代理的ip,并重载postfix:postfix -s reload

关于xclient:xclient的作用,是将前端的服务器模拟作为一个邮件客户端,而向后端的postfix进行认证和执行发送,但是postfix还需要一个打patch才能完美支持xclient。
关于此问题的讨论可以参见 http://forum.nginx.org/read.php?2,173197,173246#msg-173246

auth.php:

<?php
/**
* @see xiabaibai.net
*/
if(!isset($_SERVER ["HTTP_AUTH_USER"] ) || ! isset($_SERVER ["HTTP_AUTH_PASS"] )) {
    fail(0);
}
$username = $_SERVER ["HTTP_AUTH_USER"];
$userpass = $_SERVER ["HTTP_AUTH_PASS"];
$protocol = $_SERVER ["HTTP_AUTH_PROTOCOL"];

$backend_port = 110;
if($protocol == "imap") {
    $backend_port = 143;
} elseif ($protocol == "smtp") {
    $backend_port = 25;
}

list($uid, $domain) = explode("@", $username);

$auth = authuser($username, $userpass);
if(!$auth) fail (-2);

pass($_SERVER["SERVER_ADDR"], $backend_port);

//自定义认证,sql查询或者api
function authuser($user, $pass) {
    return true;
}

function fail($code) {
    switch($code){
        case 0: header("Auth-Status: Parameter lost"); break;
        case -1: header("Auth-Status: No Back-end Server"); break;
        case -2: header("Auth-Status: Invalid login or password" ); break;
    }
    exit();
}

function pass($server, $port) {
    header("Auth-Status: OK" );
    header("Auth-Server: $server" );
    header("Auth-Port: $port" );
    exit();
}
 
?>

声明: 本文采用 BY-NC-SA 协议进行授权. 转载请注明转自: 基于nginx的pop3/imap/smtp的反向代理解决方案
  1. 丰禾 | #1
    2011年9月25日11:39

    wao!!!! it very  difcaufl.  i`cont

  2. 北边 | #2
    2011年12月28日10:36

    我是菜鸟,我也在用nginx做邮件代理,有几个问题想请教你
    1,假设邮件服务器的地址是192.168.1.11  , 我想在地址是192.168.1.22的服务器上配置nginx去做1.11的邮件代理,实现远程通过登陆192.168.1.22去用192.168.1.11的邮件服务,是不是就按照你上面的例子来做呢?
    2.,auth.php代码可以放在192.168.1.22上么?
    3,您提到,如果认证脚本不做认证,可以直接把nginx.conf中“auth_http  指定IP:80/auth.php;”这条语句删掉吗?
    谢啦~~

  3. godsad | #3
    2012年1月13日14:16

    Thx very much! 交个朋友吧,我留的邮箱就是我qq.博主新年快乐

  1. 本文目前尚无任何 trackbacks 和 pingbacks.

*
点击收听验证码
点击收听验证码