10

前言

在与第三方系统进行接口开发时,需要不断的改进和测试,以常见的微信登录支付和 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安全方面的应用, 防抓取, 防攻击等等.


Yujiaao
12.7k 声望4.7k 粉丝

[链接]