重装只是开始:把公网服务器从裸奔状态拉回来
重装之后的第一件事不是装软件
系统重装完,ssh root@ip 一通,密码进去——这一步就已经错了。
上一台机器出事,本质就是「密码可以被人猜」。所以这次第一件事是:把密码登录这条路彻底关掉,改成密钥。
SSH 换密钥
本地生成一对 ed25519(比 RSA 短、比 RSA 快、强度还更高):
ssh-keygen -t ed25519 -f ~/.ssh/cyk_server -N "" |
把公钥追加到服务器的 ~/.ssh/authorized_keys,权限必须是这套:
chmod 700 ~/.ssh |
然后写一份加固配置,放在 sshd_config.d/ 下(注意文件名要排在云厂商的默认配置前面,因为 sshd 是「先读到的生效」):
PasswordAuthentication no |
prohibit-password 的意思不是「允许 root 用密码」,而是「root 只能用密钥」——等于把 root 远程登录变相禁掉了。
改完先 sshd -t 验证语法,再 reload。验证前不要关当前窗口,不然配错了就真的进不去了。
现在登录长这样:
ssh cyk-server |
.ssh/config 里配好别名,不用记 IP、不用带 -i。
端口从 12 个砍到 3 个
老机器上开了一堆端口:MySQL、Redis、Nacos、MinIO 控制台……每个都是当年「临时测一下」留下的。
新机器只留:
| 端口 | 用途 |
|---|---|
| 22 | SSH |
| 80 | HTTP(301 跳 HTTPS) |
| 443 | HTTPS |
图床的 9000 和 9090 全部改成只监听 127.0.0.1,需要的时候用 SSH 隧道临时打开:
ssh -L 9000:127.0.0.1:9000 -L 9090:127.0.0.1:9090 ubuntu@ip -N |
隧道比开放端口好在:它要求先有 SSH 密钥。开端口是「对全世界开一扇门」,隧道是「拿着钥匙才给你开」。
fail2ban
老机器被打了 4466 次,一次告警都没有。这次装上:
apt install fail2ban |
默认策略是「10 分钟内失败 5 次封 10 分钟」——10 分钟太短了,换个时间再来就跟没封一样。改成封一天:
# /etc/fail2ban/jail.local |
有个副作用要记住:自己输错 5 次也会被封一天。被 DROP 掉的表现是「连接超时」而不是「拒绝连接」,很容易误判成网络问题。解封:
fail2ban-client set sshd unbanip 你的IP |
服务不再直接对外
图床(MinIO)收到内网,对外只通过 nginx 反代一个路径:
location ^~ /cykblog/ { |
这里有个坑:前缀 location 必须写 ^~。否则下面那条「静态资源后缀」的正则 location 会优先匹配,把 /cykblog/xxx.webp 当成磁盘文件去找,直接 404。
文件管理(FileBrowser)也收到内网,但因为它有网页界面、还要长期对外,所以在 nginx 前面又加了一道 Basic Auth:
location ^~ /files/ { |
密码文件用 openssl 直接生成,不用额外装包:
printf 'user:%s\n' "$(openssl passwd -apr1 '你的密码')" > /etc/nginx/.htpasswd |
现在访问 /files/ 是两层:先进 nginx 的认证,再进 FileBrowser 自己的登录页。这套软件官方已经停止维护了,多一层能挡住「拿已知漏洞直接打」的自动化扫描。
证书
Let’s Encrypt,certbot 自动续期,90 天一轮。装完确认一下定时任务在:
systemctl list-timers | grep certbot |
一个反直觉的点
加固做完之后,日常使用几乎没有变麻烦:
- SSH 还是敲一句,只是不用输密码了
- 图床上传还是拖文件,只是先开个隧道(或者用 PicGo 配好一次)
- 网页访问完全没区别
真正变麻烦的只有一件事:换新设备的时候要加一次公钥。三十秒的事。
反过来想,那台老机器省下的这三十秒,代价是两周的 root 权限在别人手里。
