上一篇 下一篇 分享链接 返回 返回顶部

香港云服务器首次上线前怎么做安全加固?从SSH、防火墙到最小权限

发布人:Minchunlin 发布时间:2026-10-04 17:14 阅读量:3

新买的香港云服务器不要在拿到公网 IP 后直接部署业务。首次上线前,至少应完成一次端口盘点、SSH 认证加固、补丁更新、云侧与系统防火墙配置、权限收敛和日志审计,并保留云厂商控制台或独立救援入口作为回滚通道。

下面的命令以使用 systemd、OpenSSH 和 UFW 的 Ubuntu 22.04/24.04、Debian 12 为例。执行前先确认发行版,不要把 UFW 命令直接套用到使用 firewalld 的系统上。远程操作时始终保留当前 SSH 会话,再用第二个会话验证,确认新登录方式正常后再关闭旧认证方式。

一、上线前先保留回退通道

1. 确认系统和当前登录状态

先确认操作系统、内核、当前用户和 SSH 服务名称:

cat /etc/os-release
uname -r
id
systemctl status ssh --no-pager

如果系统提示不存在 ssh.service,可以查询实际服务名:

systemctl list-unit-files | grep -E 'ssh|sshd'

Ubuntu 和 Debian 通常使用 ssh 服务名。执行任何配置修改前,准备以下条件:

  • 云控制台可以进入串口、VNC、Web Shell 或其他救援终端;
  • 已创建云硬盘或实例快照;
  • 已记录当前公网 IPv4,若使用 IPv6,也记录对应地址;
  • 已确认管理端的公网 IP 是否固定;
  • 已知业务需要开放的端口,未确认用途的端口暂不放行;
  • 至少保留一个具备恢复权限的管理账号。

如果管理端 IP 会频繁变化,不要为了限制 SSH 而贸然删除当前访问来源。可以先使用云控制台完成切换,或者在短时间内保留临时规则,验证新地址可以登录后再收紧。

2. 先配置云侧访问控制

云平台通常还有安全组、网络 ACL 或实例防火墙。它们与系统内 UFW 是两层独立控制:

一、上线前先保留回退通道 / 2. 先配置云侧访问控制配图

  • 云侧允许、系统侧拒绝:端口仍然无法访问;
  • 云侧拒绝、系统侧允许:端口同样无法访问;
  • 两层都允许,且服务器上有程序监听:服务才可能从公网访问。

首次加固时,云侧可以按以下原则设置:

  • TCP 22:只允许管理端固定 IP 或管理网段;
  • TCP 80、443:仅在部署网站或 API 时开放;
  • 数据库、缓存、管理面板端口:默认不允许公网访问;
  • 不需要的 UDP 端口:不要因为“以后可能用到”而预先放行;
  • 如果启用了 IPv6,必须同步检查 IPv6 规则。

云侧规则修改后,不要立即关闭当前 SSH。先在第二个终端测试新规则是否生效,确认成功后再继续主机内配置。

3. 保存关键配置

修改前可以保存 SSH 和防火墙配置:

sudo cp -a /etc/ssh/sshd_config /etc/ssh/sshd_config.before-hardening
sudo cp -a /etc/ssh/sshd_config.d /etc/ssh/sshd_config.d.before-hardening
sudo ufw status numbered > ~/ufw-status.before-hardening.txt 2>&1 || true

快照和配置备份的作用不同:快照用于整机级恢复,配置备份用于快速撤销单项改动。涉及系统升级时,还要单独考虑升级后的数据写入和业务变化,不能只依赖旧快照。

二、盘点端口和服务,先决定“该关什么”

防火墙不是用来掩盖未知服务的。先找出真正监听的端口,再判断每个端口是否有业务用途。

sudo ss -lntup

常见输出类似:

LISTEN 0 128 0.0.0.0:22    0.0.0.0:*    users:(("sshd",pid=812,fd=3))
LISTEN 0 128 127.0.0.1:6379 0.0.0.0:*  users:(("redis-server",pid=901,fd=6))
LISTEN 0 128 [::]:80      [::]:*       users:(("nginx",pid=1102,fd=7))

