本文介绍基于nginx的邮局反向代理配置方案。nginx对来源于客户端的pop3/smtp/imap请求予以转发到后端postfix,后端邮件服务器采用postfix,已配置并正常运行。
本方案参考 Using a php script on apache server as the auth backend ,并基于此方案进行改进,并增加了对smtp的代理。
环境配置:centos 5.5 + nginx 1.0.4
软件安装:
1 2 3 4 5 6 7 8 |
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
#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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
<?php 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(); } ?> |
最近通过搜索访问本文章的关键词:
- nginx mail proxy (10)
- فایل tcookieid (10)