前一阵某朋友想要做个海外站,问我如何打造一个安全的WordPress网站,于是我看了很多资料,也拿一个新域名练手尝试了一下,算是有点收获,所以写篇文章记录一下。
先说下网站被攻击打垮的最基本原因,就是你的服务器IP被对方知晓了,那剩下的事情就简单了,对着你的IP一阵流量输出就行。
你可能会问,对方咋知道这些信息的?其实网上的公开工具非常多,例如这个Censys网站会扫描整个互联网的IP数据。
所以呢?网站防护最基础的一条,就是隐藏好自己的源站IP。
如何做到?用CDN呗,我们请出大善人Cloudflare。需要说明的是,这个方案更多适合部署在国外服务器、面向国外访客的网站,因为CF在国内的访问速度不太理想。也不是说没有办法区分国内外线路解析,国内环境另外加速访问啥的,就整体方案都挺复杂的,所以我重点考虑安全因素就行,其他因素优先级不高。
1 买VPS服务器
由于我的方案是使用1Panel面板,所以建议VPS规格至少为1C2G,或者更高,尤其是内存,如果你的服务器会装比较多应用,内存可以适当大一些。
我给我那朋友买了台RackNerd美国服务器,选DC02区的,配置还行,大家也可以参考下。
这里顺便提一句,在使用Cloudflare建站的这类方案中,源站服务器的线路倒是不用太关注,你可以把关注点放在服务器硬件性能上。因为Cloudflare CDN网络是全球分布的,理论上你的源站服务器放在哪里关系不大。
2 安装1Panel面板
服务器系统的话我个人推荐用最新版Debian 12。
1Panel安装过程请参考官方手册 https://1panel.cn/docs/。
如果是新手,建议全部默认配置安装即可。
提示:1Panel 集成了两种广泛使用的 Linux 防火墙软件(Firewalld 和 UFW),请根据你的服务器操作系统,在装完面板后进行相应的配置。关注重点是如果你修改了SSH默认端口22为其他数字(一般我都会改成高位端口),记得先添加防火墙规则后再启动防火墙,免得把自己给挡住了;同样道理,记得在防火墙中放行1Panel自己的后台端口(系统端口)。
3 在1Panel上建一个自签证书假域名作为默认站点
类似宝塔、1Panel这些面板,都有一个“默认站点”的功能,主要是为了防止IP被人恶意解析,原理就是,别人如果恶意解析你的IP,将会直接跳转到你的默认站点,而你,可以事先挖坑,把“默认站点”弄成一个不存在的网站,或者警告页面,这样别人的意图就无法得逞了(一般别人恶意解析都是为了做镜像站,抢你的流量)。
在1Panel后台创建一个静态网站,域名可以搞一个不存在的假域名,也可以直接写www.google.com等大站的域名。
在1Panel后台证书维护页面,用上传证书方式来创建一份自签证书,网上有很多在线服务可以生成测试用途SSL证书,从这些地方获取就行了,例如这个。
为该假网站配置HTTPS,选择刚才自签的假证书。
然后将这个自签证书的假网站设置为1Panel默认站点。
这样一来,即便是那些全网扫描程序,扫到你的IP直接访问,也只会访问到一个假网站,且证书也是假的,不会暴露你的真实域名。
4 注册域名
建议直接在Cloudflare注册就行,或者你在其他域名商注册后,将域名DNS解析改为由CF管理。
5 在Cloudflare完成域名解析并开启代理(小黄云)
关键点:千万不要在其他域名注册商那里提前将你的域名和IP直接解析绑定,不然会被某些全网扫描程序记录到,那就功亏一篑了。
完成这一步后,如果你试着去ping一下你的域名(https://ping.pe/),你会发现,返回的IP已经不是你的真实服务器IP了,而是Cloudflare的节点IP。
从菜单SSL/TLS > Overview进入,为CF的加密模式选择 Full (strict),此操作可以避免重定向问题。此模式下,必须在源站安装证书,详见后续章节描述。
从菜单SSL/TLS > Edge Certificates进入,开启 Always Use HTTPS。
6 从1Panel应用商店安装WordPress
前提:先从商店安装OpenResty(这玩意类似nginx)、MySQL、PHP 8
在商店找到并安装WordPress即可,用默认配置。
在1Panel后台创建一个网站,使用“一键部署”方式,选择“已装应用”,也就是前面从应用商店安装的WordPress程序,填好自己的域名,确认即可。
此时,你还无法直接在浏览器上输入你的域名来启动WP的安装,为啥?
因为前面的环节,你已经配置了CF代理保护域名,需要从CF获取证书在你的源服务器上安装,这样你的源服务器和CF之间才能正常加密通讯。
7 从Cloudflare获取源站证书
入口为CF后台SSL/TLS > Origin Server。
创建一个证书,选择有效期为15年。
将创建生成的两个证书Origin Certificate和Private Key文本都复制保存一份备用。
8 在1Panel安装CF证书
路径:网站>证书>上传证书。
导入方式为粘贴代码。
将前置步骤从CF获取的两份秘钥文本,分别粘贴到输入框,点击确认保存。
在1Panel后台网站列表中,打开你目标网站的配置界面,选择启用HTTPS,SSL选项是“选择已有证书”,选刚刚上传成功的CF证书。
9 启动WordPress在线安装
总算可以正式安装WordPress了,直接浏览器输入你的域名,回车即可。
详细的WordPress安装步骤我就不在本文赘述了,装过的都懂,没装过的Google一下,也很简单的。
10 源站服务器只允许Cloudflare白名单IP访问
虽然前面环节已经将域名通过CF代理方式保护起来了,用户不太可能通过域名访问来获取你的服务器IP地址。但,谁知道呢?道高一尺魔高一丈,搞不好会有其他可能,别人通过其他途径得到你的IP和域名的绑定关系。
咋办?继续强化保护吧。从服务器IP访问来源下手,设置白名单,只允许Cloudflare他们家的IP来源,才能访问你的源服务器IP。
这里咱们借助1Panel的免费WAF功能来实现我们想要的效果,WAF是基于应用层的防火墙,和传统(网络)防火墙的区别可以参考下图(出自此处):
1Panel开启WAF功能入口:1Panel后台>高级功能>WAF>全局设置>右上角开关。
- 重要提醒
- 建议你创造至少2个固定IP访问环境,举例,长期维护两台国外服务器用来出国访问,IP地址不变(所以不要使用那些共享IP的出国服务,因为他们IP地址会经常调整的)。然后将这些固定IP设置为WAF的白名单,意思是不受此防火墙规则限制,免得一个不小心把自己也给挡在大门外就尴尬了。
- 注意,一般人的家庭宽带住宅IP地址不是固定,不太适合作为白名单配置。
- WAF黑白名单逻辑
- 白名单:名单内IP不受任何规则限制
- 黑名单:名单内IP无法访问本服务器
- 优先级逻辑:白名单规则优先于黑名单
- 白名单设置
- 把自己固定用来访问服务器(后台)和网站域名的几个IP填写进去
- 把Cloudflare CDN官方IP地址范围填写进白名单(更巧妙的方式是,使用WAF的IP组功能,然后在白名单选中这个IP组,方便后续动态维护)
- Cloudflare官方的IP段几乎不怎么变动,实在不放心你可以一年检查一次
- 黑名单设置
- 创建一个类型为“IPV4范围”的名单,起始IP写 0.0.0.0,结束IP写 255.255.255.255
- 最终效果说明
- 根据以上黑白名单配置,以及优先级逻辑说明可知,我们先建了个规则将全网IPV4拉黑,然后只允许白名单内的IP访问我们的服务器
- 冲突规避说明
- 根据1Panel官方在社区论坛的帖子,WAF的黑白名单规则,不要和WAF的CDN功能同时用,也就是本文场景中,保持WAF CDN为关闭状态
以上介绍的这种黑白名单结合的机制是非常有效的,前面提过那个全网扫描的Censys网站,有人想把它的IP地址列入黑名单,其实是治标不治本,因为并不仅仅只有这家网站在整天扫描。我们这里只给Cloudflare家的IP开门,其他一律禁止。
11 1Panel启用CDN后如何查看真实访客IP
前面一整套组合拳打下来,如果你去1Panel后台查看网站访问日志会发现,来源IP全都是Cloudflare家的IP。
这是正常现象,毕竟访客的流量是经过CF网络传递后,通过CF的IP才能访问到你的源站。
但问题是,我们如果想要获得访客原始IP该咋办呢?例如我自建了一个umami统计服务,如果我不做任何处理,默认umami只会统计到CF的IP信息,那就少了很多有效的访问数据了。
办法当然是有的,那就是修改这台服务器的nginx配置,加参数,让原始日志能够同时记录真实访客IP和Cloudflare的IP。
我们去1Panel后台打开nginx配置:网站>(顶部)OpenResty > 设置 > 配置修改
找到log_format字样区域,将原本那一行代码改为如下(出自此处):
log_format main 'CDN_IP:$remote_addr - CLIENT_IP:$HTTP_X_FORWARDED_FOR - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent"';
保存以上修改结果。
在当前页面顶部,点击重启一次OpenResty。
去1Panel后台 > 日志审计 > 网站日志 看一下最新访问日志(没有的话就开一个浏览器刷新一下你的网站),看看是不是有区分出CDN_IP和CLIENT_IP?后者就是真实的访客IP。
12 Fail2Ban到底需不需要配合CDN调整获取真实访客IP?
很多人安装VPS系统后必做的事情之一就是安装Fail2Ban,用于防止被暴力扫描端口攻击(短时间内多次访问失败即可自动封禁IP)。
前面一整套Cloudflare CDN防护措施做完后,有人就担心了,那Fail2Ban怎么办?万一我封禁的都是CF的IP而不是真实访客IP,那岂不是没用了?
然后就有很多人出了各种教程,教你如何修改Fail2Ban配置,配合前一个步骤修改nginx识别真实访客IP的动作,让Fail2Ban也能达到类似效果。
我也是研究了好一阵,结合OpenAI,得到了以下结论:Fail2Ban保持原状即可,无需任何修改。
理由如下:
- CF是防护Web端流量访问的,而Fail2Ban是防护TCP方式访问的(也就是说,后者是别人直接通过IP+端口发起访问,例如SSH访问)
- 理论上,经过CF防护后,别人不可能知道域名和IP的关联关系
- 那么,即便有人拿到IP地址,他也确实能通过直接IP+端口方式来访问(攻击);此时呢?Fail2Ban自然是能够默认获得原始访客IP地址并自动封禁的
既然提到Fail2Ban,这里顺便说个小坑,那就是Debian 12及以上版本需要手动安装rsyslog,不然你直接装Fail2Ban会失败的,详见此处说明。
13 这样就一劳永逸了?
并不是。
源站IP被泄露的方式千奇百怪,以上只是将最常见的漏洞给堵住了。
限于本文篇幅,我没办法穷尽所有场景。这里再列举一个潜在的风险点:服务器SMTP发送邮件会暴露IP。解决办法?单独用另外一台服务器搭建邮局,不要用网站所在的服务器直接发邮件;或者使用专业、安全的第三方邮件API服务(请自行做调研,并非所有企业邮局服务都能保护源站IP)。
另外就是,WordPress有很多插件可以用,但尽量别装太多,要装也只从官网装,且需要经常关注相关的安全资讯,以防某些插件被黑客盯上造成信息泄露。
14 结束语
写到这里,我都感觉挺累的了。确实,对于一个非计算机科班出身的人来说,简单装个WordPress可能不算太难,但是要搞以上这么多服务器配置,就挺难的了。
尤其是,之前国内比较盛行用宝塔面板,而我用的是1Panel面板,很多网上教程没办法直接抄(毕竟1Panel还出道不久,功能上没有老前辈强大)。
还有就是,Cloudflare准确来说是面向开发者和企业的,不太适合小白个人用户,学习理解和使用的门槛比较高。你会发现,针对同一个Cloudflare功能,网上说法那是各执一词,好多时候我不得不多看几篇文章,然后对比下OpenAI给的答案,自己再判断哪个才是对的哪个是错的,真难。