判断时重点看三项:

  • 127.0.0.1:端口:通常只接受本机访问,公网无法直接连接;
  • 0.0.0.0:端口:监听所有 IPv4 地址,具备被公网访问的可能;
  • [::]:端口:可能监听所有 IPv6 地址,不能只检查 IPv4。

再查看运行中的服务:

systemctl --type=service --state=running --no-pager
systemctl list-unit-files --state=enabled --no-pager

每个监听端口都应能回答三个问题:

  1. 谁启动了它?
  2. 为什么需要对外提供?
  3. 能否改为仅监听本机或内网地址?

如果一个端口没有明确用途,先停止对应应用或服务,不要只依赖修改端口号。以服务名为依据执行操作,例如:

sudo systemctl disable --now example-service

这条命令会立即停止服务并取消开机启动,必须确认 example-service 确实不再使用。回滚时执行:

sudo systemctl enable --now example-service

从另一台机器验证公网暴露情况时,可以测试特定端口:

nc -vz SERVER_IP 22
nc -vz SERVER_IP 80
nc -vz SERVER_IP 443

nc 只能说明 TCP 连接是否建立,不能证明应用已经正常工作,也不能覆盖 UDP。端口处于监听状态,也不代表云侧安全组允许公网访问;反之,安全组放行也不代表主机上真的有程序监听。

三、先建立密钥登录,再收紧 SSH

1. 创建普通管理账号

在服务器上创建一个普通管理账号。以下命令适用于 Ubuntu/Debian:

sudo adduser opsadmin
sudo usermod -aG sudo opsadmin

如果系统没有 sudo 命令,先确认是否安装了 sudo 软件包,再进行安装。不要直接删除现有 root 账号,因为云控制台、初始化脚本或紧急恢复可能仍依赖它;这里的目标是禁止 root 通过 SSH 直接登录,而不是删除 root。

在本地管理电脑生成 Ed25519 密钥:

ssh-keygen -t ed25519 -f ~/.ssh/hk-prod-ed25519

然后将公钥复制到服务器:

ssh-copy-id -i ~/.ssh/hk-prod-ed25519.pub opsadmin@SERVER_IP

如果当前服务器只允许 root 密钥登录,可以通过云控制台或当前 root 会话,将公钥写入:

/home/opsadmin/.ssh/authorized_keys

随后检查权限:

sudo chown -R opsadmin:opsadmin /home/opsadmin/.ssh
sudo chmod 700 /home/opsadmin/.ssh
sudo chmod 600 /home/opsadmin/.ssh/authorized_keys

先开启第二个终端验证:

三、先建立密钥登录,再收紧 SSH / 1. 创建普通管理账号配图

ssh -o IdentitiesOnly=yes -i ~/.ssh/hk-prod-ed25519 opsadmin@SERVER_IP
sudo -v

只有当新账号可以登录并正常执行必要的 sudo 操作后,才进入下一步。

2. 收紧 SSH 配置

建议使用独立配置文件,避免直接覆盖发行版主配置:

sudo install -d -m 755 /etc/ssh/sshd_config.d
sudo tee /etc/ssh/sshd_config.d/99-hardening.conf >/dev/null <<'EOF'
PermitRootLogin no
PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitEmptyPasswords no
MaxAuthTries 4
LoginGraceTime 30
X11Forwarding no
EOF

这些设置的含义如下:

  • PermitRootLogin no:禁止 root 直接通过 SSH 登录;
  • PubkeyAuthentication yes:允许密钥认证;
  • PasswordAuthentication no:关闭普通密码登录,降低密码撞库风险;
  • KbdInteractiveAuthentication no:关闭键盘交互式认证;
  • MaxAuthTries 4:限制单次连接的认证尝试次数;
  • X11Forwarding no:未使用图形转发时关闭该功能。

如果服务器使用基于 PAM 的多因素认证,不要直接关闭 KbdInteractiveAuthentication,应先确认该认证方案的登录流程。对于存在多个合法 SSH 账号的服务器,也不要随意加入 AllowUsers opsadmin,否则可能把运维账号排除在外。确认账号清单后,可以显式限制:

