先看一眼你的 SSH 日志,如果服务器已经开了一段时间:
grep "Failed password" /var/log/auth.log | wc -l
如果数字超过几百甚至几千,说明你的服务器正在被持续扫描和爆破。这是互联网的背景噪音,不是针对你,全球有大量自动化 botnet 在持续扫描所有公网 IP 的常见端口——22(SSH)、3306(MySQL)、6379(Redis)、2375(Docker API)——一旦发现开放就尝试弱密码或已知漏洞。
问题不是"会不会被扫",而是"被扫到之后有没有防线"。
零信任的核心思路
零信任(Zero Trust)这个词听起来复杂,核心逻辑很简单:不信任任何来自公网的连接,除非经过明确验证。传统做法是"在边界建防火墙,进来就信任",零信任是"每一层都要验证,永远不默认信任"。
落到 VPS 上,实际意味着:减少暴露在公网的服务,用私有网络取代公开端口,用身份验证取代 IP 白名单。下面按步骤来。
第一步:加固 SSH,减少暴力破解噪音
SSH 是第一个要处理的目标。编辑 /etc/ssh/sshd_config:
# 禁止 root 直接登录
PermitRootLogin no
# 禁止密码登录,只允许密钥
PasswordAuthentication no
PubkeyAuthentication yes
# 禁止空密码
PermitEmptyPasswords no
# 只允许特定用户
AllowUsers yourusername
# 修改默认端口(降低日志噪音,不是本质安全)
Port 2222
改完重启 SSH:
sudo systemctl restart sshd
注意:修改端口之前先确认新端口防火墙已放行,否则会把自己锁在外面。换端口只是减少扫描日志的噪音,不能阻止有针对性的攻击——不要把它当成核心安全手段。
如果还没有 SSH 密钥,生成一对:
ssh-keygen -t ed25519 -C "your_comment"
把公钥复制到服务器:
ssh-copy-id -i ~/.ssh/id_ed25519.pub \
user@your_server_ip
第二步:把管理流量迁移到私有网络
这是零信任思路的核心一步:不要把管理端口暴露在公网,用私有隧道来管理服务器。有三个主要选项:
Tailscale(推荐入门)
Tailscale 基于 WireGuard,把你的设备组成一个私有网络,每台设备之间可以直接通信,不需要开公网端口。个人用户免费,配置极简单。
# 安装 Tailscale
curl -fsSL https://tailscale.com/install.sh | sh
# 启动并登录
sudo tailscale up
登录后你的服务器会得到一个私有 IP(通常是 100.x.x.x 段)。之后可以通过这个私有 IP 访问服务器,完全不需要开放公网的 22 端口。
在防火墙里把 22 端口的公网访问关掉,只保留 Tailscale 网卡的访问:
# 只允许从 Tailscale 网段访问 SSH
sudo ufw allow in on tailscale0 to any port 22
sudo ufw deny 22
Cloudflare Tunnel(适合 Web 服务)
如果你有需要对外提供的 Web 服务,Cloudflare Tunnel 可以让服务不暴露真实 IP,所有流量通过 Cloudflare 的网络进来,完全免费。
# 安装 cloudflared
wget -q https://github.com/cloudflare/cloudflared/releases/latest/\
download/cloudflared-linux-amd64.deb
sudo dpkg -i cloudflared-linux-amd64.deb
# 登录 Cloudflare 账户
cloudflared tunnel login
# 创建隧道
cloudflared tunnel create my-tunnel
# 配置路由(编辑 ~/.cloudflared/config.yml)
# tunnel: <your-tunnel-id>
# credentials-file: /root/.cloudflared/<id>.json
# ingress:
# - hostname: app.yourdomain.com
# service: http://localhost:8080
# - service: http_status:404
# 启动隧道
cloudflared tunnel run my-tunnel
有了 Tunnel 之后,80 和 443 端口可以关掉——流量从 Cloudflare 进来,不需要直接开放。
WireGuard(适合自托管 VPN)
WireGuard 是自己搭建私有 VPN 的方案,比 Tailscale 更灵活,配置也更复杂。适合需要完全自控的场景。
# 安装 WireGuard
sudo apt install wireguard -y
# 生成密钥对
wg genkey | tee /etc/wireguard/privatekey \
| wg pubkey > /etc/wireguard/publickey
# 查看公钥
cat /etc/wireguard/publickey
WireGuard 的完整配置涉及服务端和客户端两侧,篇幅较长,建议参考官方文档或专门的 WireGuard 教程。
第三步:防火墙默认拒绝
防火墙策略的基本原则:默认拒绝所有入站,只开放明确需要的端口。
# 安装 UFW
sudo apt install ufw -y
# 默认策略:拒绝入站,允许出站
sudo ufw default deny incoming
sudo ufw default allow outgoing
# 允许 SSH(如果还需要公网访问的话)
sudo ufw allow 2222/tcp
# 允许 HTTP 和 HTTPS
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# 启用防火墙
sudo ufw enable
# 查看规则
sudo ufw status verbose
如果你已经用 Tailscale 管理 SSH,22 或 2222 端口的公网规则可以不加,只开 80 和 443。
几个容易被遗忘的危险端口,确认它们没有暴露在公网:
# 检查哪些端口在监听
ss -tlnp
看到 3306(MySQL)、6379(Redis)、5432(PostgreSQL)、2375(Docker API)绑定在 0.0.0.0 上,意味着它们对全网开放,需要立即处理——改成只监听 127.0.0.1 或者私有网段。
第四步:用 CrowdSec 替代 Fail2Ban
Fail2Ban 是老牌工具,逻辑是检测到多次失败后封 IP。CrowdSec 的逻辑更进一步:它有一个共享的威胁情报网络,当一个 IP 在全球 CrowdSec 用户的服务器上被标记为恶意,你的服务器也会自动封禁它,不需要等它来攻击你才反应。
# 安装 CrowdSec
curl -s https://install.crowdsec.net | sudo bash
sudo apt install crowdsec -y
# 安装 UFW 拦截器
sudo apt install crowdsec-firewall-bouncer-iptables -y
# 查看实时告警
sudo cscli alerts list
# 查看被封禁的 IP
sudo cscli decisions list
安装完成后 CrowdSec 会自动解析 SSH、Nginx、系统日志,发现异常行为后通过 bouncer 自动下发封禁规则到防火墙。
如果你习惯 Fail2Ban 也可以继续用,两者不冲突,但 CrowdSec 的社区情报共享是它更有价值的地方。
第五步:不要暴露服务管理端口
几个高危配置,逐一检查:
Redis
Redis 默认没有密码,而且经常绑定在 0.0.0.0。编辑 /etc/redis/redis.conf:
# 只监听本地
bind 127.0.0.1
# 设置密码
requirepass your_strong_password
# 禁用危险命令
rename-command FLUSHALL ""
rename-command CONFIG ""
rename-command KEYS ""
MySQL / PostgreSQL
同样,确保只监听 127.0.0.1,不要开放 3306 或 5432 的公网访问。如果应用和数据库在同一台服务器,根本不需要开公网端口。
Docker API
这是最危险的一个。如果 Docker API 暴露在公网(2375 端口),攻击者可以完全控制你的容器环境,甚至逃逸到宿主机。检查:
# 确认 Docker 没有监听公网
ss -tlnp | grep 2375
如果有输出,立即处理。Docker 的默认 Unix socket(/var/run/docker.sock)只允许本地访问,不要开 TCP 监听,除非你知道自己在做什么。
第六步:Docker 安全部署
如果你在跑 Docker 容器,几个基本原则:
容器不要用 root 用户运行。在 Dockerfile 里加:
RUN useradd -m appuser
USER appuser
网络隔离,不同服务放不同 Docker 网络,不需要互相通信的容器不要放同一个网络:
# 创建独立网络
docker network create --internal backend-net
# 容器只加入需要的网络
docker run --network backend-net your-image
不要把 Docker socket 挂载给容器,除非这个容器确实需要管理其他容器。挂载 socket 等于给容器宿主机 root 权限。
敏感信息用 Docker Secrets 或环境变量文件管理,不要写死在镜像或 docker-compose.yml 里。
第七步:监控和告警
安全配置做完,还需要知道系统在发生什么。几个低成本方案:
Uptime Kuma 是自托管的服务监控工具,可以监控网站、端口、SSL 证书,支持多种告警方式(Telegram、邮件、Slack):
docker run -d \
--name uptime-kuma \
-p 3001:3001 \
-v uptime-kuma:/app/data \
louislam/uptime-kuma:1
Netdata 提供实时的系统资源监控,安装简单,资源占用低:
bash <(curl -Ss https://my-netdata.io/kickstart.sh)
定期检查 CrowdSec 的告警日志,了解什么类型的攻击在针对你的服务器,有助于进一步调整防护策略。
常见错误清单
几个我见过被反复踩到的坑:
所有服务绑定 0.0.0.0。这是最常见的问题,Redis、MySQL、各种管理界面全部对公网开放,攻击面极大。
忽略系统更新。已知漏洞的利用是自动化的,不更新系统等于把门开着。设置自动安全更新:
sudo apt install unattended-upgrades -y
sudo dpkg-reconfigure unattended-upgrades
以为换 SSH 端口就安全了。端口扫描会扫全段,改端口只是减少日志噪音,不是安全措施。不备份。安全事件发生后,能快速恢复比阻止入侵更重要。备份是最后一道防线。
安全配置检查清单
配置完成后逐项确认:
[ ] SSH 禁止密码登录,只用密钥
[ ] 禁止 root 直接 SSH 登录
[ ] UFW 默认拒绝入站,只开必要端口
[ ] Tailscale 或 WireGuard 用于管理访问
[ ] Cloudflare Tunnel 用于 Web 服务(如需)
[ ] CrowdSec 已安装并运行
[ ] Redis 绑定 127.0.0.1,设置密码
[ ] MySQL/PostgreSQL 不暴露公网
[ ] Docker API 未开 TCP 监听
[ ] 容器不以 root 用户运行
[ ] 系统自动安全更新已开启
[ ] 监控告警已配置
[ ] 定期备份已设置
关于预算
上面提到的所有工具——Tailscale 个人版、Cloudflare Tunnel、CrowdSec、UFW、Uptime Kuma——全部免费或有完整的免费层。这套配置不需要额外花钱,只需要时间。$5 的 VPS 配上这套安全配置,攻击面比很多没做过加固的企业服务器还小。安全不是预算的函数,是配置的函数。