VPS 安全加固實戰指南 2026:從零到堡壘級服務器防護
🛡️ 一臺剛買回來的 VPS,就像一扇沒上鎖的門。 默認配置下,SSH 端口開放、密碼登錄允許、root 直登啟用、防火牆未配置——攻擊者只需幾分鐘暴力破解就能拿到 root 權限。本文帶你從零開始,系統完成 10 大安全加固模塊,將一臺裸奔的 VPS 變成堡壘級服務器。
本文涵蓋 10 大安全模塊:
- ✅ SSH 安全加固(密鑰登錄 + 端口修改 + 禁用密碼)
- ✅ 防火牆配置(UFW / nftables 生產規則)
- ✅ Fail2ban 入侵防禦(SSH + Nginx + 多 Jail 配置)
- ✅ 內核參數加固(sysctl 安全調優)
- ✅ 用戶與權限管理(sudo + 最小權限原則)
- ✅ 自動安全更新(unattended-upgrades)
- ✅ Docker 容器安全(只讀文件系統 + 資源限制 + 網絡隔離)
- ✅ 文件完整性監控(AIDE)與 Rootkit 檢測(rkhunter)
- ✅ 日誌告警與 DDoS 緩解
- ✅ 應急響應流程 + 30 條上線檢查清單
一、VPS 安全威脅全景
在動手加固之前,先了解你的 VPS 面臨哪些威脅:
1.1 常見攻擊類型
| 攻擊類型 | 危險等級 | 發生頻率 | 典型手法 | 目標 |
|---|---|---|---|---|
| SSH 暴力破解 | ⭐⭐⭐⭐ | 極高 | 字典攻擊、撞庫、弱密碼掃描 | root 權限 |
| 挖礦木馬 | ⭐⭐⭐⭐⭐ | 高 | 利用漏洞植入挖礦程序 | CPU/GPU 資源 |
| 勒索軟件 | ⭐⭐⭐⭐⭐ | 中 | 加密文件勒索贖金 | 數據 |
| DDoS 攻擊 | ⭐⭐⭐⭐ | 中 | 大流量洪水攻擊 | 服務可用性 |
| Web 應用攻擊 | ⭐⭐⭐⭐ | 高 | SQL 注入、XSS、命令注入 | 數據庫/權限 |
| 後門植入 | ⭐⭐⭐⭐⭐ | 中 | Webshell、SSH 後門、計劃任務 | 持久化控制 |
| CVE 漏洞利用 | ⭐⭐⭐⭐⭐ | 中 | 利用已知未修補漏洞 | 系統/應用權限 |
1.2 攻擊者的典型入侵路徑
掃描開放端口 (22/80/443/3306/6379)
↓
嘗試 SSH 暴力破解 ← 90% 攻擊從這裡開始
↓
成功 → 植入挖礦程序 / 後門 / 橫向移動
失敗 → 轉向 Web 應用漏洞
↓
利用未修補 CVE (Nginx/Docker/Redis 等)
↓
獲取 shell → 提權 → 持久化
↓
清除日誌 / 植入定時任務 / 創建後門用戶1.3 安全加固的核心理念
- 最小權限原則 — 只開放必要的端口,只授予必要的權限
- 縱深防禦 — 多層防護,不依賴單一手段
- 自動響應 — Fail2ban + 告警,不要靠人工盯日誌
- 持續更新 — 安全不是一次性工作,漏洞每天都在發現
- 備份為王 — 再好的防護也可能被突破,備份是最後防線
💡 本文是 VPS 安全總綱,站內已有多篇專題文章深入講解各個模塊。本文會引用它們作為延伸閱讀,確保你既有全局視角又能深入細節。
二、SSH 安全加固
SSH 是攻擊者的首要目標,也是我們加固的第一道防線。
2.1 密鑰登錄:徹底告別密碼
# 1. 在本地機器生成 ED25519 密鑰對(比 RSA 更安全更短)
ssh-keygen -t ed25519 -C "your-email@example.com" -f ~/.ssh/vps_key
# 2. 將公鑰上傳到 VPS
ssh-copy-id -i ~/.ssh/vps_key.pub root@your-vps-ip
# 3. 測試密鑰登錄(不要關閉當前終端!)
ssh -i ~/.ssh/vps_key root@your-vps-ip⚠️ 關鍵:在確認密鑰登錄成功之前,絕對不要禁用密碼登錄。否則你會被鎖在外面。
2.2 修改 SSH 配置
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
sudo nano /etc/ssh/sshd_config修改以下關鍵參數:
# ===== SSH 安全加固配置 =====
# 修改默認端口(避免自動掃描,選 10000-65535 之間的端口)
Port 58291
# 禁用密碼登錄(僅允許密鑰)
PasswordAuthentication no
# 禁用空密碼
PermitEmptyPasswords no
# 禁用 root 直登(用普通用戶 + sudo)
PermitRootLogin no
# 僅允許指定用戶登錄
AllowUsers your-username
# 登錄超時時間(秒)
LoginGraceTime 30
# 最大認證嘗試次數
MaxAuthTries 3
# 空閒超時自動斷開(秒)
ClientAliveInterval 300
ClientAliveCountMax 2
# 禁用 X11 轉發(如不需要)
X11Forwarding no
# 禁用端口轉發(如不需要)
AllowTcpForwarding no
# 使用強加密算法
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes256-ctr
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com
KexAlgorithms curve25519-sha256@libssh.org,diffie-hellman-group16-sha512# 重啟 SSH 服務
sudo systemctl restart sshd
# 驗證配置語法(不會重啟服務)
sudo sshd -t2.3 SSH 2FA(可選但推薦)
對於高安全要求的場景,可以啟用 Google Authenticator 雙因子認證:
# 安裝 Google Authenticator PAM 模塊
sudo apt install -y libpam-google-authenticator
# 為當前用戶生成 TOTP 密鑰
google-authenticator
# 選擇 yes → yes → no → yes → yes
# 配置 PAM
echo "auth required pam_google_authenticator.so" | sudo tee -a /etc/pam.d/sshd
# 在 sshd_config 中啟用
sudo sed -i 's/ChallengeResponseAuthentication no/ChallengeResponseAuthentication yes/' /etc/ssh/sshd_config
echo "AuthenticationMethods publickey,keyboard-interactive" | sudo tee -a /etc/ssh/sshd_config
sudo systemctl restart sshd📖 延伸閱讀:SSH 密鑰配置詳解 | VPS 安全進階:超越 Fail2ban
三、防火牆配置
防火牆是服務器的網絡防線,只允許必要的流量進出。
3.1 UFW 防火牆(Ubuntu/Debian 推薦)
# 安裝 UFW
sudo apt install -y ufw
# ===== 配置默認策略 =====
sudo ufw default deny incoming
sudo ufw default allow outgoing
# ===== 開放必要端口 =====
# SSH(注意:如果你修改了 SSH 端口,這裡要對應修改)
sudo ufw allow 58291/tcp comment 'SSH'
# HTTP / HTTPS
sudo ufw allow 80/tcp comment 'HTTP'
sudo ufw allow 443/tcp comment 'HTTPS'
# 如果你運行 3X-UI 面板
sudo ufw allow 2053/tcp comment '3X-UI Panel'
# 如果你運行 WireGuard
sudo ufw allow 51820/udp comment 'WireGuard'
# ===== 限制 SSH 連接頻率 =====
# 每個 IP 每 30 秒最多 6 次連接
sudo ufw limit 58291/tcp
# 啟用防火牆
sudo ufw enable
# 查看狀態
sudo ufw status verbose3.2 UFW 高級配置
# 僅允許特定 IP 段訪問管理端口
sudo ufw allow from 192.168.1.0/24 to any port 58291 proto tcp
# 拒絕特定 IP
sudo ufw deny from 203.0.113.66 to any
# 速率限制(防止暴力連接)
sudo ufw limit 58291/tcp
# 記錄被拒絕的連接
sudo ufw logging medium
# 查看日誌
sudo tail -f /var/log/ufw.log3.3 nftables 配置(Debian 12+ / CentOS 推薦)
nftables 是 iptables 的繼任者,語法更簡潔,性能更好:
# 安裝
sudo apt install -y nftables
# 創建配置文件
sudo nano /etc/nftables.conf#!/usr/sbin/nft -f
flush ruleset
table inet filter {
chain input {
type filter hook input priority 0; policy drop;
# 允許本地迴環
iif "lo" accept
# 允許已建立的連接
ct state established,related accept
# 丟棄無效連接
ct state invalid drop
# ICMP 限速(防止 ping 洪水)
icmp type echo-request limit rate 5/second accept
ip6 nexthdr icmpv6 icmpv6 type echo-request limit rate 5/second accept
# SSH 限速(每分鐘最多 6 次新連接)
tcp dport 58291 ct state new limit rate 6/minute burst 3 packets accept
# HTTP / HTTPS
tcp dport { 80, 443 } accept
# WireGuard
udp dport 51820 accept
# 記錄被拒絕的流量
limit rate 10/minute log prefix "nftables-dropped: " drop
}
chain forward {
type filter hook forward priority 0; policy drop;
}
chain output {
type filter hook output priority 0; policy accept;
}
}# 應用規則
sudo nft -f /etc/nftables.conf
# 開機自啟
sudo systemctl enable nftables
# 查看規則
sudo nft list ruleset📖 延伸閱讀:Linux 防火牆端口開放完全指南 | iptables 防火牆指南
四、Fail2ban 入侵防禦
Fail2ban 通過監控日誌自動封禁惡意 IP,是 SSH 防爆破的標配工具。
4.1 安裝與基礎配置
sudo apt install -y fail2ban
# Fail2ban 的配置不要直接修改 jail.conf,而是創建 jail.local
sudo nano /etc/fail2ban/jail.local# ===== Fail2ban 全局配置 =====
[DEFAULT]
# 封禁時間(1 小時)
bantime = 3600
# 查找時間窗口(10 分鐘內)
findtime = 600
# 最大失敗次數
maxretry = 3
# 封禁動作(使用 UFW 或 iptables)
banaction = ufw
# 忽略的 IP(你的管理 IP)
ignoreip = 127.0.0.1/8 ::1 192.168.1.0/24
# 郵件通知(可選)
# destemail = admin@y-m.top
# sender = fail2ban@y-m.top
# action = %(action_mwl)s
# ===== SSH 防護 =====
[sshd]
enabled = true
port = 58291
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
# 重複違規者加重處罰
bantime.increment = true
bantime.factor = 2
bantime.maxtime = 604800
# ===== Nginx 防護 =====
[nginx-limit-req]
enabled = true
port = http,https
filter = nginx-limit-req
logpath = /var/log/nginx/error.log
maxretry = 10
bantime = 7200
[nginx-botsearch]
enabled = true
port = http,https
filter = nginx-botsearch
logpath = /var/log/nginx/access.log
maxretry = 5
bantime = 7200
# ===== Nginx 401/403 防護 =====
[nginx-noscript]
enabled = true
port = http,https
filter = nginx-noscript
logpath = /var/log/nginx/access.log
maxretry = 5
bantime = 3600
# ===== 防止端口掃描 =====
[port-scan]
enabled = true
filter = port-scan
logpath = /var/log/ufw.log
maxretry = 5
bantime = 86400
action = ufw# 創建端口掃描過濾器
sudo nano /etc/fail2ban/filter.d/port-scan.conf[Definition]
failregex = .*block.*from.*SRC=.*
ignoreregex =# 重啟 Fail2ban
sudo systemctl restart fail2ban
sudo systemctl enable fail2ban
# 查看狀態
sudo fail2ban-client status
sudo fail2ban-client status sshd
# 手動解封 IP
sudo fail2ban-client set sshd unbanip 203.0.113.664.2 Fail2ban 進階:遞增封禁
上面的配置中已經啟用了 bantime.increment,效果如下:
| 第 N 次被封 | 封禁時間 |
|---|---|
| 第 1 次 | 1 小時 |
| 第 2 次 | 2 小時 |
| 第 3 次 | 4 小時 |
| 第 4 次 | 8 小時 |
| ... | ... |
| 上限 | 7 天 |
📖 延伸閱讀:Fail2ban 防暴力破解配置完全指南
五、內核參數加固
Linux 內核默認配置以兼容性為主,不少參數對安全並不友好。通過 sysctl 調優可以顯著提升系統安全性。
5.1 安全加固 sysctl 配置
sudo nano /etc/sysctl.d/99-security.conf# ===== 網絡安全加固 =====
# 開啟 SYN Cookies(防 SYN Flood)
net.ipv4.tcp_syncookies = 1
# 增加 SYN 隊列長度
net.ipv4.tcp_max_syn_backlog = 4096
# SYN+ACK 重試次數(減少半連接佔用)
net.ipv4.tcp_synack_retries = 2
# 開啟反向路徑過濾(防 IP 欺騙)
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
# 禁用 ICMP 重定向(防中間人攻擊)
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv6.conf.default.accept_redirects = 0
# 禁用源路由(防 IP 欺騙)
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0
net.ipv6.conf.default.accept_source_route = 0
# 禁用 ICMP 廣播響應(防 Smurf 攻擊)
net.ipv4.icmp_echo_ignore_broadcasts = 1
# 記錄可疑數據包( Martian Packets)
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.log_martians = 1
# 忽略錯誤的 ICMP 請求
net.ipv4.icmp_ignore_bogus_error_responses = 1
# TCP Keepalive 調優(更快發現死連接)
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 5
# ===== 連接數限制 =====
# 端口範圍(可用於出站連接的臨時端口)
net.ipv4.ip_local_port_range = 10000 65535
# 連接跟蹤表大小(內存夠的話調大)
net.netfilter.nf_conntrack_max = 131072
net.netfilter.nf_conntrack_timeout_established = 3600
# TIME_WAIT 狀態優化
net.ipv4.tcp_max_tw_buckets = 8192
net.ipv4.tcp_tw_reuse = 1
# ===== 內核安全 =====
# 禁用 IPv4 轉發(如果不是路由器/VPN)
# 注意:如果你運行 WireGuard/3X-UI 需要轉發,設為 1
# net.ipv4.ip_forward = 0
# 禁用 IPv6 轉發(同上)
# net.ipv6.conf.all.forwarding = 0
# 地址空間佈局隨機化(防緩衝區溢出)
kernel.randomize_va_space = 2
# 限制 dmesg 訪問(只有 root 能看內核日誌)
kernel.dmesg_restrict = 1
# 限制 kptr(內核指針)暴露
kernel.kptr_restrict = 2
# 限制內核性能事件
kernel.perf_event_paranoid = 3
# 限制 BPF(防 eBPF 提權)
kernel.unprivileged_bpf_disabled = 1
# 禁用用戶命名空間(防容器逃逸,注意 Docker 需要)
# kernel.unprivileged_userns_clone = 0
# 限制核心轉儲(防止信息洩露)
fs.suid_dumpable = 0
# 符號鏈接保護(防 TOCTOU 攻擊)
fs.protected_symlinks = 1
fs.protected_hardlinks = 1
# FIFO 保護
fs.protected_fifos = 2
fs.protected_regular = 2# 應用配置
sudo sysctl -p /etc/sysctl.d/99-security.conf
# 驗證
sudo sysctl net.ipv4.tcp_syncookies
sudo sysctl kernel.randomize_va_space5.2 內核參數說明表
| 參數 | 值 | 作用 |
|---|---|---|
tcp_syncookies | 1 | 防 SYN Flood 攻擊 |
rp_filter | 1 | 反向路徑過濾,防 IP 欺騙 |
accept_redirects | 0 | 禁用 ICMP 重定向 |
accept_source_route | 0 | 禁用源路由 |
icmp_echo_ignore_broadcasts | 1 | 防 Smurf 攻擊 |
log_martians | 1 | 記錄可疑數據包 |
randomize_va_space | 2 | ASLR 地址隨機化 |
dmesg_restrict | 1 | 限制 dmesg 訪問 |
kptr_restrict | 2 | 隱藏內核指針 |
suid_dumpable | 0 | 禁用核心轉儲 |
protected_symlinks | 1 | 符號鏈接保護 |
⚠️ 注意:如果你運行 WireGuard 或 3X-UI 代理面板,需要保持
net.ipv4.ip_forward = 1。具體配置請參考 WireGuard 自建 VPN 完整教程 和 3X-UI 面板自建代理教程。
六、用戶與權限管理
6.1 創建非 root 管理用戶
永遠不要用 root 直接操作。創建一個有 sudo 權限的普通用戶:
# 創建新用戶
adduser deploy
# 加入 sudo 組
usermod -aG sudo deploy
# 驗證 sudo 權限
su - deploy
sudo whoami # 應返回 root6.2 sudo 安全配置
sudo visudo -f /etc/sudoers.d/security# ===== sudo 安全配置 =====
# 要求 sudo 時輸入密碼(默認行為)
Defaults requiretty
Defaults !visiblepw
# 密碼嘗試 3 次後退出
Defaults passwd_tries = 3
# 超時時間 5 分鐘
Defaults timestamp_timeout = 5
# 記錄 sudo 日誌
Defaults logfile = "/var/log/sudo.log"
Defaults log_input, log_output
# 允許 deploy 用戶執行所有命令
deploy ALL=(ALL) ALL
# 如果有隻需要特定命令的用戶,用最小權限
# webadmin ALL=(ALL) /usr/bin/systemctl restart nginx, /usr/bin/systemctl reload nginx6.3 禁用不必要的系統賬戶
# 查看所有用戶的 shell
cat /etc/passwd | grep -E "(/bin/bash|/bin/sh)$"
# 禁用不需要登錄的系統賬戶
sudo usermod -s /usr/sbin/nologin sync
sudo usermod -s /usr/sbin/nologin news
sudo usermod -s /usr/sbin/nologin uucp
sudo usermod -s /usr/sbin/nologin operator
sudo usermod -s /usr/sbin/nologin games
# 鎖定空密碼賬戶
sudo passwd -l nobody6.4 文件權限加固
# 關鍵系統文件權限
sudo chmod 644 /etc/passwd
sudo chmod 640 /etc/shadow
sudo chmod 644 /etc/group
sudo chmod 640 /etc/gshadow
# SSH 目錄權限
sudo chmod 700 ~/.ssh
sudo chmod 600 ~/.ssh/authorized_keys
# sudoers 文件權限
sudo chmod 440 /etc/sudoers
sudo chmod 440 /etc/sudoers.d/*七、自動安全更新
保持系統更新是安全的基礎。配置自動安裝安全補丁,不需要手動干預。
7.1 配置 unattended-upgrades
# 安裝
sudo apt install -y unattended-upgrades apt-listchanges
# 自動配置
sudo dpkg-reconfigure -plow unattended-upgrades# 編輯配置文件
sudo nano /etc/apt/apt.conf.d/50unattended-upgradesUnattended-Upgrade::Allowed-Origins {
"${distro_id}:${distro_codename}";
"${distro_id}:${distro_codename}-security";
"${distro_id}ESMApps:${distro_codename}-apps-security";
"${distro_id}ESM:${distro_codename}-infra-security";
};
# 自動重啟(如果更新需要)
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "04:00";
# 郵件通知(可選)
// Unattended-Upgrade::Mail "admin@y-m.top";
// Unattended-Upgrade::MailReport "on-change";
# 移除不再需要的包
Unattended-Upgrade::Remove-Unused-Dependencies "true";
# 移除不再需要的內核
Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";# 編輯自動更新週期
sudo nano /etc/apt/apt.conf.d/20auto-upgradesAPT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
APT::Periodic::AutocleanInterval "7";
APT::Periodic::Download-Upgradeable-Packages "1";# 驗證配置(試運行)
sudo unattended-upgrade --dry-run --verbose
# 手動觸發一次
sudo unattended-upgrade -v7.2 需要排除的包
某些包不希望自動更新(如自定義內核、特定版本鎖定):
# 在 50unattended-upgrades 中添加
Unattended-Upgrade::Package-Blacklist {
"nginx";
"docker-ce";
"redis-server";
};💡 建議:對於生產環境的關鍵服務(如數據庫),建議關閉自動更新,改用 定時手動更新 + 更新前快照 的策略。
八、Docker 容器安全
如果你在 VPS 上跑 Docker(很多人都是),容器安全同樣重要。
8.1 Docker 守護進程加固
sudo nano /etc/docker/daemon.json{
"icc": false,
"no-new-privileges": true,
"userland-proxy": false,
"live-restore": true,
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
},
"default-ulimits": {
"nofile": {
"Name": "nofile",
"Hard": 65536,
"Soft": 1024
}
},
"userns-remap": "default"
}sudo systemctl restart docker8.2 容器安全最佳實踐
# 1. 不要用 --privileged 運行容器
# 錯誤:docker run --privileged nginx
# 正確:docker run --cap-drop ALL --cap-add NET_BIND_SERVICE nginx
# 2. 只讀文件系統 + 臨時目錄
docker run -d \
--name myapp \
--read-only \
--tmpfs /tmp \
--cap-drop ALL \
--cap-add NET_BIND_SERVICE \
--memory="512m" \
--cpus="1.0" \
--pids-limit=100 \
--security-opt no-new-privileges \
-p 80:80 \
nginx:alpine
# 3. 使用非 root 用戶運行
docker run -d \
--user 1000:1000 \
myapp:latest
# 4. 限制網絡訪問(僅允許出站到指定地址)
docker network create --internal restricted-net
docker run -d --network restricted-net myapp8.3 Docker 安全檢查腳本
#!/bin/bash
# 文件名: docker-security-check.sh
echo "===== Docker 安全檢查 ====="
# 檢查是否有 --privileged 容器
echo "1. 檢查特權容器..."
PRIVILEGED=$(docker ps -q | xargs docker inspect --format '{{.Name}} Privileged={{.HostConfig.Privileged}}' | grep "Privileged=true" || echo "無")
echo " $PRIVILEGED"
# 檢查是否有容器以 root 運行
echo "2. 檢查 root 運行的容器..."
ROOT_CONTAINERS=$(docker ps -q | xargs docker inspect --format '{{.Name}} User={{.Config.User}}' | grep 'User=$' || echo "無")
echo " $ROOT_CONTAINERS"
# 檢查是否有容器沒有資源限制
echo "3. 檢查無資源限制的容器..."
NO_LIMIT=$(docker ps -q | xargs docker inspect --format '{{.Name}} Memory={{.HostConfig.Memory}} CPUs={{.HostConfig.NanoCpus}}' | grep 'Memory=0 CPUs=0' || echo "無")
echo " $NO_LIMIT"
# 檢查 Docker 版本
echo "4. Docker 版本: $(docker version --format '{{.Server.Version}}')"
# 檢查 daemon.json 配置
echo "5. 安全配置檢查..."
if [ -f /etc/docker/daemon.json ]; then
echo " daemon.json 存在"
grep -q "no-new-privileges" /etc/docker/daemon.json && echo " ✓ no-new-privileges 已啟用" || echo " ✗ no-new-privileges 未啟用"
grep -q "userns-remap" /etc/docker/daemon.json && echo " ✓ userns-remap 已啟用" || echo " ✗ userns-remap 未啟用"
else
echo " ✗ daemon.json 不存在"
fi8.4 Docker Compose 安全配置示例
# docker-compose.security.yml
services:
webapp:
image: myapp:latest
read_only: true
tmpfs:
- /tmp
- /run
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE
security_opt:
- no-new-privileges:true
deploy:
resources:
limits:
cpus: '1.0'
memory: 512M
reservations:
memory: 256M
pids_limit: 100
user: "1000:1000"
networks:
- frontend
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 30s
timeout: 5s
retries: 3
networks:
frontend:
driver: bridge
internal: false📖 延伸閱讀:Docker 多階段構建優化 | Immich 私有云部署
九、文件完整性監控與 Rootkit 檢測
9.1 AIDE — 文件完整性監控
AIDE(Advanced Intrusion Detection Environment)定期掃描關鍵文件,發現任何篡改立即告警。
# 安裝
sudo apt install -y aide
# 初始化數據庫(首次運行會掃描所有文件,耗時較長)
sudo aideinit
# 將初始化數據庫設為基準
sudo cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db
# 手動執行檢查
sudo aide --check
# 更新基準(當你主動修改了系統文件後)
sudo aide --update
sudo cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db配置定時檢查腳本:
sudo nano /etc/cron.daily/aide-check#!/bin/bash
# AIDE 每日完整性檢查
REPORT=$(sudo aide --check 2>&1)
if echo "$REPORT" | grep -q "All entries match"; then
echo "[$(date)] AIDE 檢查通過,文件完整性正常" >> /var/log/aide-check.log
else
echo "[$(date)] ⚠️ AIDE 檢測到文件變更!" >> /var/log/aide-check.log
echo "$REPORT" >> /var/log/aide-check.log
# 發送告警郵件(可選)
echo "$REPORT" | mail -s "[ALERT] AIDE 文件完整性檢查異常" admin@y-m.top
# Telegram 告警(可選)
# curl -s "https://api.telegram.org/bot<TOKEN>/sendMessage" \
# -d chat_id="<CHAT_ID>" \
# -d text="⚠️ AIDE 檢測到文件變更,請檢查 /var/log/aide-check.log"
fisudo chmod +x /etc/cron.daily/aide-check9.2 rkhunter — Rootkit 檢測
# 安裝
sudo apt install -y rkhunter
# 更新數據庫
sudo rkhunter --update
sudo rkhunter --propupd
# 執行檢查
sudo rkhunter --check --sk
# 查看報告
sudo cat /var/log/rkhunter.log | grep -E "Warning|Rootkit"配置每日自動掃描:
sudo nano /etc/cron.daily/rkhunter-check#!/bin/bash
# rkhunter 每日 Rootkit 掃描
REPORT=$(sudo rkhunter --check --sk --report-warnings-only 2>&1)
if [ -n "$REPORT" ]; then
echo "[$(date)] ⚠️ rkhunter 發現可疑項:" >> /var/log/rkhunter-check.log
echo "$REPORT" >> /var/log/rkhunter-check.log
# Telegram 告警
# curl -s "https://api.telegram.org/bot<TOKEN>/sendMessage" \
# -d chat_id="<CHAT_ID>" \
# -d text="⚠️ rkhunter 發現可疑項,請檢查日誌"
else
echo "[$(date)] rkhunter 掃描通過,未發現 Rootkit" >> /var/log/rkhunter-check.log
fisudo chmod +x /etc/cron.daily/rkhunter-check📖 延伸閱讀:Linux 服務器入侵檢測與安全審計實戰
十、日誌告警與 DDoS 緩解
10.1 日誌監控告警
# 安裝 logwatch(每日安全摘要郵件)
sudo apt install -y logwatch
# 配置
sudo nano /etc/logwatch/conf/logwatch.confMailTo = admin@y-m.top
MailFrom = logwatch@y-m.top
Range = yesterday
Detail = High
Service = All# 測試發送
sudo logwatch --output mail --range yesterday
# 它會每天自動運行(已集成到 /etc/cron.daily/)10.2 SSH 登錄告警
在用戶登錄時發送通知:
sudo nano /etc/ssh/sshrc#!/bin/bash
# SSH 登錄通知
# 獲取登錄信息
IP=$(echo "$SSH_CONNECTION" | awk '{print $1}')
TIME=$(date "+%Y-%m-%d %H:%M:%S")
USER=$(whoami)
HOST=$(hostname)
# Telegram 通知
curl -s "https://api.telegram.org/bot<TOKEN>/sendMessage" \
-d chat_id="<CHAT_ID>" \
-d text="🔐 SSH 登錄通知
服務器: $HOST
用戶: $USER
IP: $IP
時間: $TIME"
# 郵件通知
echo "SSH 登錄: $USER from $IP at $TIME on $HOST" | mail -s "[SSH] 登錄通知" admin@y-m.topsudo chmod +x /etc/ssh/sshrc10.3 DDoS 緩解策略
| 策略 | 適用場景 | 效果 | 實施難度 |
|---|---|---|---|
| UFW 速率限制 | 小規模連接洪水 | 中 | 低 |
| Fail2ban | 應用層 CC 攻擊 | 中 | 低 |
| Cloudflare CDN | L3/L4/L7 DDoS | 高 | 低 |
| iptables/nftables 限速 | SYN Flood | 中 | 中 |
| BBR 擁塞控制 | 帶寬耗盡型攻擊 | 中 | 低 |
10.3.1 開啟 BBR 擁塞控制
echo "net.core.default_qdisc = fq" | sudo tee -a /etc/sysctl.d/99-bbr.conf
echo "net.ipv4.tcp_congestion_control = bbr" | sudo tee -a /etc/sysctl.d/99-bbr.conf
sudo sysctl -p /etc/sysctl.d/99-bbr.conf
# 驗證
sysctl net.ipv4.tcp_congestion_control
# 應返回: net.ipv4.tcp_congestion_control = bbr10.3.2 iptables SYN Flood 防護
# 限制每秒 SYN 包數量
sudo iptables -A INPUT -p tcp --syn -m limit --limit 20/s --limit-burst 40 -j ACCEPT
sudo iptables -A INPUT -p tcp --syn -j DROP
# 限制每 IP 併發連接數
sudo iptables -A INPUT -p tcp --dport 80 -m connlimit --connlimit-above 50 -j DROP
sudo iptables -A INPUT -p tcp --dport 443 -m connlimit --connlimit-above 50 -j DROP
# 保存規則
sudo netfilter-persistent save10.3.3 Cloudflare 防護(推薦)
對於 Web 服務,最有效的 DDoS 防護是套一層 Cloudflare:
- 域名 DNS 遷移到 Cloudflare
- 開啟 Proxy(橙色雲朵)
- SSL/TLS 設為 Full (Strict)
- 開啟 Always Use HTTPS
- 安全級別設為 High
- 開啟 Bot Fight Mode
- 配置 WAF 規則攔截惡意請求
📖 延伸閱讀:Cloudflare Tunnel 內網穿透 | Cloudflare WARP 中轉
十一、應急響應:被黑了怎麼辦
即使做了所有加固,也可能被突破。關鍵是如何快速響應。
11.1 應急響應流程
發現異常 → 隔離服務器 → 保留證據 → 排查範圍 → 清除威脅 → 恢復服務 → 覆盤總結11.2 第一步:隔離
# 立即斷網(通過雲平臺控制檯操作,不要用 SSH 斷網,否則自己也連不上)
# 或通過防火牆僅允許自己的 IP
sudo ufw deny incoming
sudo ufw allow from YOUR_IP to any port 58291
# 禁用所有非必要服務
sudo systemctl stop nginx
sudo systemctl stop docker11.3 第二步:排查
# 1. 檢查當前登錄用戶
w
who -a
last -20
# 2. 檢查可疑進程
ps aux | grep -E "(miner|xmr|kworker.*\s$|python.*http)"
top -c
# 3. 檢查網絡連接
ss -tunlp
ss -tunp | grep ESTABLISHED
# 4. 檢查計劃任務(挖礦木馬最喜歡藏這裡)
crontab -l
sudo crontab -l
ls -la /etc/cron.d/
ls -la /var/spool/cron/
cat /etc/crontab
# 5. 檢查異常文件
find /tmp /var/tmp /dev/shm -type f -executable
find / -name "*.sh" -newer /etc/passwd -type f 2>/dev/null
# 6. 檢查 SSH 後門
cat ~/.ssh/authorized_keys
grep -r "PermitRootLogin\|PasswordAuthentication" /etc/ssh/
# 7. 檢查新增用戶
grep -v "nologin\|false" /etc/passwd
# 8. 檢查 SUID 文件(提權後門)
find / -perm -4000 -type f 2>/dev/null
# 9. 檢查異常 systemd 服務
systemctl list-units --type=service --state=running | grep -v "ssh\|docker\|nginx\|systemd"
# 10. 運行 rkhunter
sudo rkhunter --check --sk11.4 第三步:清除與恢復
# 殺死可疑進程
sudo kill -9 $(pgrep -f "可疑進程名")
# 刪除惡意文件
sudo rm -f /tmp/可疑文件
sudo rm -f /var/tmp/可疑文件
# 清除惡意計劃任務
crontab -r # 清空當前用戶 crontab
sudo rm -f /etc/cron.d/惡意文件
# 刪除後門 SSH 密鑰
nano ~/.ssh/authorized_keys # 手動刪除不認識的密鑰
# 重置所有密碼
passwd
sudo passwd root
# 更新所有軟件
sudo apt update && sudo apt upgrade -y11.5 最終建議:重裝系統
如果確認被入侵,最安全的做法是重裝系統:
- 備份關鍵數據(只備份應用數據,不備份系統配置)
- 雲平臺重裝系統
- 按本文流程重新加固
- 恢復數據(逐個檢查後再恢復)
- 更新所有密鑰和密碼
💡 記住:你永遠無法 100% 確定清除了所有後門。重裝是唯一可靠的選擇。
📖 延伸閱讀:VPS 數據備份與恢復完整指南 | rsync 增量備份指南
十二、安全檢查清單:上線前 30 條
將以下清單逐條檢查後再上線服務:
SSH 安全
防火牆
入侵防禦
內核加固
用戶與權限
自動更新
完整性監控
容器安全
備份
十三、一鍵加固腳本
將以上核心步驟整合為一鍵腳本,方便新 VPS 快速加固:
#!/bin/bash
# ============================================================
# VPS 一鍵安全加固腳本 v2026
# 適用系統: Debian 12+ / Ubuntu 22.04+
# 作者: y-m.top
# ============================================================
set -e
# ===== 配置區(按需修改)=====
SSH_PORT="58291"
NEW_USER="deploy"
SSH_KEY="" # 填入你的公鑰(ssh-ed25519 AAAA... email)
# ===== 顏色輸出 =====
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
info() { echo -e "${GREEN}[✓]${NC} $1"; }
warn() { echo -e "${YELLOW}[!]${NC} $1"; }
error() { echo -e "${RED}[✗]${NC} $1"; }
# ===== 1. 系統更新 =====
echo "===== 1/8 系統更新 ====="
apt update && apt upgrade -y -o Dpkg::Options::="--force-confold"
info "系統已更新"
# ===== 2. 創建管理用戶 =====
echo "===== 2/8 創建管理用戶 ====="
if ! id "$NEW_USER" &>/dev/null; then
adduser --gecos "" --disabled-password "$NEW_USER"
usermod -aG sudo "$NEW_USER"
info "用戶 $NEW_USER 已創建並加入 sudo 組"
else
warn "用戶 $NEW_USER 已存在"
fi
# ===== 3. SSH 加固 =====
echo "===== 3/8 SSH 加固 ====="
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date +%s)
# 設置 SSH 密鑰
if [ -n "$SSH_KEY" ]; then
mkdir -p /home/$NEW_USER/.ssh
echo "$SSH_KEY" > /home/$NEW_USER/.ssh/authorized_keys
chmod 700 /home/$NEW_USER/.ssh
chmod 600 /home/$NEW_USER/.ssh/authorized_keys
chown -R $NEW_USER:$NEW_USER /home/$NEW_USER/.ssh
info "SSH 公鑰已添加"
fi
# 修改 SSH 配置
sed -i "s/^#Port 22/Port $SSH_PORT/" /etc/ssh/sshd_config
sed -i "s/^Port 22/Port $SSH_PORT/" /etc/ssh/sshd_config
sed -i 's/^#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
sed -i 's/^PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
sed -i 's/^#PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config
sed -i 's/^PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config
sed -i 's/^#PermitEmptyPasswords.*/PermitEmptyPasswords no/' /etc/ssh/sshd_config
sed -i 's/^#MaxAuthTries.*/MaxAuthTries 3/' /etc/ssh/sshd_config
sed -i 's/^#LoginGraceTime.*/LoginGraceTime 30/' /etc/ssh/sshd_config
# 添加 AllowUsers
if ! grep -q "^AllowUsers" /etc/ssh/sshd_config; then
echo "AllowUsers $NEW_USER" >> /etc/ssh/sshd_config
fi
info "SSH 配置已加固(端口: $SSH_PORT)"
# ===== 4. 防火牆 =====
echo "===== 4/8 防火牆配置 ====="
apt install -y ufw
ufw default deny incoming
ufw default allow outgoing
ufw limit $SSH_PORT/tcp comment 'SSH'
ufw allow 80/tcp comment 'HTTP'
ufw allow 443/tcp comment 'HTTPS'
echo "y" | ufw enable
info "UFW 防火牆已啟用"
# ===== 5. Fail2ban =====
echo "===== 5/8 Fail2ban 配置 ====="
apt install -y fail2ban
cat > /etc/fail2ban/jail.local << 'EOF'
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 3
banaction = ufw
ignoreip = 127.0.0.1/8 ::1
bantime.increment = true
bantime.factor = 2
bantime.maxtime = 604800
[sshd]
enabled = true
port = 58291
maxretry = 3
EOF
# 修正 SSH 端口
sed -i "s/port = 58291/port = $SSH_PORT/" /etc/fail2ban/jail.local
systemctl restart fail2ban
systemctl enable fail2ban
info "Fail2ban 已配置"
# ===== 6. 內核加固 =====
echo "===== 6/8 內核參數加固 ====="
cat > /etc/sysctl.d/99-security.conf << 'EOF'
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 4096
net.ipv4.tcp_synack_retries = 2
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv6.conf.default.accept_redirects = 0
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.conf.all.log_martians = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
kernel.randomize_va_space = 2
kernel.dmesg_restrict = 1
kernel.kptr_restrict = 2
kernel.perf_event_paranoid = 3
kernel.unprivileged_bpf_disabled = 1
fs.suid_dumpable = 0
fs.protected_symlinks = 1
fs.protected_hardlinks = 1
fs.protected_fifos = 2
fs.protected_regular = 2
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr
EOF
sysctl -p /etc/sysctl.d/99-security.conf
info "內核安全參數已應用"
# ===== 7. 自動更新 =====
echo "===== 7/8 自動安全更新 ====="
apt install -y unattended-upgrades
cat > /etc/apt/apt.conf.d/20auto-upgrades << 'EOF'
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
APT::Periodic::AutocleanInterval "7";
EOF
info "自動安全更新已啟用"
# ===== 8. 完整性監控 =====
echo "===== 8/8 安裝 AIDE + rkhunter ====="
apt install -y aide rkhunter
rkhunter --update
rkhunter --propupd
info "AIDE 和 rkhunter 已安裝(需手動初始化 AIDE 數據庫)"
# ===== 完成 =====
echo ""
echo "=========================================="
echo -e "${GREEN}✓ VPS 安全加固完成!${NC}"
echo "=========================================="
echo ""
echo "重要提醒:"
echo "1. 請先用新端口和密鑰測試 SSH 連接,確認能連上後再關閉當前終端"
echo " ssh -p $SSH_PORT $NEW_USER@your-vps-ip"
echo "2. 手動初始化 AIDE 數據庫:"
echo " sudo aideinit && sudo cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db"
echo "3. 建議安裝 Docker 後配置 daemon.json 加固"
echo "4. 完整檢查清單請參考文章第十二節"
echo ""
warn "警告:請先驗證 SSH 密鑰登錄成功後再關閉當前終端!"將腳本保存為 vps-hardening.sh,修改配置區參數後執行:
chmod +x vps-hardening.sh
sudo ./vps-hardening.shFAQ:常見問題
Q1:加固後 SSH 連不上了怎麼辦?
先用雲平臺的 VNC 控制檯登錄,然後檢查:
- SSH 端口是否正確:
grep "^Port" /etc/ssh/sshd_config - 密鑰是否配置正確:
cat ~/.ssh/authorized_keys - 防火牆是否放行:
ufw status - Fail2ban 是否誤封:
fail2ban-client status sshd - SSH 服務是否運行:
systemctl status sshd
如果確認配置正確但仍無法連接,臨時恢復備份:
cp /etc/ssh/sshd_config.bak.* /etc/ssh/sshd_config
systemctl restart sshdQ2:Fail2ban 把自己的 IP 封了怎麼辦?
# 查看被封的 IP
sudo fail2ban-client status sshd
# 解封 IP
sudo fail2ban-client set sshd unbanip YOUR_IP
# 將自己的 IP 加入白名單
sudo nano /etc/fail2ban/jail.local
# 修改 ignoreip = 127.0.0.1/8 ::1 YOUR_IP
sudo systemctl restart fail2banQ3:unattended-upgrades 會自動重啟服務器嗎?
只有在配置中開啟了 Automatic-Reboot "true" 時才會。關鍵服務(如數據庫)建議關閉自動重啟,改用手動更新:
# 在 50unattended-upgrades 中設置
Unattended-Upgrade::Automatic-Reboot "false";Q4:Docker 容器用了 --read-only 後無法寫入怎麼辦?
掛載可寫捲到需要寫入的目錄:
docker run --read-only \
-v /data/app/logs:/app/logs \
-v /data/app/uploads:/app/uploads \
--tmpfs /tmp \
myappQ5:AIDE 報告大量文件變更,正常嗎?
首次運行 AIDE 後如果安裝了新軟件或修改了配置,會產生大量變更報告。處理方式:
- 確認變更是你自己操作引起的
- 更新 AIDE 基準:
sudo aide --update && sudo cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db - 如果變更不是你引起的,立即排查入侵
Q6:如何判斷服務器是否被入侵?
快速檢查清單:
# 1. 檢查異常進程(特別是高 CPU 佔用)
top -c -o %CPU | head -20
# 2. 檢查異常網絡連接
ss -tunp | grep ESTABLISHED
# 3. 檢查計劃任務
crontab -l && sudo crontab -l && ls /etc/cron.d/
# 4. 檢查最近修改的文件
find /etc /usr/local/bin /tmp -type f -mtime -7 2>/dev/null
# 5. 運行 rkhunter
sudo rkhunter --check --sk
# 6. 檢查登錄記錄
last -20如果發現可疑進程、異常網絡連接或未知計劃任務,參考第十一節應急響應流程。
Q7:sysctl 參數設置後重啟會丟失嗎?
不會。寫入 /etc/sysctl.d/ 目錄的 .conf 文件會在每次啟動時自動加載。但如果你直接用 sysctl -w 設置的參數,重啟後會丟失。
Q8:需要同時用 UFW 和 iptables/nftables 嗎?
不需要。選擇一個即可:
- UFW — Ubuntu/Debian 用戶首選,語法簡單
- nftables — Debian 12+ / CentOS 默認,性能更好
- iptables — 老系統兼容,但不推薦新部署使用
混用可能導致規則衝突。
總結與延伸閱讀
安全加固優先級
如果你時間有限,按以下優先級執行:
| 優先級 | 加固項 | 耗時 | 效果 |
|---|---|---|---|
| P0 | SSH 密鑰 + 禁用密碼 + 修改端口 | 5 分鐘 | 阻斷 90% 自動化攻擊 |
| P0 | 防火牆僅開放必要端口 | 3 分鐘 | 減少攻擊面 |
| P1 | Fail2ban 防爆破 | 5 分鐘 | 自動封禁惡意 IP |
| P1 | 內核 sysctl 加固 | 2 分鐘 | 防網絡層攻擊 |
| P2 | 創建非 root 用戶 | 3 分鐘 | 限制權限 |
| P2 | 自動安全更新 | 3 分鐘 | 防 CVE 漏洞 |
| P3 | AIDE + rkhunter | 10 分鐘 | 入侵檢測 |
| P3 | Docker 安全加固 | 5 分鐘 | 容器隔離 |
| P3 | 日誌告警通知 | 10 分鐘 | 實時感知 |
P0 + P1 總共 15 分鐘,就能擋住 95% 的攻擊。
延伸閱讀
- VPS 供應商橫向對比 — 選一臺安全基礎好的 VPS
- Fail2ban 防暴力破解完全指南 — Fail2ban 深度配置
- VPS 安全進階:超越 Fail2ban — 2FA 和 UFW 高級配置
- 入侵檢測與安全審計實戰 — AIDE/rkhunter 深度教程
- Linux 防火牆端口完全指南 — UFW/iptables/firewalld 全覆蓋
- Nginx 反向代理與 SSL 配置 — Web 服務安全配置
- VPS 數據備份與恢復完整指南 — 最後的安全網
- 3X-UI 面板自建代理教程 — 代理面板部署
- WireGuard 自建 VPN 完整教程 — VPN 協議配置
🛡️ 安全沒有終點,只有持續的加固。 上線不是結束,而是開始。定期更新、定期檢查、定期演練——這才是真正的安全之道。
延伸阅读
免责声明
本文仅供技术交流和学习参考。涉及第三方服务的链接可能包含 sponsored 标记,请自行核实服务条款、价格和可用性,并遵守当地法律法规。