AllowUsers opsadmin deploy

修改后先检查语法,检查通过才重新加载:

sudo sshd -t
sudo systemctl reload ssh
sudo systemctl is-active ssh

再开一个全新的终端测试密钥登录:

ssh -o IdentitiesOnly=yes -i ~/.ssh/hk-prod-ed25519 opsadmin@SERVER_IP

确认实际生效的配置:

sudo sshd -T | grep -E 'permitrootlogin|pubkeyauthentication|passwordauthentication|kbdinteractiveauthentication|maxauthtries'

预期应能看到类似结果:

permitrootlogin no
pubkeyauthentication yes
passwordauthentication no
kbdinteractiveauthentication no
maxauthtries 4

如果 sshd -t 报错,不要执行 reload。先查看具体行号和配置冲突:

sudo sshd -t
sudo journalctl -u ssh --since "-10 minutes" --no-pager

修改 SSH 端口并不是安全加固的核心措施。端口改动只能减少低质量扫描噪声,不能替代密钥认证、来源限制和补丁更新。如果确实需要变更端口,必须先在云侧和 UFW 同时允许新端口,并保留当前会话,再从新端口建立第二个连接验证,最后才删除旧端口规则。

四、更新补丁并减少无用服务

SSH 和防火墙配置完成后,应更新系统软件包。更新前确认有快照,并安排可能的重启窗口。

先查看待更新内容:

sudo apt-get update
apt list --upgradable
sudo apt-get -s upgrade

-s 只模拟升级,不会真正改动系统。确认升级范围合理后执行:

sudo apt-get upgrade

如果内核、OpenSSH、systemd 或网络组件发生更新,可能需要重启。先检查系统是否提示重启:

test -f /var/run/reboot-required && echo "需要重启" || echo "暂不需要重启"

重启前应确认:

  • 当前业务有维护窗口;
  • 已有第二种登录或云控制台恢复入口;
  • 应用配置和数据已保存;
  • 云侧安全组不会阻止重启后所需的端口;
  • 远程挂载、启动盘和自启动服务已经核对。

需要重启时:

sudo reboot

重启后重新检查:

uptime
uname -r
systemctl --failed
sudo ss -lntup

不要使用一条“批量禁用所有非必要服务”的命令。对于每个服务,先确认它的用途和依赖,再执行:

systemctl status SERVICE_NAME --no-pager
sudo systemctl disable --now SERVICE_NAME

尤其要谨慎处理网络、云初始化、磁盘挂载、时间同步和监控相关服务。误停这些服务可能导致重启后无法登录、时间漂移或监控失效。

五、配置云侧和主机侧防火墙

1. 先放行管理来源,再启用 UFW

以下示例假设 203.0.113.10 是管理端固定公网 IP。该地址只是文档示例,不能直接照抄为实际地址。

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow from 203.0.113.10 to any port 22 proto tcp

如果服务器确实承载网站,再单独放行 Web 端口:

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

如果业务只供内网调用,则不要开放到所有公网地址,可以限制到内网网段:

sudo ufw allow from 10.20.0.0/16 to any port 8080 proto tcp

数据库、缓存和内部管理端口通常不应直接执行以下形式的全网放行:

allow 3306/tcp
allow 6379/tcp
allow 9200/tcp

如果应用必须跨主机访问,应指定真实的应用服务器来源 IP 或内网网段,并同时在云侧规则中限制来源。

确认 SSH 规则已经存在后再启用防火墙:

sudo ufw status numbered
sudo ufw enable
sudo ufw status verbose

启用后,从第二个终端重新测试 SSH、网站和必要的业务端口。若管理端 IP 不固定,建议通过云控制台进行规则调整,避免把 SSH 管理范围永久放宽到整个公网。

2. 检查 IPv6 和规则顺序

确认 UFW 是否启用了 IPv6 规则:

grep '^IPV6=' /etc/default/ufw
sudo ufw status

