前言
在与第三方系统进行接口开发时,需要不断的改进和测试,以常见的微信登录支付和 Alipay 支付和登录为例. 相对来讲 Alipay 做起来容易一些, 一是接口 SDK 封装的简单一些,对老接口也相对友好, 文档的岐义少. 微信就不那么容易了. 出于安全的考虑,微信的商户 ID 授权回调和支付回调只允许后台配置的一个地址, 看上去可以加, 但在我有限的经验里,加了也不管用. 有时间吐槽,不如花时间想其他办法搞定. 借助于万能的 nginx 反向代理功能, 我们就把测试的和正式环境的配置通一个域名地址,但不同参数的方式搞定了.
使用场景 - 微信的测试
假设你和一个正式服务器,如 bixuebihui.com, 还有一个测试用的,dev.bixuebihui.com, 正式的微信回调路径是 https://bixuebihui.com/pay, 测试的路径是 https://dev.bixuebihui.com/other/pay 微信后台绑定的是前一个路径,但你想对自己的代码按后一个路径做测试,该怎么做 nginx 的配置呢?
闲话少说,上代码,啊不,配置:
servername bixuebihui.com;
location /pay {
proxy_connect_timeout 3;
proxy_read_timeout 30;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect / /;
add_header X-Upstream $upstream_addr;
proxy_set_header Host $arg_domain;
if ($arg_domain ~ "dev\.bixuebihui\.com" ){
proxy_pass https://your.private.dev.ip;
rewrite /pay/(.*) /other/pay/$1 break;
break;
}
proxy_pass http://your_super_cluster;
}
说明:
-
proxy_pass https://your.private.dev.ip;
这里要用 ip 比较好,因为 Host 是用 domain 控制的,如果也用 domain 会有安全问题。 - "https://xxxx.weixin.qq.com/xxxapi?redirect_uri=https%3A%2F%2Fbixuebihui.com%2Fpay%3Fdomain%3Dhttps%253A%252F%252Fdev.bixuebihui.com%252Fother%252Fpay&other_params=xxxxxx " 传给微信的参数进行 url 转义, 其中 domain 参数是可以被微信原样返回,这样就可以按你自己的需求完成反向代理了。
路径改写与域名的处理
上面的例子中,实际向服务器发起的请求,根据参数不同,可能被改写,也可能不会
如访问 bixuebihui.com/pay/abc.do 最终实际请求发送给http://your_super_cluster/pay/abc.do
, 且 Host 参数为bixuebihui.com
, 如果 your_super_cluster上 有多个虚拟主机, 将会访问到主机头为 bixuebihui.com 的一个或默认的.
如访问的是 bixuebihui.com/pay/abc.do?domain=dev.bixuebihui.com
则最终请求会发给https://your.private.dev.ip/other/pay/abc.do?domain=dev.bixuebihui.com
,且 Host 参数为 $arg_domain 的值,即 dev.bixuebihui.com
.
如何处理 https
nginx 支持对 https 的代理, 如果你的应用服务器与 nginx 在一个子网内,建议直接在 nginx 上配置 https, 后端采用 http 协议, 这样应用服务器的压力会小很多.
配置 https 协议现在有很多免费证书可用. 最方便的要数 certbot, 在这个网站上连注册都不需要, 就可以为你的域名获得证书, 自动支持对 nginx 和 apache 等常见 web 服务器进行自动配置, 完全傻瓜化使用. 一分钟搞定真不是吹的. 2018 年 4 月左右将推出对通配二级域名的支持.到时候会更加方便. 真是良心网站.
参数与 redirect
如果你的网站有 302 这类的跳转,这时反向代理要设置成
proxy_redirect / /;
否则后端服务器有可能返回内网跳转路径给浏览器, 造成无法访问.
nginx配置正确性测试
对生产环境的修改前先要备份
最好对现有的可能运行的配置文件做备份,有两种办法,一是用版本管理系统,如git ,参考这里,另一种方式是自己写脚本来管理备份。
下面是我的备份脚本,供参考, 路径要改成你自己的,这个脚本是以日期为扩展名,如果你同一天需要多个备份请修改脚本,别掉坑里。
nginx_config_backup.sh
###################################################################
#######nginx_config_backup###################################################
#!/bin/sh
# -----------------------------
# the directory for story your backup file.
backup_dir="/home/yourname/backup"
# date format for backup file (dd-mm-yyyy)
time="$(date +"%Y%m%d")"
MKDIR="$(which mkdir)"
RM="$(which rm)"
MV="$(which mv)"
TAR="$(which tar)"
GZIP="$(which gzip)"
#针对不同系统,如果环境变量都有。可以去掉
# check the directory for store backup is writable
test ! -w $backup_dir && echo "Error: $backup_dir is un-writeable." && exit 0
# the directory for story the newest backup
test ! -d "$backup_dir" && $MKDIR "$backup_dir"
$TAR -zcPf $backup_dir/$HOSTNAME.nginx.$time.tar.gz /etc/nginx
#delete the oldest backup 30 days ago
find $backup_dir -name "*.gz" -mtime +30 |xargs rm -rf
exit 0;
搭建测试环境
另一条运维的原则是:不要在生产环境上直接改,在测试环境修改并经过测试,测试通过后,再上传到生产环境。
安装扩展包
$ sudo apt-get install nginx-extras
这样你就可以使用 Lua, echo 这些方便调试的工具了。
echo使用很简单
在location 配置块内:
echo hello world;
echo_flush;
详细说明看这里echo.
如果你是一个网管,代码是别人写的,且写得很烂,怎么办?为了能睡个安稳觉,你可安装 nginx-naxsi 版本, "Nginx Anti Xss & Sql Injection". 损失一点效率,带来的是更安全。不过这个版本在新的(15.04以后的)ubuntu里已经不再提供更新了。需要话可能需要自已单独设置安装源。
修改了 nginx 的配置文件, 一定要先测试再重启
nginx -t && service nginx reload
或
sudo service nginx configtest && sudo service nginx reload
debug 可以输出更多信息
server {
#other config
error_log /var/logs/nginx/example.com.error.log;
location /admin/ {
error_log /var/logs/nginx/admin-error.log debug;
}
#other config
}
如果你的站长访问量很大,这么做你的磁盘很快会被耗光, 也可以设置成只针对特定 IP 写 debug 信息
events {
debug_connection 1.2.3.4;
}
这里 1.2.3.4 是你要调试的 ip 地址,
想要获得自己的外网 ip,有一个网站很好用
curl http://httpbin.org/ip
这个网站上还有很多其他用来调试http协议应用的api接口. 简单易用.
总结
nginx很强大, 详细掌握nginx的用法能帮你少写很多代码, 维护一个更健康的网站.
如果有人感兴趣, 下次可以讨论一下nginx安全方面的应用, 防抓取, 防攻击等等.