🛡️ 服务器加固

SSH key-only、UFW 防火墙、Fail2ban、自动安全更新——VPS 上线后的第一件事

🔑 SSH 加固

SSH 是你服务器的正门。默认配置是开着的门,任何人都可以尝试密码登录。加固 SSH 是服务器安全的第一步。

# 1. 生成 SSH 密钥(Ed25519,比 RSA 更安全更快) ssh-keygen -t ed25519 -C "your-email@example.com" # 2. 上传公钥到服务器 ssh-copy-id -i ~/.ssh/id_ed25519.pub root@your-server # 3. 修改 SSH 配置 # /etc/ssh/sshd_config # 禁用 root 密码登录 PermitRootLogin prohibit-password # 禁用密码登录(只允许密钥) PasswordAuthentication no PubkeyAuthentication yes # 禁用空密码 PermitEmptyPasswords no # 限制尝试次数 MaxAuthTries 3 # 登录超时 LoginGraceTime 30 # 限制用户(只允许特定用户登录) AllowUsers deploy root # 禁用不需要的认证方式 ChallengeResponseAuthentication no KerberosAuthentication no GSSAPIAuthentication no # 使用强加密算法 KexAlgorithms curve25519-sha256@libssh.org Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com # 日志 LogLevel VERBOSE # 应用配置 systemctl restart sshd # ⚠️ 重要:不要关闭当前 SSH 会话! # 开一个新窗口测试能否用密钥登录 # 如果登不上,还有旧会话可以修复

SSH 跳板机配置

# ~/.ssh/config — 本地配置 # 通过跳板机连接生产服务器 Host bastion HostName bastion.example.com User deploy IdentityFile ~/.ssh/id_ed25519 Host prod-* ProxyJump bastion User deploy IdentityFile ~/.ssh/id_ed25519 Host prod-app HostName 10.0.0.1 Host prod-db HostName 10.0.0.2 # 一条命令直连 ssh prod-app # 自动通过 bastion 跳转 # SSH Agent Forwarding(不要开!安全风险) # 如果需要在生产服务器上 git pull,用 Deploy Key 代替

🔥 UFW 防火墙

# UFW = Uncomplicated Firewall # 默认策略:拒绝所有入站,允许所有出站 # 1. 基本规则 ufw default deny incoming ufw default allow outgoing # 2. 允许 SSH(⚠️ 先加这条,否则会锁死自己!) ufw allow 22/tcp # 如果改了 SSH 端口: ufw allow 2222/tcp # 3. 允许 HTTP/HTTPS ufw allow 80/tcp ufw allow 443/tcp # 4. 限制来源 IP(推荐) # 只允许你的 IP 访问 SSH ufw allow from YOUR_IP to any port 22 # 5. 允许特定端口(如 Docker 直接暴露) ufw allow from 10.0.0.0/8 to any port 5432 # 内网 PostgreSQL # 6. 启用 ufw enable # 7. 查看规则 ufw status verbose # 常用操作 ufw delete allow 80/tcp # 删除规则 ufw insert 1 allow 22/tcp # 在第一条插入 ufw reload # 重载配置 # Docker + UFW 的坑 # Docker 默认会绕过 UFW 直接修改 iptables # 解决:在 /etc/docker/daemon.json 中禁用 iptables 操作 { "iptables": false } # 然后用 Traefik/Nginx 作为唯一入口

🚫 Fail2ban

# Fail2ban = 自动封禁暴力破解 IP # 安装 apt install fail2ban # 配置 # /etc/fail2ban/jail.local [DEFAULT] bantime = 3600 # 封禁 1 小时 findtime = 600 # 10 分钟内 maxretry = 3 # 3 次失败即封禁 destemail = you@example.com action = %(action_mwl)s # 封禁 + 发邮件 [sshd] enabled = true port = 22 filter = sshd logpath = /var/log/auth.log maxretry = 3 [nginx-http-auth] enabled = true port = 80,443 filter = nginx-http-auth logpath = /var/log/nginx/error.log [nginx-badbots] enabled = true port = 80,443 filter = nginx-badbots logpath = /var/log/nginx/access.log # 自定义规则:保护 API [api-rate-limit] enabled = true port = 80,443 filter = api-rate-limit logpath = /var/log/nginx/access.log maxretry = 100 findtime = 60 bantime = 600 # /etc/fail2ban/filter.d/api-rate-limit.conf [Definition] failregex = ^ .* "(GET|POST) /api/ .*" (429|503) .*$ ignoreregex = # 常用命令 fail2ban-client status # 查看所有 jail fail2ban-client status sshd # 查看 SSH jail 状态 fail2ban-client set sshd unbanip 1.2.3.4 # 解封 IP fail2ban-client reload # 重载配置

🔄 自动安全更新

# Ubuntu 自动安全更新 apt install unattended-upgrades apt-listchanges # /etc/apt/apt.conf.d/50unattended-upgrades Unattended-Upgrade::Allowed-Origins { "${distro_id}:${distro_codename}-security"; "${distro_id}ESMApps:${distro_codename}-apps-security"; "${distro_id}ESMInfrastructure:${distro_codename}-infrastructure-security"; }; # 自动清理旧内核 Unattended-Upgrade::Remove-Unused-Dependencies "true"; Unattended-Upgrade::Automatic-Reboot "false"; # 安全更新一般不需要重启 # 如果需要自动重启(内核更新后) Unattended-Upgrade::Automatic-Reboot "true"; Unattended-Upgrade::Automatic-Reboot-Time "03:00"; # /etc/apt/apt.conf.d/20auto-upgrades APT::Periodic::Update-Package-Lists "1"; APT::Periodic::Unattended-Upgrade "1"; APT::Periodic::Download-Upgradeable-Packages "1"; APT::Periodic::AutocleanInterval "7"; # 测试(dry-run) unattended-upgrade --dry-run --debug

📋 最小权限原则

# 最小权限 = 只给必要的权限,不多给 # 1. 创建专用用户(不要用 root 跑应用) useradd -m -s /bin/bash appuser # 2. 限制 sudo 权限 # /etc/sudoers.d/deploy deploy ALL=(ALL) /usr/bin/docker, /usr/bin/systemctl restart nginx # 只允许 docker 和 nginx restart # 3. 文件权限 chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys chmod 600 .env # 环境变量文件 chmod 600 *.pem # SSL 密钥 # 4. Docker 安全 # 不要把 Docker socket 暴露给非特权用户 # 使用 Docker Content Trust export DOCKER_CONTENT_TRUST=1 # 5. 数据库权限 # 应用用只读用户连接只读库 # 管理操作用管理员用户 GRANT SELECT, INSERT, UPDATE ON app_tables TO app_user; -- 不要给 app_user DELETE/DROP 权限 # 6. API Key 轮换 # 每 90 天轮换一次 # 使用 Vault 或 AWS Secrets Manager 存储 # 代码中不要硬编码密钥

✅ 安全检查清单

检查项状态命令
SSH 禁用密码登录grep PasswordAuthentication /etc/ssh/sshd_config
SSH 只允许密钥grep PubkeyAuthentication /etc/ssh/sshd_config
UFW 启用ufw status
Fail2ban 运行systemctl status fail2ban
自动安全更新systemctl status unattended-upgrades
非 root 用户运行应用ps aux | grep node
没有不必要的开放端口ss -tlnp
环境变量文件权限 600ls -la .env
Docker socket 不暴露find / -name "*.yml" -exec grep docker.sock {} \;
定期备份运行ls -la /backup/

💡 上线前 30 分钟安全清单

每次新 VPS 上线前做这些:① 创建 deploy 用户 + SSH 密钥 ② 禁用 root 密码登录 ③ 配置 UFW(只开 22/80/443)④ 安装 Fail2ban ⑤ 启用自动安全更新 ⑥ 安装 Docker ⑦ 配置日志轮转 ⑧ 设置备份 Cron。整个过程可以用 Ansible Playbook 自动化——一次配置,永远安全。

🔗 相关专题

⚙️ Ansible · 🔒 SSL & 域名 · 💾 备份恢复 · 🏗️ 返回首页