如果服务器拥有公网 IPv6,而只验证了 IPv4,需要单独测试 IPv6 入口。否则可能出现 IPv4 已限制、IPv6 仍暴露的情况。

查看带编号的规则:

sudo ufw status numbered

删除错误规则时使用编号前先再次确认:

sudo ufw delete NUMBER

防火墙调整的风险是可能立即切断当前远程连接。发生锁定时,应通过云控制台进入服务器,先查看:

sudo ufw status verbose
sudo ss -lntup

必要时可以在控制台临时执行:

sudo ufw disable

这会关闭主机侧防火墙,只适合作为短时间恢复手段。恢复 SSH 后,应重新添加来源受限规则并再次启用 UFW,而不是长期保持关闭状态。

六、落实最小权限,避免所有程序都使用 root

1. 区分登录账号、部署账号和服务账号

管理账号可以拥有必要的 sudo 权限,但网站、脚本、队列程序和数据库进程不应使用 root 身份运行。查看现有账号和高权限组:

管理账号可以拥有必要的 sudo 权限,但网站、脚本、队列程序和数据库进程不应使用 root 身份运行示意图

getent passwd
getent group sudo
sudo getent group adm
sudo -l -U opsadmin

新建服务账号时,可以使用无登录 shell 的系统账号:

sudo useradd --system --home /nonexistent --shell /usr/sbin/nologin appsvc

只有在确认该服务确实使用 appsvc 后,才调整文件所有者。不要对整个应用目录执行不加判断的 chmod -R 777,这会让同机其他用户或被入侵的进程更容易修改程序和配置。

包含密码、密钥或连接字符串的配置文件应限制读取权限,例如:

sudo chown appsvc:appsvc /etc/example/app.env
sudo chmod 600 /etc/example/app.env

具体所有者应以应用启动用户为准。修改前先确认:

systemctl show example.service -p User -p Group

2. 缩小 sudo 权限范围

管理员账号可以保留完整 sudo,便于初始维护;部署账号则应尽量只允许必要命令。编辑 sudoers 时必须使用 visudo:

sudo visudo -f /etc/sudoers.d/deploy

示例:

deploy ALL=(root) /usr/bin/systemctl restart nginx, /usr/bin/systemctl status nginx

命令路径必须先核验:

command -v systemctl
command -v nginx

保存后检查整个 sudo 配置:

sudo visudo -cf /etc/sudoers
sudo sudo -l -U deploy

不要随意写成:

deploy ALL=(ALL) NOPASSWD: ALL

这实际上等同于把 root 权限交给部署账号。还要注意,允许执行某些脚本、编辑服务配置或调用可加载外部参数的命令,可能间接获得完整 root 权限,因此最小权限需要结合实际命令行为判断,而不是只看命令名称。

七、建立可追溯的登录、提权和配置审计

至少应能够回答以下问题:谁登录过、从哪里登录、是否执行过 sudo、SSH 配置何时变化、防火墙规则是否被修改。

先检查当前日志:

sudo journalctl -u ssh --since "today" --no-pager
sudo journalctl _COMM=sudo --since "today" --no-pager
last -a | head -n 20
sudo lastb -a | head -n 20

在 Ubuntu/Debian 上,也可以查看认证日志:

sudo grep -E 'Failed password|Accepted|sudo:' /var/log/auth.log | tail -n 50

如果系统默认没有持久化 systemd 日志,可以配置日志落盘:

sudo mkdir -p /etc/systemd/journald.conf.d /var/log/journal

sudo tee /etc/systemd/journald.conf.d/10-persistent.conf >/dev/null <<'EOF'
[Journal]
Storage=persistent
SystemMaxUse=1G
EOF

sudo systemctl restart systemd-journald

SystemMaxUse=1G 是示例值,应根据磁盘容量和日志量调整。验证日志占用:

sudo journalctl --disk-usage

如果需要记录关键文件变更,可以安装并启用 auditd:

sudo apt-get install auditd
sudo systemctl enable --now auditd
sudo auditctl -s

为 SSH 和 sudo 配置增加审计规则:

