一台刚开通的 Debian 裸机,SSH 用着默认的 22 端口、root 直接可登、软件源指向万里之外的官方站,apt update 要跑三分钟。这样的机器上线即埋雷。Debian 的哲学是"少即是多"——最小安装里连 sudo 都没有,好处是干净,代价是所有初始化动作都得你自己做。本文按用户 → SSH → 防火墙 → 软件源 → 收尾加固的顺序,给出一套可以直接照抄执行的配置流程。
一、先确认基线:版本、网络与分区
动手之前花两分钟确认环境,能省掉后面大量返工。注意 Debian 的稳定版代号会随时间推进(本文示例以编写时的 stable 版 bookworm / Debian 12 为主),实际代号请以自己机器上的输出为准。
# 确认 Debian 版本与代号 cat /etc/debian_version lsb_release -a hostnamectl # 网络与网关、DNS ip -br addr ip route show default resolvectl status 2>/dev/null || cat /etc/resolv.conf # 磁盘与文件系统类型(后面做快照会用到) lsblk -f df -hT / /boot /var
如果此时 apt update 极慢或者报证书/域名解析错误,先解决网络和时间。时间偏差过大会导致 HTTPS 证书校验失败、表现为 Certificate is not yet valid,这一点在刚开通的云主机上并不罕见:
timedatectl status sudo timedatectl set-timezone Asia/Shanghai # Debian 默认使用 systemd-timesyncd,无需额外安装 sudo systemctl enable --now systemd-timesyncd timedatectl timesync-status 2>/dev/null || timedatectl show-timesync
二、软件源设置:先把源改对
Debian 12 起默认采用 DEB822 新格式,配置文件在 /etc/apt/sources.list.d/debian.sources,而不是老教程里那一行 deb http://...。两种写法都有效,但不要混用同一套件,否则会撞"Target Packages ... is configured multiple times"警告。
2.1 新格式(DEB822,Debian 11+/12 推荐)
sudo tee /etc/apt/sources.list.d/debian.sources <<'EOF' Types: deb URIs: https://deb.debian.org/debian Suites: bookworm bookworm-updates Components: main contrib non-free non-free-firmware Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg Types: deb URIs: https://security.debian.org/debian-security Suites: bookworm-security Components: main contrib non-free non-free-firmware Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg EOF sudo apt update
2.2 老格式(一行式,兼容习惯)
sudo tee /etc/apt/sources.list <<'EOF' deb https://deb.debian.org/debian bookworm main contrib non-free non-free-firmware deb https://deb.debian.org/debian bookworm-updates main contrib non-free non-free-firmware deb https://security.debian.org/debian-security bookworm-security main contrib non-free non-free-firmware EOF # 用新格式时,请把 sources.list 里的重复条目注释或删除 sudo apt update
三个容易踩的点:
- 安全源自 Debian 11(bullseye)起改为
<代号>-security套件,形式是https://security.debian.org/debian-security bookworm-security。沿用更老教程里的security.debian.org/debian-security stable/updates写法在新版本上会失效。 non-free-firmware是 Debian 12 新增的组件,网卡、RAID 卡、GPU 的部分固件现在放这里。漏配这个组件,某些硬件会直接"没有网卡"。- 不要给源写
stable这个代号。写stable意味着下一次大版本发布时,你的机器会在某次apt update后被自动带到新版本——这在服务器上极其危险。永远写死代号。
2.3 换国内镜像与安全组注意事项
如果服务器在国内部署,deb.debian.org 会解析到就近 CDN,通常并不慢;确有需要时可替换 URIs 为国内镜像站(如清华、阿里云、腾讯云的 Debian 镜像),路径结构一致。更换后务必确认 apt update 不再报 NO_PUBKEY 或 Release 文件已过期。
另外,apt 从 1.5 版本起原生支持 https,不必再装 apt-transport-https;许多旧教程里的这一步在现代 Debian 上是多余操作。
2.4 backports 的正确打开方式
需要新内核或新版驱动时才会用到 backports。它默认优先级为 100,即"不会自动覆盖 stable 的包",只有显式指定才会安装:
# 添加 backports 源 echo 'deb https://deb.debian.org/debian bookworm-backports main contrib non-free-firmware' \ | sudo tee /etc/apt/sources.list.d/backports.list # 安装时必须显式指定,否则不会生效 sudo apt update sudo apt install -t bookworm-backports linux-image-amd64 # 确认策略,验证来源正确 apt policy apt-cache policy linux-image-amd64
三、创建用户与配置 sudo
Debian 最小安装默认没有安装 sudo(这是它和 Ubuntu 最大的差异之一)。直接用新用户执行 sudo 会报 command not found。
# 1. 安装 sudo(如果尚未安装) su - apt update && apt install -y sudo # 2. 创建运维用户(adduser 是 Debian 的交互式封装,会自动建 home 与同名组) adduser opsadmin # 3. 加入 sudo 组(Debian 的默认 sudoers 已放行 %sudo) usermod -aG sudo opsadmin # 4. 验证:切换到新用户,sudo -l 应输出可执行的规则 su - opsadmin sudo -l getent group sudo
需要给特定应用账号建用户时(例如跑服务的 appuser,不允许密码登录,只能用密钥),这样更合适:
sudo adduser --disabled-password --gecos "" appuser sudo mkdir -p /home/appuser/.ssh sudo install -m 700 -o appuser -g appuser -d /home/appuser/.ssh sudo install -m 600 -o appuser -g appuser /dev/null /home/appuser/.ssh/authorized_keys # 把公钥内容写入 authorized_keys 后确认权限 sudo stat -c '%U %G %a %n' /home/appuser/.ssh /home/appuser/.ssh/authorized_keys
如果需要给某个账号做细粒度授权,不要改 /etc/sudoers,在 /etc/sudoers.d/ 下建独立文件,并用 visudo 校验语法:
sudo visudo -f /etc/sudoers.d/appuser # 内容示例:只允许重启某个服务,且无需密码 # appuser ALL=(root) NOPASSWD: /bin/systemctl restart app.service sudo visudo -c # 全量语法检查,有误会直接指出文件名与行号
四、SSH 加固:Debian 上最容易搞混的地方
把密钥准备好再动手加固,否则可能把自己锁在门外。先开第二个终端窗口保持已登录状态,改完不重启服务也能验证。
4.1 分发密钥
# 在本地机器上生成密钥(没有则先生成) ssh-keygen -t ed25519 -C "ops@company" # 推送到服务器 ssh-copy-id -i ~/.ssh/id_ed25519.pub opsadmin@SERVER_IP # 在服务器上确认写入结果 ls -l ~/.ssh/authorized_keys sudo sshd -t # 任何时候改动前先做语法自检
4.2 修改 SSH 服务端配置
Debian 的 SSH 服务单元名是 ssh 而不是 sshd(Red Hat 系才是 sshd)。这是新手最常犯的错误之一。新版 sshd_config 顶部通常有 Include /etc/ssh/sshd_config.d/*.conf,建议把自定义配置放进独立文件,避免包升级时被覆盖。
sudo tee /etc/ssh/sshd_config.d/10-hardening.conf <<'EOF' Port 22 PermitRootLogin no PubkeyAuthentication yes PasswordAuthentication no PermitEmptyPasswords no ChallengeResponseAuthentication no UsePAM yes X11Forwarding no AllowTcpForwarding no ClientAliveInterval 300 ClientAliveCountMax 2 LoginGraceTime 30 MaxAuthTries 3 MaxSessions 10 EOF sudo sshd -t sudo systemctl reload ssh sudo systemctl status ssh --no-pager
关键参数说明:
| 参数 | 推荐值 | 作用 | 注意点 |
|---|---|---|---|
| PermitRootLogin | no | 禁止 root 直接登录 | 若有自动化工具依赖 root 登录,改用 prohibit-password 过渡 |
| PasswordAuthentication | no | 关闭口令认证 | 必须先确认密钥能登录,否则直接锁死 |
| MaxAuthTries | 3 | 单次连接最多认证次数 | 调太小会导致多密钥用户第一次握手失败 |
| ClientAliveInterval / CountMax | 300 / 2 | 约 10 分钟无响应则断开 | 用于回收僵死连接,配合跳板机策略 |
| AllowUsers / AllowGroups | 按需 | 白名单机制 | 一旦配置,名单外账号将无法登录,注意别漏掉 rsync/备份账号 |
改完端口的话(比如改成 2222),别忘了 Debian 上 SELinux 不存在,但 AppArmor 与防火墙都要同步放行,并且下一次 sshd 包升级时会询问是否覆盖 sshd_config,选保留本地版本。
五、防火墙:选一个并坚持用
Debian 从 buster 起默认后端是 nftables,你看到的 iptables 命令多半是 iptables-nft 兼容层。三者混用是灾难的起点。
| 方案 | 上手成本 | 适合场景 | 主要缺点 |
|---|---|---|---|
| ufw | 低 | 单机、规则简单(allow 22/tcp 这类) | 复杂 NAT/多网卡能力弱;Debian 默认未安装 |
| nftables 原生 | 高 | 网关、容器宿主、需要精细规则 | 语法学习成本高 |
| firewalld | 中 | 已有 RHEL 系经验的团队统一配置风格 | 与容器运行时、Docker 的 iptables 规则容易打架 |
| 云厂商安全组 | 低 | 云平台基线防护 | 不能替代主机防火墙,二者应叠加 |
5.1 ufw 最简配置(推荐新手)
sudo apt install -y ufw # 默认策略:拒绝所有入站,允许所有出站 sudo ufw default deny incoming sudo ufw default allow outgoing # 先放行 SSH,再启用,顺序不能反 sudo ufw allow 22/tcp comment 'ssh' sudo ufw allow 80,443/tcp comment 'web' # 按来源 IP 放行(例如只允许办公室 IP 访问管理端口) sudo ufw allow from 203.0.113.10 to any port 22 proto tcp sudo ufw enable sudo ufw status numbered sudo ufw logging medium # 日志写入 /var/log/ufw.log
服务器在国外、管理网段固定的话,ufw allow from 限制来源 IP 是最有效的一步。务必确认自己的出口 IP(可用 curl -4 ifconfig.io 或 ip route get 8.8.8.8 辅助判断)再执行。
5.2 nftables 原生规则示例
sudo apt install -y nftables
sudo tee /etc/nftables.conf <<'EOF'
#!/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
tcp dport 22 accept
tcp dport { 80, 443 } accept
icmp type echo-request limit rate 5/second accept
}
chain forward { type filter hook forward priority 0; policy drop; }
chain output { type filter hook output priority 0; policy accept; }
}
EOF
sudo nft -c -f /etc/nftables.conf # 先做语法检查,别直接 reload
sudo systemctl enable --now nftables
sudo nft list ruleset
六、收尾加固:自动更新、时间与基础软件
6.1 启用安全自动更新
服务器上建议至少让安全更新自动安装,避免一级 CVE 打不上。
sudo apt install -y unattended-upgrades apt-listchanges sudo dpkg-reconfigure -plow unattended-upgrades # 确认定时器已启用 systemctl status apt-daily-upgrade.timer --no-pager systemctl status apt-daily.timer --no-pager # 查看自动更新的策略与时点 grep -Ev '^\s*#|^\s*$' /etc/apt/apt.conf.d/50unattended-upgrades | head -40 grep -r PersonalPackageArchives /etc/apt/apt.conf.d/50unattended-upgrades # 干跑一次,看它会装什么 sudo unattended-upgrade --dry-run --debug | head -50
6.2 防暴力破解与基础工具
sudo apt install -y fail2ban sudo tee /etc/fail2ban/jail.local <<'EOF' [sshd] enabled = true port = ssh backend = systemd maxretry = 5 findtime = 600 bantime = 3600 EOF sudo systemctl enable --now fail2ban sudo fail2ban-client status sshd
基础工具按需安装,注意 net-tools(ifconfig、netstat)已长期无维护,优先用 iproute2 的 ip、ss:
sudo apt install -y curl wget vim tmux htop iotop sysstat lsof rsync \
ca-certificates gnupg jq dnsutils
# 如需 iperf3/netcat 做网络排查
sudo apt install -y iperf3 netcat-openbsd tcpdump
# sar 采集开关(sysstat)
sudo sed -i 's/^ENABLED=.*/ENABLED="true"/' /etc/default/sysstat
sudo systemctl enable --now sysstat
6.3 内核参数与资源限制
sudo tee /etc/sysctl.d/99-server.conf <<'EOF' net.ipv4.ip_forward = 0 net.ipv4.tcp_syncookies = 1 net.ipv4.conf.all.rp_filter = 1 net.ipv4.conf.default.rp_filter = 1 net.ipv4.icmp_echo_ignore_broadcasts = 1 net.ipv4.conf.all.accept_redirects = 0 net.ipv4.conf.all.send_redirects = 0 net.core.somaxconn = 65535 net.ipv4.ip_local_port_range = 1024 65535 vm.swappiness = 10 fs.file-max = 1000000 EOF sudo sysctl --system sudo sysctl -a --pattern 'somaxconn|swappiness'
文件描述符的上限别忘了还要在 systemd 侧同步。PAM 的 /etc/security/limits.conf 只作用于登录会话,对 systemd 服务无效,服务的限制要靠 systemctl edit:
sudo systemctl edit nginx.service # 写入: # [Service] # LimitNOFILE=65535 # LimitNPROC=65535 sudo systemctl daemon-reload sudo systemctl restart nginx systemctl show nginx -p LimitNOFILE
七、交付前的自检清单
初始化完成后,按顺序跑一遍,任何一项不通过都不许交付:
sshd -T | grep -E 'permitrootlogin|passwordauthentication'确认返回no。- 新开一个终端用密钥登录成功,且
root直登被拒绝。 sudo ufw status或nft list ruleset显示预期规则,reboot后仍生效(确认已 enable)。apt update && apt list --upgradable无 dependent 错误、无NO_PUBKEY。apt policy <关键包名>确认来源是你期望的那个套件,没有被意外从 backports 拉包。timedatectl中 NTP 为active,时区正确。systemctl --failed输出为空。systemctl list-timers --all里能看到apt-daily-upgrade.timer且下次触发时间合理。
小结
Debian 初始化的本质,是把"系统默认给你的一切"换成"你明确要求的一切"。最容易出问题的四个点位再强调一遍:sudo 默认没装、服务名是 ssh 不是 sshd、sources.list 别写 stable、防火墙别混用 iptables 与 nftables。
避坑建议:
- 所有
sshd_config改动放进/etc/ssh/sshd_config.d/,改完必跑sshd -t,并在已登录的第二个窗口不断线的情况下 reload。 - 关闭密码登录之前,先在一个已开的 session 里验证新用户密钥登录 OK——这是唯一不会被锁死的保命手段,比任何救援都要快。
- 软件源永远写死代号。
stable会在下一次大版本发布时把你的生产机器"自动升级"。若确实不想被大版本波及,可用apt-mark hold或/etc/apt/preferences.d/固定关键包。 - 第三方的软件源密钥放到
/etc/apt/keyrings/并配合源的Signed-By字段使用,避免全局信任带来的污染。 - 启用
unattended-upgrades后仍要定期上线看看/var/log/unattended-upgrades/,自动更新失败不会有人主动通知你。 - 初始化做完立刻做一次云盘快照或系统快照,把这个"干净基准"留住,后续扩容和排障都有退路。
把这套流程脚本化成 Ansible 或 cloud-init 配置,才是它真正发挥作用的地方——新机器从开通到可交付控制在十分钟以内。
企业QQ咨询




