跳轉到內容

VPS 安全加固實戰指南 2026:從零到堡壘級服務器防護

VPS Security Hardening

🛡️ 一臺剛買回來的 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 安全加固的核心理念

  1. 最小權限原則 — 只開放必要的端口,只授予必要的權限
  2. 縱深防禦 — 多層防護,不依賴單一手段
  3. 自動響應 — Fail2ban + 告警,不要靠人工盯日誌
  4. 持續更新 — 安全不是一次性工作,漏洞每天都在發現
  5. 備份為王 — 再好的防護也可能被突破,備份是最後防線

💡 本文是 VPS 安全總綱,站內已有多篇專題文章深入講解各個模塊。本文會引用它們作為延伸閱讀,確保你既有全局視角又能深入細節。


二、SSH 安全加固

SSH 是攻擊者的首要目標,也是我們加固的第一道防線。

2.1 密鑰登錄:徹底告別密碼

bash
# 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 配置

bash
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
sudo nano /etc/ssh/sshd_config

修改以下關鍵參數:

bash
# ===== 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
bash
# 重啟 SSH 服務
sudo systemctl restart sshd

# 驗證配置語法(不會重啟服務)
sudo sshd -t

2.3 SSH 2FA(可選但推薦)

對於高安全要求的場景,可以啟用 Google Authenticator 雙因子認證:

bash
# 安裝 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 推薦)

bash
# 安裝 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 verbose

3.2 UFW 高級配置

bash
# 僅允許特定 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.log

3.3 nftables 配置(Debian 12+ / CentOS 推薦)

nftables 是 iptables 的繼任者,語法更簡潔,性能更好:

bash
# 安裝
sudo apt install -y nftables

# 創建配置文件
sudo nano /etc/nftables.conf
bash
#!/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;
    }
}
bash
# 應用規則
sudo nft -f /etc/nftables.conf

# 開機自啟
sudo systemctl enable nftables

# 查看規則
sudo nft list ruleset

📖 延伸閱讀Linux 防火牆端口開放完全指南 | iptables 防火牆指南


四、Fail2ban 入侵防禦

Fail2ban 通過監控日誌自動封禁惡意 IP,是 SSH 防爆破的標配工具。

4.1 安裝與基礎配置

bash
sudo apt install -y fail2ban

# Fail2ban 的配置不要直接修改 jail.conf,而是創建 jail.local
sudo nano /etc/fail2ban/jail.local
ini
# ===== 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
bash
# 創建端口掃描過濾器
sudo nano /etc/fail2ban/filter.d/port-scan.conf
ini
[Definition]
failregex = .*block.*from.*SRC=.*
ignoreregex =
bash
# 重啟 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.66

4.2 Fail2ban 進階:遞增封禁

上面的配置中已經啟用了 bantime.increment,效果如下:

第 N 次被封封禁時間
第 1 次1 小時
第 2 次2 小時
第 3 次4 小時
第 4 次8 小時
......
上限7 天

📖 延伸閱讀Fail2ban 防暴力破解配置完全指南


五、內核參數加固

Linux 內核默認配置以兼容性為主,不少參數對安全並不友好。通過 sysctl 調優可以顯著提升系統安全性。

5.1 安全加固 sysctl 配置

bash
sudo nano /etc/sysctl.d/99-security.conf
bash
# ===== 網絡安全加固 =====

# 開啟 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
bash
# 應用配置
sudo sysctl -p /etc/sysctl.d/99-security.conf

# 驗證
sudo sysctl net.ipv4.tcp_syncookies
sudo sysctl kernel.randomize_va_space

5.2 內核參數說明表

參數作用
tcp_syncookies1防 SYN Flood 攻擊
rp_filter1反向路徑過濾,防 IP 欺騙
accept_redirects0禁用 ICMP 重定向
accept_source_route0禁用源路由
icmp_echo_ignore_broadcasts1防 Smurf 攻擊
log_martians1記錄可疑數據包
randomize_va_space2ASLR 地址隨機化
dmesg_restrict1限制 dmesg 訪問
kptr_restrict2隱藏內核指針
suid_dumpable0禁用核心轉儲
protected_symlinks1符號鏈接保護

⚠️ 注意:如果你運行 WireGuard 或 3X-UI 代理面板,需要保持 net.ipv4.ip_forward = 1。具體配置請參考 WireGuard 自建 VPN 完整教程3X-UI 面板自建代理教程


六、用戶與權限管理

6.1 創建非 root 管理用戶

永遠不要用 root 直接操作。創建一個有 sudo 權限的普通用戶:

bash
# 創建新用戶
adduser deploy

# 加入 sudo 組
usermod -aG sudo deploy