sudo tee /etc/audit/rules.d/hardening.rules >/dev/null <<'EOF'
-w /etc/ssh/sshd_config -p wa -k ssh-config
-w /etc/ssh/sshd_config.d -p wa -k ssh-config
-w /etc/sudoers -p wa -k sudo-policy
-w /etc/sudoers.d -p wa -k sudo-policy
EOF

sudo augenrules --load
sudo auditctl -l

查询规则命中的记录:

sudo ausearch -k ssh-config -ts today
sudo ausearch -k sudo-policy -ts today

审计日志本身也会占用磁盘,需要定期检查轮转和保留空间。日志只记录行为,不会自动阻止攻击;发现异常登录时,还要结合来源 IP、密钥、账号权限和防火墙规则处理。

八、上线前验收清单

完成加固后,可以按下面的顺序验收:

检查项目验证方式合格判断
操作系统补丁apt list --upgradable无关键安全更新,或已明确安排更新窗口
SSH 认证新终端使用密钥登录普通管理账号可登录并执行必要的 sudo
root SSHsshd -T | grep permitrootlogin显示 permitrootlogin no
密码登录使用禁用密码认证的测试连接密码认证被拒绝
监听端口sudo ss -lntup每个监听端口都有明确用途
云侧规则控制台安全组或 ACLSSH 仅允许管理来源,业务端口按需开放
主机防火墙sudo ufw status verbose默认拒绝入站,已配置的端口与业务一致
权限范围sudo -l -U 用户名部署账号没有不必要的完整 root 权限
日志审计journalctl、ausearch能查询登录、sudo 和关键配置变更
重启状态systemctl --failed无失败服务,业务端口重启后仍正常监听

对于 Web 服务,还应从外部测试实际访问,而不仅是测试端口:

curl -I http://SERVER_IP
curl -k -I https://SERVER_IP

如果端口能连接但返回 4xx、5xx 或 TLS 错误,说明网络层已经可达,问题应转向 Nginx、应用配置或证书,而不是继续扩大防火墙范围。

九、出现问题时的回滚顺序

SSH 配置导致无法登录

保留的旧 SSH 会话不要关闭。先在旧会话中执行:

sudo sshd -t
sudo mv /etc/ssh/sshd_config.d/99-hardening.conf \
        /etc/ssh/sshd_config.d/99-hardening.conf.disabled
sudo systemctl reload ssh

如果所有会话都已断开,通过云控制台恢复配置文件,再检查语法后 reload:

sudo cp -a /etc/ssh/sshd_config.before-hardening /etc/ssh/sshd_config
sudo sshd -t
sudo systemctl reload ssh

防火墙导致业务或管理端口中断

通过云控制台查看 UFW 规则并删除刚增加的规则:

sudo ufw status numbered
sudo ufw delete NUMBER

如果无法定位规则,可以在控制台临时关闭 UFW,恢复 SSH 后重新按“先允许管理来源、再启用防火墙”的顺序配置。云侧规则也要同步检查,不能只修改主机内防火墙。

禁用服务导致应用无法启动

恢复服务并查看日志:

sudo systemctl enable --now SERVICE_NAME
sudo systemctl status SERVICE_NAME --no-pager
sudo journalctl -u SERVICE_NAME -b --no-pager

系统升级后出现兼容性问题

不要直接执行不明确版本的批量降级。先停止继续变更,保存当前日志和配置;如果升级前有快照,可在确认业务数据已经备份、接受快照之后产生的数据变化后,再安排实例级回滚。仅仅恢复 /etc 配置无法撤销内核、库文件和服务二进制的变化。

sudoers 配置错误

如果新建了独立文件,例如 /etc/sudoers.d/deploy,可以先移走该文件,再用 visudo 检查:

sudo mv /etc/sudoers.d/deploy /etc/sudoers.d/deploy.disabled
sudo visudo -cf /etc/sudoers

所有回滚动作都应保留当前登录会话,并在回滚后重新验证 SSH、监听端口、防火墙状态和业务服务。这样完成的服务器,才适合进入正式部署或对外提供服务。

目录结构
全文