长亭雷池WAF是一款国产的WAF软件,有免费的社区版本,最近总是看到有人提起,都说这个WAF挺好用的,搞的我心里痒痒的,老想着部署一个试试。。
WG-Easy是一个WireGuard的Web UI,使用WG-Easy可以非常方便的安装和管理WireGuard VPN。
简单说一下为什么要这样搭配使用。。
由于我把长亭雷池WAF部署在单独的服务器上,这个WAF的主要工作原理就是通过反向代理来实现的,如果直接反代源站服务器的公网IP+端口是可以用,但这不就等于把源站IP暴露了嘛,为了保护源站IP不被泄露,我想了个办法就是用WireGuard把部署WAF的这台服务器与源站所在服务器建立一个VPN,然后源站的NGINX只监听在VPN的IP上,WAF这边配置反代VPN的IP+端口即可。
当然保护源站IP不被泄露的方法不止这一种,比如还可以配置源站服务器的防火墙仅允许WAF服务器访问,等等。你可以选择一个合适自己的方案。但说句实话,真要保证源站IP不漏,其实还挺难的,如果你的域名曾经解析过源站IP,这其实大概率就已经漏了,即便现在你做了这些操作,别人扫DNS记录就能扫出来。。还有诸如censys这类网站也是每天全世界到处爬网站证书信息。。
另外刚才说了这个WAF的主要工作原理就是通过反向代理来实现的,即便你不需要它提供的WAF功能,也可以把它当个反向代理的面板来使用,可以说是NPM(Nginx Proxy Manager)等一众软件的绝佳替代品了。(不过现在社区版好像限制只能添加50个站点了)
我已经部署折腾好了,下面记录一下步骤。。
首先部署WG-Easy,我把WG-Easy部署在WAF所在的机器上。安装Docker:
apt -y update apt -y install curl curl -fsSL https://get.docker.com -o get-docker.sh sh get-docker.sh
新建compose文件:
mkdir -p /opt/wg-easy && cd /opt/wg-easy && nano docker-compose.yml
我的配置如下:
volumes: etc_wireguard: services: wg-easy: image: ghcr.io/wg-easy/wg-easy container_name: wg-easy environment: - LANG=chs - WG_HOST=your-server-public-ip - PASSWORD_HASH=$$2b$$12$$coPqCsPtcFO.Ab99xylBNOW4.Iu7OOA2/ZIboHN6/oyxca3MWo7fW - PORT=51821 - WG_PORT=51820 - WG_DEFAULT_ADDRESS=10.8.0.x - WG_ALLOWED_IPS=10.8.0.0/24 volumes: - etc_wireguard:/etc/wireguard ports: - "51820:51820/udp" - "51821:51821/tcp" restart: unless-stopped cap_add: - NET_ADMIN - SYS_MODULE sysctls: - net.ipv4.ip_forward=1 - net.ipv4.conf.all.src_valid_mark=1
有几个非常关键的配置特别说明一下:
1、WG_HOST一定要配置为服务器的公网IP。
2、WG_ALLOWED_IPS务必配置成VPN IP所在网段,WG-Easy在默认情况下会配置成0.0.0.0/0,这样启动会导致服务器直接断网,因为0.0.0.0/0是接管机器所有的流量,这对于有公网IP的服务器来说是致命的,并且我们也不需要它接管所有流量。
3、PASSWORD_HASH需要配置成bcrypt加密后的密码,假设你要设置的密码为:YOUR_PASSWORD,可以使用下面的命令生成:
docker run -it ghcr.io/wg-easy/wg-easy wgpw YOUR_PASSWORD
回显为:
PASSWORD_HASH='$2b$12$coPqCsPtcFO.Ab99xylBNOW4.Iu7OOA2/ZIboHN6/oyxca3MWo7fW'
在配置到compose的环境变量中时,需要去掉单引号,并且将每个$符号替换成两个$$符号:
$$2b$$12$$coPqCsPtcFO.Ab99xylBNOW4.Iu7OOA2/ZIboHN6/oyxca3MWo7fW
启动WG-Easy:
docker compose up -d
WG-Easy的Web UI在51821端口上可用,登录进去后,新建客户端:
将客户端配置文件下载下来,里面的内容类似于:
[Interface] PrivateKey = hidden Address = 10.8.0.2/24 DNS = 1.1.1.1 [Peer] PublicKey = hidden PresharedKey = hidden AllowedIPs = 10.8.0.0/24 PersistentKeepalive = 0 Endpoint = hidden:51820
请确保AllowedIPs是VPN所在的网段,Endpoint是服务器的公网IP。
接着登录到源站服务器,安装WireGuard:
apt -y update apt -y install wireguard
新建WireGuard客户端配置文件:
nano /etc/wireguard/wg0.conf
将刚才的客户端配置文件内容写入到wg0.conf内:
[Interface] PrivateKey = hidden Address = 10.8.0.2/24 DNS = 1.1.1.1 [Peer] PublicKey = hidden PresharedKey = hidden AllowedIPs = 10.8.0.0/24 PersistentKeepalive = 0 Endpoint = hidden:51820
启动:
systemctl start wg-quick@wg0
使用wg命令检查连接状态:
此时会有一个问题,现在源站服务器是能PING通WAF服务器,但是WAF服务器是PING不通源站服务器的。其实这并不是什么错误,而是预期的行为。
因为WAF服务器上运行的WG-Easy使用的网络是Docker的桥接模式,这就导致WAF服务器里面的WG-Easy容器是能PING通源站服务器的,但WAF服务器主机自身是PING不通的。
要解决这个问题,其实有多种办法,根据这个页面里面的说明,你可以将compose的网络改为host模式,或者仅开放特定端口,但我个人觉得这两方法都不太好。
我个人觉得的最优解是直接把WAF服务器主机也加入到WireGuard网络中,也就是把WAF服务器主机也配置成一个WireGuard客户端。
所以接下来我们需要回到WG-Easy的Web UI,再新建一个客户端,把客户端配置文件下载下来:
然后在部署WG-Easy的这台WAF服务器主机上同样也安装WireGuard:
apt -y update apt -y install wireguard
新建WireGuard客户端配置文件:
nano /etc/wireguard/wg0.conf
将刚才的客户端配置文件内容写入到wg0.conf内:
[Interface] PrivateKey = hidden Address = 10.8.0.3/24 DNS = 1.1.1.1 [Peer] PublicKey = hidden PresharedKey = hidden AllowedIPs = 10.8.0.0/24 PersistentKeepalive = 0 Endpoint = hidden:51820
启动:
systemctl start wg-quick@wg0
这样源站服务器和WAF服务器双方都能互相PING通了,源站服务器的IP是10.8.0.2,WAF服务器的IP就是10.8.0.3,而WG-Easy所在的容器内VPN IP则是10.8.0.1,简单测试一下:
至此,两台服务器的VPN算是建立完成了。别忘了在两台服务器内设置开机自启:
systemctl enable wg-quick@wg0
接下来在WG-Easy所在的这台WAF服务器上部署长亭雷池WAF,准备目录下载compose文件:
mkdir -p /opt/safeline && cd /opt/safeline wget https://waf.chaitin.com/release/latest/compose.yaml
新建.env配置文件:
nano .env
写入如下内容,注意修改dbpassword:
SAFELINE_DIR=/opt/safeline IMAGE_TAG=latest MGT_PORT=9443 POSTGRES_PASSWORD=dbpassword SUBNET_PREFIX=172.22.222 IMAGE_PREFIX=chaitin
启动:
docker compose up -d
现在长亭雷池WAF的Web UI在9443端口可用,但我们不知道管理员的账号和密码,执行下面的命令获取:
docker exec safeline-mgt resetadmin
至此长亭雷池WAF就安装完成了,在继续配置WAF之前,我们需要先把源站的NGINX配置进行修改以适配WAF。
这边我打算使用WAF保护两个站点:Chevereto、WordPress。需要修改的内容有:
1、修改NGINX监听的IP地址为VPN IP。
2、修改站点运行的端口,Chevereto运行在50000端口,WordPress运行在50001端口,
3、删除有关HTTPS的配置内容,直接用HTTP。
4、源站NGINX具有http_realip_module模块,用于获取客户端真实IP。(Debian11、12官方源里面安装的NGINX自带这个模块不需要自己编译)
编辑源站NGINX的vhost(Chevereto)配置文件:
nano /etc/nginx/sites-available/chevereto
示例配置:
server { listen 10.8.0.2:50000; server_name img.xxoo.zip; root /var/www/chevereto; index index.html index.htm index.php; client_max_body_size 100M; set_real_ip_from 0.0.0.0/0; real_ip_header X-Forwarded-For; # Disable access to sensitive application files location ~* (app|content|lib)/.*\.(po|php|lock|sql)$ { return 404; } location ~* composer\.json|composer\.lock|.gitignore$ { return 404; } location ~* /\.ht { return 404; } # Image not found replacement location ~* \.(jpe?g|png|gif|webp)$ { log_not_found off; error_page 404 /content/images/system/default/404.gif; } # CORS header (avoids font rendering issues) location ~* \.(ttf|ttc|otf|eot|woff|woff2|font.css|css|js)$ { add_header Access-Control-Allow-Origin "*"; } # PHP front controller location / { index index.php; try_files $uri $uri/ /index.php$is_args$query_string; } # Single PHP-entrypoint (disables direct access to .php files) location ~* \.php$ { internal; include snippets/fastcgi-php.conf; fastcgi_pass unix:/var/run/php/php7.4-fpm.sock; } }
编辑源站NGINX的vhost(WordPress)配置文件:
nano /etc/nginx/sites-available/wordpress
示例配置:
server { listen 10.8.0.2:50001; server_name lala.im; root /var/www/wordpress; index index.html index.htm index.php; client_max_body_size 100M; set_real_ip_from 0.0.0.0/0; real_ip_header X-Forwarded-For; location / { try_files $uri $uri/ /index.php?$args; } location ~ \.php$ { include snippets/fastcgi-php.conf; fastcgi_pass unix:/var/run/php/php7.4-fpm.sock; } }
重启NGINX:
systemctl restart nginx
在源站NGINX的配置上面我走了很多弯路,尤其是关于WordPress的配置,一开始我直接去掉了server_name,想着反代也用不上,但是后来发现WordPress依赖这个来生成邮件发信人地址,没有这个会导致WordPress评论邮件通知出错或者评论超时。具体问题见此页面,但这个只影响旧版本,新版的WordPress已经不使用server_name了。
另外由于我使用了Really Simple SSL插件来修复WordPress混合内容,这个插件会导致301重定向循环,我一直忘了这茬,导致我进不去后台了。要解决的话就是先停用这个插件,等反代配置好之后再启用。但问题是现在我已经进不去后台怎么停用呢?此时我想到了用WP-CLI。
安装WP-CLI:
curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar chmod +x wp-cli.phar mv wp-cli.phar /usr/local/bin/wp
找到插件名,然后停用:
sudo -u www-data wp --path=/var/www/wordpress plugin list sudo -u www-data wp --path=/var/www/wordpress plugin deactivate really-simple-ssl
至此源站这快的配置就OK了。现在登录到长亭雷池WAF的Web UI,继续配置WAF。(以下步骤仅演示WordPress站点,Chevereto站点的配置步骤与此相同就省略掉了)
首先在全局配置这里,启用如下图所示的这些功能:
申请SSL证书,申请前把域名DNS解析到WAF服务器所在IP:
申请SSL证书可以一次性填写多个域名:
现在就可以添加站点了,这是我添加的三个站点:
我博客的域名是带www的跳转到不带www的,所以添加第一个站点的时候只绑定不带www的域名:
再额外添加一个站点,这个站点绑定带www的域名,并且设置为301重定向:
反之如果你是不带www的域名要跳转到带www的域名,也是可以这样操作的。至此就大功告成了,咱也是用上WAF的人了,233
补充点后续使用过程中遇到的问题,主要是误报,Chevereto这程序还好,WordPress在编写文章的时候,如果文章的内容有些敏感就可能会触发WAF的误报:
好在长亭雷池WAF有一个Customized rules的功能,在这里添加白名单规则即可:
虽然长亭雷池WAF有误报,但比ModSecurity的误报率还是要低的多。。ModSecurity简直就是一个噩梦。。
另外现在国产的WAF产品里面,除了长亭以外,还有南墙WEB应用防火墙(uuWAF)、宝塔WAF等等,可选择的空间还是很大的。
最后八卦一下。。我发现长亭的股权结构,阿里是大股东哦= =
可能是我没看明白,这种最终是不是还要解析域名到你得waf服务器地址? 另外 组内网tailsclae也能搞定(用起来实在太方便了),当然 docker自带swarm应该也是可以的
域名肯定解析到WAF服务器地址啊,不然用户怎么访问网站= =,WAF服务器的地址暴露就暴露了无所谓的,WAF的作用就是清洗流量和过滤用户行为的,类似于正常流量放行,恶意流量阻止掉这种操作。如果把WAF部署在高防服务器上面,比如OVH这种自带防御的机器,这样就更坚固了。
两台服务器组VPN的目的就是让流量只能通过WAF服务器进入,如果用源站IP+端口就能访问后端的话等于是直接绕过WAF了,那WAF不就失效了嘛。
不过你也可以在WAF服务器前面套一个CDN,比如CloudFlare,那这样的话相当于反代两次,有点套娃的意思了。。但是也有应用场景,比如WAF服务器线路不行,用CDN可以加速访问。
然后lala的长亭部署在阿里云上吗,这就来给你刷流量试试
你好坏,把我一套房刷没了
大佬。怎么能联系上你,想付费请教一些问题,有TG吗