# 驗證 sudo 權限
su - deploy
sudo whoami  # 應返回 root

6.2 sudo 安全配置

bash
sudo visudo -f /etc/sudoers.d/security
bash
# ===== 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 nginx

6.3 禁用不必要的系統賬戶

bash
# 查看所有用戶的 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 nobody

6.4 文件權限加固

bash
# 關鍵系統文件權限
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

bash
# 安裝
sudo apt install -y unattended-upgrades apt-listchanges

# 自動配置
sudo dpkg-reconfigure -plow unattended-upgrades
bash
# 編輯配置文件
sudo nano /etc/apt/apt.conf.d/50unattended-upgrades
bash
Unattended-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";
bash
# 編輯自動更新週期
sudo nano /etc/apt/apt.conf.d/20auto-upgrades
bash
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
APT::Periodic::AutocleanInterval "7";
APT::Periodic::Download-Upgradeable-Packages "1";
bash
# 驗證配置(試運行)
sudo unattended-upgrade --dry-run --verbose

# 手動觸發一次
sudo unattended-upgrade -v

7.2 需要排除的包

某些包不希望自動更新(如自定義內核、特定版本鎖定):

bash
# 在 50unattended-upgrades 中添加
Unattended-Upgrade::Package-Blacklist {
    "nginx";
    "docker-ce";
    "redis-server";
};

💡 建議:對於生產環境的關鍵服務(如數據庫),建議關閉自動更新,改用 定時手動更新 + 更新前快照 的策略。


八、Docker 容器安全

如果你在 VPS 上跑 Docker(很多人都是),容器安全同樣重要。

8.1 Docker 守護進程加固

bash
sudo nano /etc/docker/daemon.json
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"
}
bash
sudo systemctl restart docker

8.2 容器安全最佳實踐

bash
# 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 myapp

8.3 Docker 安全檢查腳本

bash
#!/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 不存在"
fi

8.4 Docker Compose 安全配置示例

yaml
# 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)定期掃描關鍵文件,發現任何篡改立即告警。

bash
# 安裝
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

配置定時檢查腳本:

bash
sudo nano /etc/cron.daily/aide-check
bash
#!/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"
fi
bash
sudo chmod +x /etc/cron.daily/aide-check

9.2 rkhunter — Rootkit 檢測

bash
# 安裝
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"

配置每日自動掃描:

bash
sudo nano /etc/cron.daily/rkhunter-check
bash
#!/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
fi
bash
sudo chmod +x /etc/cron.daily/rkhunter-check

📖 延伸閱讀Linux 服務器入侵檢測與安全審計實戰


十、日誌告警與 DDoS 緩解

10.1 日誌監控告警

bash
# 安裝 logwatch(每日安全摘要郵件)
sudo apt install -y logwatch

# 配置
sudo nano /etc/logwatch/conf/logwatch.conf
bash
MailTo = admin@y-m.top
MailFrom = logwatch@y-m.top
Range = yesterday
Detail = High
Service = All
bash
# 測試發送
sudo logwatch --output mail --range yesterday

# 它會每天自動運行(已集成到 /etc/cron.daily/)

10.2 SSH 登錄告警

在用戶登錄時發送通知:

bash
sudo nano /etc/ssh/sshrc
bash
#!/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.top
bash
sudo chmod +x /etc/ssh/sshrc

10.3 DDoS 緩解策略

策略適用場景效果實施難度
UFW 速率限制小規模連接洪水
Fail2ban應用層 CC 攻擊
Cloudflare CDNL3/L4/L7 DDoS
iptables/nftables 限速SYN Flood
BBR 擁塞控制帶寬耗盡型攻擊

10.3.1 開啟 BBR 擁塞控制

bash
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 = bbr

10.3.2 iptables SYN Flood 防護

bash
# 限制每秒 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 save

10.3.3 Cloudflare 防護(推薦)

對於 Web 服務,最有效的 DDoS 防護是套一層 Cloudflare:

  1. 域名 DNS 遷移到 Cloudflare
  2. 開啟 Proxy(橙色雲朵)
  3. SSL/TLS 設為 Full (Strict)
  4. 開啟 Always Use HTTPS
  5. 安全級別設為 High
  6. 開啟 Bot Fight Mode
  7. 配置 WAF 規則攔截惡意請求

📖 延伸閱讀Cloudflare Tunnel 內網穿透 | Cloudflare WARP 中轉


十一、應急響應:被黑了怎麼辦

即使做了所有加固,也可能被突破。關鍵是如何快速響應。

11.1 應急響應流程

發現異常 → 隔離服務器 → 保留證據 → 排查範圍 → 清除威脅 → 恢復服務 → 覆盤總結

11.2 第一步:隔離

