本文主要就实现前言中的要求2进一步展开说明。
实现的思路是利用前端服务器(即中间服务器)反向代理客户端的应用请求,并将请求转发到实际部署应用的后端应用服务器,对于同一台机器而言(假设应用实际部署在2367端口),在默认情况下前端相当于监听该机器80端口的虚拟服务器(本文使用Apache),后端相当于监听2367端口的虚拟服务器(本文使用Nginx).
对于Nginx和Apache的区别:
- Nginx高度模块化设计,编写配置简单,处理静态文件速度高于Apache,内存占用较少,同时并发性较好(异步非阻塞型),适合做前端服务器
- Apache非常稳定,动态页面处理能力高,模块非常丰富,rewrite性能强大
因此对于单独选择其中一种web服务器来构建项目时,如果追求项目性能,可以使用Nginx;相对的如果追求稳定性以及更多配置选项,建议使用Apache。对于两者结合使用来说,Nginx更适合作为前端来担任负载均衡和反向代理,将Apache用作后端服务器来处理动态请求。本文是在现有配置的基础(Apache监听80端口)并且不方便修改配置的情况下,用Apache作为前端反向代理,并不盲目推荐仿造该做法,应根据实际情况进行调整。
构建过程
具体构建过程如下图所示:
左边的绿框表示基于Apache构建的反向代理服务器,右边的粉框表示基于Nginx构建的应用服务器。反向代理服务器除了基础的反向代理配置以外,还加了一层ip过滤,用来阻止校园网以外ip(因为对于我的需求来说,应用的受访对象是学校研究室)的访问;应用服务器上除了配置应用以外还增加了一个登录认证的环节(用户名密码)来过滤研究室成员以外的访问。Apache和Nginx间添加了个白名单,使得应用服务器只能接受来自反向代理服务器的请求(这样外部即使探测到应用的地址也无法直接访问)。
反向代理
Apache的配置如下:
# Include module configuration:
IncludeOptional mods-enabled/*.load
IncludeOptional mods-enabled/*.conf
# Include list of ports to listen on
Include ports.conf
#NameVirtualHost *:443
<VirtualHost *:443>
ServerName abc.example.com
ServerAlias abc.example.com
ProxyRequests Off
<Proxy "*">
Require ip yyy.yyy.yyy.yyy/zz
</Proxy>
ProxyPass / http://xxx.xxx.xxx.xxx:2367/
ProxyPassReverse / http://xxx.xxx.xxx.xxx:2367
SSLCertificateFile "/path/to/your/sslcert/fullchain.pem"
SSLCertificateKeyFile "/path/to/your/sslcert/privkey.pem"
</VirtualHost>
其中要注意的是,Apache的反向代理功能是需要手动开启的。首先需要向apache.conf
里导入mod_proxy
,mod_proxy_http.so
,mod_proxy_connect.so
这三个模块。如果你是FreeBSD,你只需要在httpd.conf
上把注释取消掉,并重启服务后就可以了;但如果你使用的是Ubuntu,与sites-available
和sites-enabled
的使用方法相同,mods-available
是所有模块的存储目录,但是服务载入的模块是存储在mods-enabled
的。
这一点通过apache.conf
的以下几行可以证实:
# Include module configuration:
IncludeOptional mods-enabled/*.load
IncludeOptional mods-enabled/*.conf
当apache服务运行时,只载入mods-enabled
里面的模组,而部分模组在安装时预设是不会加载的。(即该模组不会出现在mods-enabled
)
Apache给我们提供了a2enmod
指令帮助我们快速添加模块,相对的停用模块使用a2dismod
命令:
admin@ubuntu:~$ sudo a2enmod proxy proxy_http proxy_connect # 启用模块
admin@ubuntu:~$ sudo a2dismod proxy proxy_http proxy_connect # 停用模块
启用之后,指定的模块会以软链接的形式被放进mods-enabled
中,重启服务生效。
添加模块之后,需要在apache.conf
中添加如下行即可启用反向代理功能。
ProxyRequests Off
添加如下行设置你的代理目标
ProxyPass / http://xxx.xxx.xxx.xxx:2367/
ProxyPassReverse / http://xxx.xxx.xxx.xxx:2367
添加ip白名单,你可以指定具体ip,也可以像我一样限定一个网段。
<Proxy "*">
Require ip yyy.yyy.yyy.yyy/zz
</Proxy>
添加https证书,关于代理服务器与应用服务器是否需要https这一点可以参考反向代理服务器代理HTTPS。
SSLCertificateFile "/path/to/your/sslcert/fullchain.pem"
SSLCertificateKeyFile "/path/to/your/sslcert/privkey.pem"
至此,反向代理服务器的配置到此为止。
应用服务器
Nginx的配置如下,笔者配置的是静态页面,php等动态应用请根据Nginx文档自行调整:
server {
listen 2367;
listen [::]:2367;
root /path/to/app;
# Add index.php to the list if you are using PHP
index index.html index.htm;
server_name _;
auth_basic "Please enter your username and password.";
auth_basic_user_file /path/to/your/htpasswd;
location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
try_files $uri $uri/ =404;
alias /path/of/your/app/;
index index.html;
}
}
以下开始说明。在/etc/nginx/sites-availble/
下以默认模板创建一个全新的配置文件,将其软链接到/etc/nginx/sites-enabled/
:
sudo touch /etc/nginx/sites-available/mysite.conf
sudo ln -s /etc/nginx/sites-available/mysite.conf /etc/nginx/sites-enabled/mysite.conf.enable
使用绝对路径,不然会报错。
应用的部署配置,根据你的实际情况进行编写。
登录验证我们通过nginx配置以及htpasswd工具实现。htpasswd是一款Apache内置的用户名密码生成工具,使用方法如下:
$ htpasswd -c /usr/local/nginx/password username
# 假如我们想将验证文件储存在/usr/local/nginx/下
# 文件名为password,登录用户名为username
# 回车后输入密码
# -c 创建加密文件
至此登录信息创建完毕,将验证信息写入网站配置文件中:
auth_basic "Please enter your username and password.";
auth_basic_user_file /usr/local/nginx/password;
实现效果如图所示:
该实现是一个最基本的验证功能,它有一个缺陷在于你无法设定登录过期时间,也就是说某台设备一次登录成功后它将一直保持登录成功状态,直到网站cache被使用者手动清除。
配置完成后,重启nginx服务器生效。
代理服务器与应用服务器之间添加白名单
这部分实现很简单粗暴,直接在应用服务器上(Nginx)过滤除代理服务器以外的所有请求即可,添加如下配置。
# Whitelist
allow zzz.zzz.zzz.zzz; # 反向代理服务器的地址
deny all;
allow关键字后跟的ip以外的请求会全部deny掉。
尾声
至此,全部实现的介绍完毕。