Debian服务器初始化配置教程:用户、SSH、防火墙与软件源设置

一台刚开通的 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

关键参数说明:

参数推荐值作用注意点
PermitRootLoginno禁止 root 直接登录若有自动化工具依赖 root 登录,改用 prohibit-password 过渡
PasswordAuthenticationno关闭口令认证必须先确认密钥能登录,否则直接锁死
MaxAuthTries3单次连接最多认证次数调太小会导致多密钥用户第一次握手失败
ClientAliveInterval / CountMax300 / 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

七、交付前的自检清单

初始化完成后,按顺序跑一遍,任何一项不通过都不许交付:

  1. sshd -T | grep -E 'permitrootlogin|passwordauthentication' 确认返回 no。
  2. 新开一个终端用密钥登录成功,且 root 直登被拒绝。
  3. sudo ufw status 或 nft list ruleset 显示预期规则,reboot 后仍生效(确认已 enable)。
  4. apt update && apt list --upgradable 无 dependent 错误、无 NO_PUBKEY。
  5. apt policy <关键包名> 确认来源是你期望的那个套件,没有被意外从 backports 拉包。
  6. timedatectl 中 NTP 为 active,时区正确。
  7. systemctl --failed 输出为空。
  8. 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 配置,才是它真正发挥作用的地方——新机器从开通到可交付控制在十分钟以内。