bash
# 立即斷網(通過雲平臺控制檯操作,不要用 SSH 斷網,否則自己也連不上)
# 或通過防火牆僅允許自己的 IP
sudo ufw deny incoming
sudo ufw allow from YOUR_IP to any port 58291

# 禁用所有非必要服務
sudo systemctl stop nginx
sudo systemctl stop docker

11.3 第二步:排查

bash
# 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 --sk

11.4 第三步:清除與恢復

bash
# 殺死可疑進程
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 -y

11.5 最終建議:重裝系統

如果確認被入侵,最安全的做法是重裝系統

  1. 備份關鍵數據(只備份應用數據,不備份系統配置)
  2. 雲平臺重裝系統
  3. 按本文流程重新加固
  4. 恢復數據(逐個檢查後再恢復)
  5. 更新所有密鑰和密碼

💡 記住:你永遠無法 100% 確定清除了所有後門。重裝是唯一可靠的選擇。

📖 延伸閱讀VPS 數據備份與恢復完整指南 | rsync 增量備份指南


十二、安全檢查清單:上線前 30 條

將以下清單逐條檢查後再上線服務:

SSH 安全

防火牆

入侵防禦

內核加固

用戶與權限

自動更新

完整性監控

容器安全

備份


十三、一鍵加固腳本

將以上核心步驟整合為一鍵腳本,方便新 VPS 快速加固:

bash
#!/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,修改配置區參數後執行:

bash
chmod +x vps-hardening.sh
sudo ./vps-hardening.sh

FAQ:常見問題

Q1:加固後 SSH 連不上了怎麼辦?

先用雲平臺的 VNC 控制檯登錄,然後檢查:

  1. SSH 端口是否正確:grep "^Port" /etc/ssh/sshd_config
  2. 密鑰是否配置正確:cat ~/.ssh/authorized_keys
  3. 防火牆是否放行:ufw status
  4. Fail2ban 是否誤封:fail2ban-client status sshd
  5. SSH 服務是否運行:systemctl status sshd

如果確認配置正確但仍無法連接,臨時恢復備份:

bash
cp /etc/ssh/sshd_config.bak.* /etc/ssh/sshd_config
systemctl restart sshd

Q2:Fail2ban 把自己的 IP 封了怎麼辦?

bash
# 查看被封的 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 fail2ban

Q3:unattended-upgrades 會自動重啟服務器嗎?

只有在配置中開啟了 Automatic-Reboot "true" 時才會。關鍵服務(如數據庫)建議關閉自動重啟,改用手動更新:

bash
# 在 50unattended-upgrades 中設置
Unattended-Upgrade::Automatic-Reboot "false";

Q4:Docker 容器用了 --read-only 後無法寫入怎麼辦?

掛載可寫捲到需要寫入的目錄:

bash
docker run --read-only \
  -v /data/app/logs:/app/logs \
  -v /data/app/uploads:/app/uploads \
  --tmpfs /tmp \
  myapp

Q5:AIDE 報告大量文件變更,正常嗎?

首次運行 AIDE 後如果安裝了新軟件或修改了配置,會產生大量變更報告。處理方式:

  1. 確認變更是你自己操作引起的
  2. 更新 AIDE 基準:sudo aide --update && sudo cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db
  3. 如果變更不是你引起的,立即排查入侵

Q6:如何判斷服務器是否被入侵?

快速檢查清單:

bash
# 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 — 老系統兼容,但不推薦新部署使用

混用可能導致規則衝突。


總結與延伸閱讀

安全加固優先級

如果你時間有限,按以下優先級執行:

優先級加固項耗時效果
P0SSH 密鑰 + 禁用密碼 + 修改端口5 分鐘阻斷 90% 自動化攻擊
P0防火牆僅開放必要端口3 分鐘減少攻擊面
P1Fail2ban 防爆破5 分鐘自動封禁惡意 IP
P1內核 sysctl 加固2 分鐘防網絡層攻擊
P2創建非 root 用戶3 分鐘限制權限
P2自動安全更新3 分鐘防 CVE 漏洞
P3AIDE + rkhunter10 分鐘入侵檢測
P3Docker 安全加固5 分鐘容器隔離
P3日誌告警通知10 分鐘實時感知

P0 + P1 總共 15 分鐘,就能擋住 95% 的攻擊。

延伸閱讀


🛡️ 安全沒有終點,只有持續的加固。 上線不是結束,而是開始。定期更新、定期檢查、定期演練——這才是真正的安全之道。


延伸阅读

免责声明

本文仅供技术交流和学习参考。涉及第三方服务的链接可能包含 sponsored 标记,请自行核实服务条款、价格和可用性,并遵守当地法律法规。

最後更新於: