vps-security-hardening
VPS 安全加固 Skill
版本: 1.0.7 | 作者: github.com/wlzh | 参考: https://x.com/gxjdian/status/2033751314208059507
概述
本 Skill 用于自动化 VPS 安全加固流程,基于「7招安全加固」最佳实践,通过 SSH 远程执行一系列安全配置命令。
⚠️ 重要警告
在执行任何操作前,务必确保:
- VPS 平台防火墙已开放新的 SSH 端口 - 否则将被锁死无法登录!
- 如使用云服务商(AWS/阿里云/腾讯云等),需在安全组/防火墙规则中放行端口
- 建议先保持原 22 端口连接,新开一个终端测试新端口成功后再关闭 22
🔴 前置条件:开启 root 密码登录
如果 VPS 不支持 root 密码登录,必须先通过 VNC/控制台 开启!
很多云服务商(AWS、阿里云等)默认禁用 root 密码登录,只允许密钥登录。在运行此 Skill 前,需要先开启:
通过 VPS 平台控制台(VNC)执行以下命令:
# 1. 开启密码认证
sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication yes/' /etc/ssh/sshd_config
# 2. 开启 root 登录
sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin yes/' /etc/ssh/sshd_config
# 3. 重启 SSH 服务
systemctl restart ssh
# 4. 设置 root 密码(会提示输入两次)
passwd root
执行完成后,才能使用此 Skill 进行 SSH 登录和后续配置。
所需信息(执行时收集)
运行此 Skill 时,需要用户提供:
| 参数 | 说明 | 示例 |
|---|---|---|
VPS_IP |
VPS 的 IP 地址 | 192.168.1.100 |
ROOT_PASSWORD |
root 密码 | MyP@ssw0rd |
NEW_USER |
新建的 sudo 用户名 | admin |
NEW_USER_PASSWORD |
新用户密码 | UserP@ss123 |
SSH_PORT |
新的 SSH 端口 | 22222 |
执行流程
Phase 0: 环境检查
# 检查本地是否安装 sshpass(用于自动输入密码)
which sshpass || echo "需要安装 sshpass: brew install sshpass 或 apt install sshpass"
Phase 1: SSH 连接与系统检测
- 检测 root 密码登录是否开启
- 检测 Ubuntu 版本(影响 SSH 配置方式)
- 登录后执行系统更新
# 检测 Ubuntu 版本
lsb_release -a
# 更新系统
apt update && apt upgrade -y
# 检查必要工具
which ufw || apt install ufw -y
which sudo || apt install sudo -y
which fail2ban-client || apt install fail2ban -y
Ubuntu 版本与 SSH 配置方式:
| Ubuntu 版本 | SSH 配置方式 |
|---|---|
| 22.10, 23.04, 23.10 | socket 激活,需配置 /etc/systemd/system/ssh.socket.d/ |
| 24.04+ | 直接修改 /etc/ssh/sshd_config 或 sshd_config.d/ |
Phase 2: 创建 Sudo 用户(第一招)
# 创建用户
useradd -m -G sudo -s /bin/bash ${NEW_USER}
# 设置密码
echo "${NEW_USER}:${NEW_USER_PASSWORD}" | chpasswd
# 验证用户创建成功
id ${NEW_USER}
Phase 3: 配置 SSH 安全设置(第二招)
方式A:Ubuntu 24.04+ / 传统方式
创建专用配置文件 /etc/ssh/sshd_config.d/99-hardening.conf:
# VPS Security Hardening - generated by vps-security-hardening skill
# Author: github.com/wlzh
# Version: 1.0.0
Port ${SSH_PORT}
PermitRootLogin prohibit-password
PasswordAuthentication yes
PubkeyAuthentication yes
MaxAuthTries 3
ClientAliveInterval 300
ClientAliveCountMax 2
方式B:Ubuntu 22.10/23.04/23.10(socket 激活)
# 创建 socket 覆盖配置
mkdir -p /etc/systemd/system/ssh.socket.d
cat > /etc/systemd/system/ssh.socket.d/listen.conf << EOF
[Socket]
ListenStream=
ListenStream=${SSH_PORT}
EOF
# 禁用 socket 激活,改用传统服务
systemctl disable --now ssh.socket
systemctl enable --now ssh.service
配置说明:
Port: 自定义 SSH 端口,避开默认 22PermitRootLogin prohibit-password: root 仅允许密钥登录(比 without-password 更严格)PasswordAuthentication yes: 普通用户允许密码登录(配置密钥后可改为 no)PubkeyAuthentication yes: 启用密钥认证MaxAuthTries 3: 最多尝试 3 次认证ClientAliveInterval/CountMax: 5 分钟无活动断开
Phase 4: 配置 Fail2ban(第三招)
# 安装 fail2ban
apt install fail2ban -y
# 创建自定义配置
cat > /etc/fail2ban/jail.local << 'EOF'
[sshd]
ignoreip = 127.0.0.1/8
enabled = true
filter = sshd
port = ${SSH_PORT}
maxretry = 5
findtime = 300
bantime = 600
logpath = /var/log/auth.log
action = %(action_)s
EOF
# 启动服务
systemctl enable fail2ban
systemctl start fail2ban
配置说明:
ignoreip: 白名单 IP,不会被封maxretry: 允许失败 5 次findtime: 5 分钟内bantime: 封禁 10 分钟(设为 -1 永久封禁,但不推荐)
Phase 5: 验证 SSH 配置
# 检查配置语法
sshd -t
# 验证配置生效(重启前)
sshd -T | grep -iE "^(port|permitrootlogin|passwordauthentication|pubkeyauthentication) "
# 预期输出:
# port ${SSH_PORT}
# permitrootlogin prohibit-password
# passwordauthentication yes
# pubkeyauthentication yes
Phase 6: 配置 UFW 防火墙(第六招)
# 设置默认策略
ufw default deny incoming
ufw default allow outgoing
# 允许新 SSH 端口(必须在启用前配置!)
ufw allow ${SSH_PORT}/tcp comment 'SSH custom port'
# 如果有网站服务
# ufw allow 80/tcp
# ufw allow 443/tcp
# 启用防火墙
ufw --force enable
# 删除默认 22 端口(确认新端口可用后)
ufw delete allow 22/tcp 2>/dev/null || ufw status numbered
# 查看状态
ufw status verbose
Phase 7: 重启服务
# 重载配置
systemctl daemon-reload
systemctl restart ssh.service
systemctl restart fail2ban
# 验证服务状态
systemctl is-active ssh.service
systemctl is-active fail2ban
Phase 8: SSH 登录通知(第五招,可选)
如需配置登录通知(企业微信/Telegram/钉钉):
# 编辑 PAM 配置
vim /etc/pam.d/sshd
# 添加:session optional pam_exec.so /usr/local/bin/notify_ssh_login.sh
# 创建通知脚本
vim /usr/local/bin/notify_ssh_login.sh
chmod +x /usr/local/bin/notify_ssh_login.sh
企业微信通知脚本示例:
#!/bin/bash
if [ "$PAM_TYPE" != "open_session" ]; then
exit 0
fi
ip=$PAM_RHOST
date=$(date +"%e %b %Y, %a %r")
name=$PAM_USER
webhook_url="https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=你的webhook密钥"
curl -s -X POST "$webhook_url" \
-H "Content-Type: application/json" \
-d "{
\"msgtype\": \"markdown\",
\"markdown\": {
\"content\": \"**SSH登录提醒**\n> 登录用户: $name\n> 客户端IP: $ip\n> 登录时间: $date\"
}
}"
Phase 9: 生成报告
执行完成后,生成包含以下内容的报告:
════════════════════════════════════════════════════════════
VPS 安全加固报告
════════════════════════════════════════════════════════════
执行时间: $(date)
VPS IP: ${VPS_IP}
系统版本: $(lsb_release -ds)
[✓] 系统更新: apt update && apt upgrade 完成
[✓] 新用户: ${NEW_USER} 已创建并加入 sudo 组
[✓] SSH 端口: ${SSH_PORT}
[✓] Root 登录: 仅允许密钥登录 (prohibit-password)
[✓] 密码认证: 已启用(普通用户)
[✓] Fail2ban: 已安装并启动
[✓] UFW 防火墙: 已启用
防火墙状态:
$(ufw status verbose)
Fail2ban 状态:
$(fail2ban-client status sshd)
SSH 配置验证:
$(sshd -T | grep -iE "^(port|permitrootlogin|passwordauthentication) ")
════════════════════════════════════════════════════════════
登录信息
════════════════════════════════════════════════════════════
新登录命令: ssh -p ${SSH_PORT} ${NEW_USER}@${VPS_IP}
⚠️ 重要提醒:
1. 请确保 VPS 平台防火墙已开放端口 ${SSH_PORT}
2. 建议配置 SSH 密钥登录后禁用密码认证
3. 保存好新用户密码: ${NEW_USER_PASSWORD}
4. 如使用 Docker,注意配置端口映射安全(见第七招)
════════════════════════════════════════════════════════════
执行脚本
完整的自动化脚本见 scripts/harden-vps.sh,支持以下参数:
./scripts/harden-vps.sh \
--ip <VPS_IP> \
--root-pass <ROOT_PASSWORD> \
--user <NEW_USER> \
--user-pass <NEW_USER_PASSWORD> \
--port <SSH_PORT>
Docker 安全提醒(第七招)
如果 VPS 上运行 Docker,需要注意:
-
内部服务不暴露端口 - 数据库、Redis 等只在容器内部通信
services: redis: image: redis:alpine # 不需要 ports 配置! -
需要反代的服务只监听 127.0.0.1
services: app: ports: - "127.0.0.1:3000:3000" # 只在本地监听 -
需要公网访问的服务才暴露端口
services: web: ports: - "80:80" - "443:443"
原因:Docker 会直接修改 iptables 规则,绕过 UFW!
常见问题
Q: sshpass 未安装怎么办?
A: 手动安装:
- macOS:
brew install hudochenkov/sshpass/sshpass - Ubuntu/Debian:
sudo apt install sshpass -y - CentOS/RHEL:
sudo yum install sshpass -y
Q: root 密码登录未开启怎么办?
A: 需要通过 VPS 控制台(VNC/控制台)执行:
sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication yes/' /etc/ssh/sshd_config
sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin yes/' /etc/ssh/sshd_config
systemctl restart ssh
passwd root # 设置 root 密码
Q: 被防火墙锁死怎么办?
A: 通过 VPS 平台控制台(VNC)登录,执行:
ufw disable
# 或添加规则
ufw allow 22/tcp
ufw allow ${SSH_PORT}/tcp
Q: 如何配置 SSH 密钥登录?
# 本地生成密钥
ssh-keygen -t ed25519 -C "your@email.com"
# 复制公钥到服务器
ssh-copy-id -p ${SSH_PORT} ${NEW_USER}@${VPS_IP}
# 测试密钥登录成功后,禁用密码认证
# 修改 /etc/ssh/sshd_config.d/99-hardening.conf
PasswordAuthentication no
systemctl restart ssh
安全检查清单
- 系统已更新 (
apt update && apt upgrade) - sudo 用户已创建
- SSH 端口已修改
- root 密码登录已禁用
- Fail2ban 已安装并运行
- UFW 防火墙已配置
- 云平台防火墙已开放新端口
- SSH 密钥已配置(推荐)
- SSH 登录通知已配置(可选)
- Docker 端口映射已检查(如适用)
版本历史
- v1.0.0 (2026-03-17): 初始版本
- 7 招安全加固完整实现
- 支持 Ubuntu 多版本检测
- Fail2ban 自动安装配置
- SSH 登录通知支持
- Docker 安全提醒
More from wlzh/skills
wespy-fetcher
获取并转换微信公众号/网页文章为 Markdown 的封装 Skill,完整支持 WeSpy 的单篇抓取、微信专辑批量下载、专辑列表获取、HTML/JSON/Markdown 多格式输出。Use when user asks to 抓取微信公众号文章、公众号专辑批量下载、URL 转 Markdown、保存微信文章、mp.weixin.qq.com to markdown.
43x-fetcher
抓取 X (Twitter) 推文和长文章的命令行工具。支持普通推文(文字、图片、视频链接)和 X Article 长文章(完整正文,Markdown 格式),自动保存为 Markdown 文件。基于 Jane-xiaoer/x-fetcher 项目。Use when user mentions "抓取推文", "下载推文", "保存 X 文章", "fetch tweet", or provides x.com/twitter.com URLs.
43youtube-downloader
Download YouTube videos with customizable quality and format options. Use this skill when the user asks to download, save, or grab YouTube videos. Supports various quality settings (best, 1080p, 720p, 480p, 360p), multiple formats (mp4, webm, mkv), and audio-only downloads as MP3.
28audiocut-keyword
音频关键字过滤工具 - 根据关键字配置自动识别并删除音频中的指定内容
26youtube-tracker
Track YouTube channels for new uploads. Supports both RSS mode (no API key needed, unlimited quota) and API mode. Use when: add/remove/list tracked YouTube channels, check for new videos, or run scheduled YouTube channel monitoring.
6