如何搭建一个树洞
0 开始搭建树洞之前
如果你在看这篇文章,可能或多或少你对搭建树洞有着一定的兴趣。因此,首先需要强调的是:搭建并运营一个树洞是一个工作量巨大并且难度很高的事情。树洞的运营是一个一定需要一支团队才可以胜任的任务,并且这个团队至少需要有以下几点能力:
- 技术:搭建树洞、树洞功能更新时都需要技术能力
- 网络安全:树洞的隐私保护是重中之重,也是树洞用户非常关心的问题
- 日常管理:团队中最好需要管理员7/24值班管理树洞,管理员还需要有极高的舆情处理能力,同时看得懂各种黑话
- 法务:日常管理中遇到的各种问题都可能需要法务帮忙
在你想要开始搭建树洞之前,请确保你身边有一群你们相互信任的伙伴,你们的合力可以覆盖上面几点能力。
1 对技术人员的要求
树洞的技术栈目前已经较为复杂,后端使用的是Linux+Nginx+MySQL+Redis+Go;Web前端使用的是React;Android前端主要是Kotlin;iOS前端是SwiftUI。如果要完成树洞后端的搭建,技术人员至少需要掌握:
- Linux的基本使用方法和常用bash命令,比如vim、top、ps、tmux
- 基础网络协议知识,如HTTP协议等
- 基础的密码学知识,至少需要可以看懂https://github.com/treehollow/treehollow-v3-encryption-doc
- 熟悉git、cron
如果你掌握了这些基础,那么请继续往下看吧!搭建树洞至少需要1天的时间,请保持耐心。
2 选择一个云服务器提供商和操作系统
树洞的后端需要运行在一个有公网IP的服务器中,至少需要1核2G内存,最好2核4G内存或以上。市面上现在有很多服务器提供商,国外大厂商有Amazon AWS、Google Cloud、Microsoft Azure等,小厂商有Digitalocean、Vultr、Linode等,国内知名的有阿里云、腾讯云、华为云等。它们之间的对比如下表:
备案 | 价格 | 网络速度 | |
---|---|---|---|
国外大厂商 | 不需要 | 比较贵 | 晚上国际出口可能很慢 |
国外小厂商 | 不需要 | 比较便宜 | 晚上国际出口可能很慢 |
国内厂商 | 需要 | 很贵 | 快 |
选择完厂商之后,就选择一个操作系统吧,对于服务器来说,操作系统最重要的特性就是稳定。因此,我们推荐CentOS 7,它的官方支持将在2024年6月才结束。
3 注册一个域名
注册域名实在是太简单了,网上的教程很多。这里需要强调一下安全问题
⚠ 必须采取的安全措施】:请务必确保时刻没有子域名DNS解析到服务器真实IP,并且服务器真实IP必须始终保密!
【服务器的IP如果泄露,DDoS等情况就有可能发生,同时还会极大地增加攻击面。因此,服务器的HTTP流量必须始终通过CDN(比如Cloudflare CDN)。在https://securitytrails.com/dns-trails 网站上,一个域名的全部子域名和DNS历史记录都可以轻松查到,因此不能有任何时刻让服务器真实IP暴露在外。
【建议的安全措施】:请使用堡垒机登录ssh
堡垒机可以减少一定的攻击面,对服务器安全是很有益的。如果树洞运营团队有条件,请使用堡垒机。
4 在服务器上搭建后端
第一步:设置时区为Asia/Shanghai
sudo timedatectl set-timezone Asia/Shanghai
请相信,这会节省很多麻烦的
第二步(可选):安装swap空间
有swap空间可以让服务器在内存吃紧的时候有着更好的表现。如果你的服务器硬盘是SSD的,那么swap会消耗SSD寿命;不过如果你是租的服务器,谁会在意寿命呢:)
参考教程:https://www.digitalocean.com/community/tutorials/how-to-add-swap-on-centos-7
第三步:安装并配置Nginx,同时配置firewalld或iptables防火墙
参考教程:https://www.digitalocean.com/community/tutorials/how-to-install-nginx-on-centos-7
【⚠必须采取的安全措施】:请务必配置好iptables或firewalld或使用服务器提供商的安全组功能,仅允许CDN流量访问80/443端口
否则,攻击者可以通过全网扫描的方式获取服务器的真实IP,参考:https://cloud.tencent.com/developer/article/1079482
如果你使用的是基于iptables的防火墙,那么我们在此提供一个示例脚本,你可以使用以下脚本方便地添加Cloudflare的节点进入iptables白名单:
#!/bin/bash
iptables -F
ipset destroy cf4
ipset create cf4 hash:net
for x in $(curl https://www.cloudflare.com/ips-v4); do ipset add cf4 $x; done
iptables -A INPUT -m set --match-set cf4 src -p tcp -m multiport --dports 80,443 -j ACCEPT
iptables -A INPUT -p tcp -m multiport --dports 80,443 -j DROP
iptables-save
这个脚本要求ipset已经被安装。如果你看不懂这段脚本在干什么,请先搜索学习相关知识之后,再进行后续步骤。
第四步:安装并配置MySQL 8.0,Redis,Go
参考教程:
https://www.mysqltutorial.org/install-mysql-centos/
https://www.digitalocean.com/community/tutorials/how-to-install-secure-redis-centos-7
https://golang.org/doc/install
【注意】:MySQL的中文搜索引擎分词在默认情况下有bug,请参考treehollow/treehollow-backend#43 解决
第五步(可选):安装并配置Nginx amplify
Nginx Amplify是一个可以监控服务器健康状态的免费平台,详细介绍和安装方法请见https://amplify.nginx.com/
第六步:注册Google reCAPTCHA
请到https://developers.google.com/recaptcha/intro 分别注册一个reCAPTCHA v3和reCAPTCHA v2 Checkbox,未来将会在后端和前端配置文件中用到
第七步:购买或搭建一个SMTP邮件发送服务器
国外有mailgun和sendgrid,国内有阿里云,也可以自己搭建(可能会很难),具体做法请你根据自身情况搜索
第八步:配置Nginx
本文假设读者已经对Nginx配置文件的结构和用法已经有了基本的了解,下面只介绍几个重点。
重点1:如何让Nginx在CDN后面获取IP
由于服务器只和CDN边缘节点进行网络通信,获取客户IP时就会有难度。还好,几乎所有CDN都会在HTTP的X-Forwarded-For header中转发客户IP。请参考:https://support.cloudflare.com/hc/en-us/articles/200170986-How-does-Cloudflare-handle-HTTP-Request-headers-
但是我们不能完全信任X-Forwarded-For的结果,因为如果攻击者构造一个含X-Forwarded-For的包,就可以达到IP欺骗的效果。为此,Nginx的比较新的版本里都带一个叫ngx_http_realip_module的模块,只要将CDN的IP列表添加进Nginx信任的列表里,就可以正确解析出客户IP。参考:https://cloud.tencent.com/developer/article/1521273
我们在此提供一个脚本,以Cloudflare CDN为例,生成Nginx所需要的配置文件:
#!/bin/bash
echo "# generated by updateNginxWhitelist.sh" > /etc/nginx/whitelist.conf
echo "# Cloudflare IPs" >> /etc/nginx/whitelist.conf
for x in $(curl https://www.cloudflare.com/ips-v4); do echo "set_real_ip_from $x;" >> /etc/nginx/whitelist.conf; done
echo >> /etc/nginx/whitelist.conf
echo "real_ip_header X-Forwarded-For;" >> /etc/nginx/whitelist.conf
echo "real_ip_recursive on;" >> /etc/nginx/whitelist.conf
nginx -t
nginx -s reload
运行此脚本前,在nginx.conf
中加入include whitelist.conf;
就可以了。如果你看不懂这段脚本在干什么,请先搜索学习相关知识之后,再进行后续步骤。
重点2:如何让Go程序在Nginx后面获取IP
以T大树洞API的/v3/security
块为例,Nginx配置文件会类似:
...
location /v3/security {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_pass http://unix:/somewhere/treehollow-security-api.sock;
error_page 502 = @fallback;
}
...
location @fallback {
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' 'https://web.thuhole.com';
add_header 'Access-Control-Allow-Headers' 'TOKEN';
add_header 'Content-Length' 0;
return 204;
}
proxy_pass http://unix:/somewhere/treehollow-fallback.sock;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
add_header Access-Control-Allow-Origin "https://web.thuhole.com";
}
...
如果你看不懂这段配置大概在干什么,请先搜索学习相关知识之后,再进行后续步骤。
重点3:Nginx中Websocket的配置
树洞Android客户端的推送服务使用了Websocket协议的方式,Nginx处理Websocket时的配置应该类似这样:
...
server_name ws.thuhole.com;
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header X-Forwarded-Proto http;
proxy_redirect http:// $scheme://;
proxy_connect_timeout 3m;
proxy_send_timeout 3m;
proxy_read_timeout 3m;
proxy_pass http://unix:/somewhere/treehollow-push-api.sock;
}
...
这里如果看不懂没关系,后面会更仔细介绍T大树洞后端的结构
第九步:为树洞后端的运行环境添加新的用户
添加新的低权限Linux用户:
useradd -m username
添加新的MySQL数据库及用户:https://matomo.org/faq/how-to-install/faq_23484/
第十步(可选):下载GeoIP库
T大树洞使用GeoIP库进行风控等操作,这里你如果不知道用什么库,就用免费的Maxmind数据库:https://dev.maxmind.com/geoip/geoipupdate/
安装并运行geoipupdate,然后把geoipupdate放到crontab里
第十一步:下载、编译运行树洞后端代码
树洞后端代码位于https://github.com/treehollow/treehollow-backend
安装方式:git clone
下来之后,进入项目文件夹,然后运行:
go install ./...
这时会在$GOPATH/bin
生成几个可执行文件,有用的几个分别是:
treehollow-v3-push-api
: 用于处理Android和iOS消息推送服务的可执行程序
treehollow-v3-security-api
: 用于处理/v3/security
中所有API的可执行程序
treehollow-v3-services-api
: 用于处理/v3/
中security以外API的可执行程序
treehollow-v3-fallback
: 当服务更新时,用于向前端显示错误信息的可执行程序
将example.config.yml
复制到config.yml
之后修改参数即可运行。在生产环境中,这四个程序应该都在运行
⚠ 必须采取的安全措施】:配置SELinux
第十二步【SELinux也许是个讨厌的东西,但它对服务器安全至关重要。为了树洞服务的安全,树洞运营团队的技术人员应该花几个小时学习以下SELinux的使用。这里我们提供一些有用的资料:
实际用的时候其实基本就是用两次audit2allow:https://www.server-world.info/en/note?os=CentOS_7&p=selinux&f=9
(注:如果两次audit2allow不行,那就四次)
第十三步:检查各个域名的正常运行、配置前端的config
T大树洞前端代码位于:https://github.com/treehollow/webhole 配置环境变量之后通过GitHub Actions即可成功运行部署
Android和iOS客户端需要配置文件才能正常运行,请在这个模板下修改:https://github.com/treehollow/thuhole-config/blob/main/main.txt
在T大树洞的生产环境中,至少有8个域名会解析运行:
thuhole.com
: 主页www.thuhole.com
: 跳转到thuhole.com
tapi.thuhole.com
: 主要API都在这个域名ws.thuhole.com
: Android消息推送时的Websocket服务器re.thuhole.com
: 给app登录时显示reCAPTCHA界面的网页,参考https://github.com/treehollow/thuhole-recaptcha-v2/blob/main/recaptcha/index.htmli.thuhole.com
: 显示图片用的域名web.thuhole.com
: 网页版树洞terms.thuhole.com
: 用于放用户协议、隐私政策、树洞规范
把这些服务一个个上线是费时费力的事情,但是生产环境毕竟就是需要这么多服务。