前言

最近逛论坛的时候发现大家的网站都是被打过的,我就没被打

但为了保证网站的在线率,提前假定自己被ddos的情况。未雨绸缪总是好的

方法

js css资源cdn替换

针对我自己的网站来说,我是静态hexo,没有数据库,没必要去保护自己的接口

但还是有优化的空间,比如js,css等资源可以使用国内的公共cdn

以我的主题Butterfly为例子

注意这里如果需要修改mainjs和maincss的话需要选择和主题对应版本号的js和css,或者你自己传到自己的对象存储中填写对应的链接

把需要用到的包通过国内cdn加速

就不要用什么jsdelivr.net什么的了,访问速度很慢,反向加速

可以看到优化后的速度很快,基本都是200ms以下的加载

具体请看别人写的目前可用 cdnjs, unpkg/npm, jsdelivr 国内镜像(前端文件镜像)

网站吞吐量

静态页面的吞吐量跟网络, 4k硬盘io息息相关,如果用的是和中国互联很差的如github page, cloudflare page(cloudflare其实还好点), vercel(有些地区被阻断了有的时候很卡),就优先换线路,或者直接备案域名找个国内存储桶托管(具体可以看3. 迁移halo到hexo,并部署到七牛云作静态资源博客

但我已经放弃了国内备案,这种做法就不适合我了

于是只能转而提升硬盘io,我测了一下我的serverless的硬盘4k只有惨淡的4MB/s

想要改善只能换服务器了,但转念一想得益于静态页面的资源很小,其实可以把静态资源全放到内存里永久缓存就行了

目前我找到的支持内存缓存的页面服务器是带插件的caddy,即cache-handler,但是需要手动编译,这里给出Dockerfile

FROM golang:1.23-alpine AS builder

RUN go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest

RUN xcaddy build \
--with github.com/caddyserver/cache-handler \
--with github.com/darkweak/storages/badger/caddy
# 使用badger
FROM alpine:3.18

RUN apk add --no-cache ca-certificates

COPY --from=builder /go/caddy /usr/bin/caddy

RUN addgroup -S caddy && adduser -S caddy -G caddy

WORKDIR /srv

EXPOSE 8090

USER caddy

CMD ["caddy", "run", "--config", "/etc/caddy/Caddyfile", "--adapter", "caddyfile"]

docker build . -t twoonefour/caddy打包镜像即可开箱即用了

接下来是配置文件,根据cache-handler文档

{
cache {
ttl 999999999s
mode bypass_request
badger {
configuration {
InMemory true # 这里很坑,根据文档是要填写ValueDir或path其中一个的。不要填ValueDir和path, 不然无法启用
}
}
}
}

:8090 {
cache
header -Vary
header -Server
header -Alt-Svc
header -cache-control

handle /css/* {
reverse_proxy http://hexo.zeabur.internal:8080 {
header_up Host {host}
header_up X-Real-IP {remote}
}
}
handle /js/* {
reverse_proxy http://hexo.zeabur.internal:8080 {
header_up Host {host}
header_up X-Real-IP {remote}
}
}
# 默认路由
handle {
reverse_proxy http://hexo.zeabur.internal:8080 {
header_up Host {host}
header_up X-Real-IP {remote}
}
}
}

请求一下显示hit和badger即可

为了排除延迟干扰,直接使用香港服务器请求网页,如下图,延迟只有1.19ms

并排除dns解析干扰

cat “43.199.8.212 www.voidval.com“ >> /etc/hosts

使用命令

curl -o /dev/null -s -w %{time_total}”\n” “https://www.voidval.com/css/index.css

虽然只提升了20ms, 但如果面对磁盘性能瓶颈时候会有很大的提升(理论上

这样即便遇到ddos攻击,磁盘io也不会爆满导致网站无法访问(多半会先网络瓶颈就是了)

图片优化

hexo使用懒加载即可,还可以让图片在上传时自动压缩为webp

nginx配置单个链接

接下来nginx开启限制单个ip并发限制5个链接

# http块添加(/etc/nginx/nginx.conf内)
limit_conn_zone $binary_remote_addr zone=addr:10m;
# server块添加, 单个ip限制5个最大连接数
limit_conn addr 5;
limit_conn_log_level error;

fail2ban

注意,如果你使用cdn,就不要使用这个,用iptables过滤cdn ip就行了

安装

apt install fail2ban -y

配置

cat << EOF >> /etc/nginx/conf.d/fallback.conf
[nginx-conn-limit]
enabled = true
filter = nginx-conn-limit
port = http,https
logpath = /var/log/nginx/error.log
maxretry = 1
bantime = 3600
EOF
cat << EOF >> /etc/fail2ban/filter.d/nginx-conn-limit.conf
[Definition]
failregex = limiting connections by zone "addr", client: <HOST>
ignoreregex =
EOF

这里要对应nginx上面的addr zone和error logpath

Cloudflare WAF

使用cloudflare waf过滤一部分风险流量
在博客访问来源不属于cn时触发验证码(Managed Challenge)

爬虫跳过验证

可以看到能挡掉大部分来自外面的恶意攻击

iptables拒绝除了来自cf的ip

若你使用cdn,直接将cf cdn的来源加入白名单,其他流量拒绝即可

wget https://www.cloudflare.com/ips-v4 -O cf.zone
apt install ipset
ipset -N cf hash:net
for i in $(cat cf.zone); do ipset -A cf $i; done
iptables -A INPUT -p tcp -m set --dport=443 --match-set cf src -j ACCEPT
iptables -A INPUT -p tcp -m tcp --dport=443 -j DROP

但我暂时不用cdn,因为线路比较好不舍得用

保护重要的端口只允许特定地址访问(如中国)

同上类似

wget https://github.com/Hackl0us/GeoIP2-CN/raw/release/CN-ip-cidr.txt
apt install ipset
ipset -N cn hash:net
for i in $(cat CN-ip-cidr.txt); do ipset -A cn $i; done
iptables -A INPUT -p tcp -m set --dport=1688 --match-set cn src -j ACCEPT
iptables -A INPUT -p tcp -m tcp --dport=1688 -j DROP

dns切换(最终方法)

被打了直接解析切到gov可以爆杀ddos

没办法的办法,切解析

这里还是教切解析吧

准备一个备用服务器 -> cron定时curl 检测网站是否在规定时间内返回200 -> 若不是则切换解析到备用服务器

#/bin/bash
# 五秒内不返回内容则切换解析,否则退出
curl -Ls --max-time 5 https://www.voidval.com > /dev/null && exit 0

# 切换解析的命令(自查

切换解析的命令可以参考这里

加钱上ip防护的服务器

没钱,我直接跳过

linux内核调参

SYN Cookies

sysctl -w net.ipv4.tcp_syncookies=1
sysctl -p

其他的自行探索

压测网站

使用go-stress-test压测

这里先关掉了fail2ban和nginx链接限制测试ddos(因为这里只有一个ip只能算dos)

48线程并发测试结果如下

root@localhost:~/go-stress-testing# go run main.go -c $(nproc) -n 60 -u https://www.voidval.com

开始启动 并发数:48 请求数:60 请求参数:
request:
form:http
url:https://www.voidval.com
method:GET
headers:map[Content-Type:application/x-www-form-urlencoded; charset=utf-8]
data:
verify:statusCode
timeout:30s
debug:false
http2.0:false
keepalive:false
maxCon:1


─────┬───────┬───────┬───────┬────────┬────────┬────────┬────────┬────────┬────────┬────────
耗时│ 并发数│ 成功数│ 失败数│ qps │最长耗时│最短耗时│平均耗时│下载字节│字节每秒│ 状态码
─────┼───────┼───────┼───────┼────────┼────────┼────────┼────────┼────────┼────────┼────────
114s│ 48│ 2854│ 26│ 34.49│30001.36│ 246.37│ 1391.76│74,255,372│ 649,126│200:2854;509:26


************************* 结果 stat ****************************
处理协程数量: 48
请求总数(并发数*请求数 -c * -n): 2880 总请求时间: 114.393 秒 successNum: 2854 failureNum: 26
tp90: 1403.000
tp95: 4372.000
tp99: 16871.000
************************* 结果 end ****************************

cpu很容易就占满了

tp99为1200ms,qps为34,还是cpu瓶颈了,但此时网站还是能访问的,最终结果还能接受吧QAQ,毕竟服务器就一个单核洋垃圾E5-2696,不卡死宕机就算成功

syn flood测试

主机cpu甚至没有波动直接被ban了

ending

到这里优化就差不多了,其实静态页面没什么好d的_(:з)∠)_,毕竟d也要花钱