2476 字
12 分钟
新到手的 Linux 服务器,我这样设置
2025-11-20

原文链接:https://blog.dejavu.moe/posts/new-linux-server-setup-guide/

概要#

本文介绍每次上手一台新的 Linux 服务器后,我的一些 基本设置步骤,包括:

  • 使用一键 DD 脚本重装纯净的 Debian GNU/Linux 操作系统
  • SSH 安全和 Fail2ban 设置
  • 配置 UFW 防火墙
  • 安装 Nginx Web 服务器
  • 安装 Docker CE 及必要插件
  • 使用 Cloudflare CDN 保护服务和全球加速

并不一定适合所有人的需求,仅作为我每次快速设置新服务器的速查手册。建议搭配以下内容一起使用:

重装系统#

选择脚本#

网络上支持一键 DD 重装系统的脚本有很多,我主要使用这两个:

  1. bin456789/reinstall
  2. bohanwood/debi

前者支持的系统选择更多,后者则专注于 Debian GNU/Linux 的最小发行版。两者都在 GitHub 上开源,且经过长期的社区关注和审查,安全性大可以放心。

无论如何,在正式开始之前,仔细阅读一遍脚本作者的说明(文档说明详细易读),知道自己在做什么,预期会出现什么。

我在所有服务器上都一直使用 Debian,下面以 debi 脚本为例。

下载脚本#

Terminal window
curl -fLO https://raw.githubusercontent.com/bohanyang/debi/master/debi.sh

执行脚本#

赋予脚本可执行权限

Terminal window
chmod +x debi.sh

开始重装系统

Terminal window
sudo ./debi.sh \
--version 13 \
--architecture arm64 \
--cloudflare \
--user viamoe \
--authorized-keys-url https://github.com/githubUserName.keys \
--ssh-port 22122 \
--bbr

上面参数的意义:

  • --version 13

    指定 Debian 13(代号 Trixie)为安装的版本

  • --architecture arm64

    指定系统架构,这里的 arm64,只适用于 ARM64 架构的机器(比如甲骨文 ARM VPS)

  • --cloudflare

    使用 Cloudflare 作为系统默认 DNS

  • --user viamoe

    创建一个普通用户,用户名为 viamoe,脚本自动配置该用户的 sudo 权限

  • --authorized-keys-url https://github.com/githubUserName.keys

    指定 SSH 公钥 URL 来源,用于设置 SSH 免密码登录

  • --ssh-port 22122

    修改 SSH 默认端口为 22122,你应当修改它,减少被自动扫描攻击的风险

  • --bbr

    启用 BBR(TCP 拥塞控制算法),提升网络在高延迟或跨国网络环境下传输性能

一切就绪,开始重装系统

Terminal window
sudo reboot

期间你可以使用 VNC 查看系统安装进度,根据服务器性能或网络环境,稍等几分钟,新的系统即将就绪。之后,使用重装阶段预设的用户名密码或 SSH 密钥登录服务器。

安装常用软件包#

我们的服务器正在运行的是一个纯净、最小、最新的 Debian GNU/Linux 操作系统,需要安装一些基础或常用的软件包。

基本工具包#

Terminal window
sudo apt update
sudo apt install \
ca-certificates \
apt-transport-https \
man \
build-essential \
git \
curl \
wget \
screen \
btop \
net-tools \
tree \
neovim

安装 Docker#

参考 Docker 官方文档 说明的步骤,下列命令不保证时效性

Terminal window
# Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
# Add the repository to Apt sources:
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo systemctl status docker

安装 Nginx#

同样地,参考 Nginx 项目文档——在 Debian 上的 安装步骤

Terminal window
# install the prerequisites
sudo apt install curl gnupg2 ca-certificates lsb-release debian-archive-keyring
# import gpg key
curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor \
| sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null
# verify gpg key
mkdir -m 700 ~/.gnupg
gpg --dry-run --quiet --no-keyring --import --import-options import-show /usr/share/keyrings/nginx-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \
http://nginx.org/packages/debian `lsb_release -cs` nginx" \
| sudo tee /etc/apt/sources.list.d/nginx.list
# install nginx
sudo apt update
sudo apt install nginx
# start nginx
sudo systemctl start nginx

SSH 基本加固#

编辑 SSH 配置文件

Terminal window
sudo nvim /etc/ssh/sshd_config

这里有一些我们需要关注的配置项目:

  • Port 22122

    SSH 服务监听的默认端口,我们已在重装脚本中指定

  • PermitRootLogin no

    禁止 Root 用户直接登录,使用普通用户登录,使用 sudo 提权

  • PasswordAuthentication no

    禁止使用密码登录 SSH,我们应当使用密钥对或实体安全密钥(如 Yubikey、Canokey 等)进行登

  • PermitEmptyPasswords no 禁止空密码登录

  • ChallengeResponseAuthentication no 禁用键盘交互式密码认证

  • PubkeyAuthentication yes 启用公钥认证,此前已在重装脚本中指定

  • UseDNS no 禁用 DNS 反查

  • X11Forwarding no 禁用 X11 转发,如果你不知道这是什么那就可以禁用

保持当前的 SSH 会话不要断开连接,重启 SSH 服务

Terminal window
sudo systemctl restart sshd

重开一个 SSH 会话,再次登录当前服务器,确保连接正常,否则返回第一个 SSH 会话中进行检查。

配置 Fail2ban#

使用 Fail2ban 保护我们的服务器免受 SSH 爆破,并合理封禁异常的 IP 地址

安装 Fail2ban#

Terminal window
sudo apt update
sudo apt install fail2ban

SSH 守护配置#

创建一个最小的,仅用于守护 SSH 登录的 Fail2ban 配置文件

Terminal window
sudo nvim /etc/fail2ban/jail.local

配置内容如下:

[DEFAULT]
# 忽略 IP 地址:防止将自己封禁。
# 如果您使用动态 IP,不要设置您的公网 IP。
# 127.0.0.1/8 和 ::1 忽略本地回环地址。
ignoreip = 127.0.0.1/8 ::1
# 封禁时间:封禁 1 小时(3600 秒)
bantime = 1h
# 查找时间:在 10 分钟内(600 秒)
findtime = 10m
# 最大重试次数:如果在 findtime (10 分钟) 内失败了 3 次,则封禁。
maxretry = 3
[sshd]
# 启用 SSH 保护
enabled = true
# SSH 服务的监听端口:确保这里设置为您的自定义端口 22122
port = 22122
# 日志文件路径:Debian/Ubuntu/CentOS 通常使用 auth.log,默认配置会自动检测。
# logpath = /var/log/auth.log
# filter:使用默认的 sshd 过滤器(无需修改)
# filter = sshd

启动 Fail2ban#

Terminal window
sudo systemctl enable fail2ban
sudo systemctl restart fail2ban

检查配置#

Terminal window
sudo fail2ban-client status sshd
sudo fail2ban-client status

如果输出显示 Jail status: ... Status: running,在 Jail list 中看到了 sshd,应该就配置成功了。

配置 UFW 防火墙#

安装 ufw#

Terminal window
sudo apt install ufw

设置默认策略#

默认拒绝所有传入/入站连接

Terminal window
sudo ufw default deny incoming

默认允许所有传出/出站连接

Terminal window
sudo ufw default allow outgoing

现在大多数服务器有 IPv6 公网 IP,启用 IPv6 支持

Terminal window
sudo sed -i 's/IPV6=no/IPV6=yes/' /etc/default/ufw

允许 SSH 传入/入站连接

千万不要忘记 SSH 端口,以免自己被「锁在」UFW 外面!

Terminal window
# 替换为实际 SSH 端口
sudo ufw allow 22122/tcp

Cloudflare 回源访问规则#

Nginx 默认监听端口 80(HTTP) 和 443(HTTPS),要允许 Cloudflare CDN 回源访问,必需将 Cloudflare IP 段添加到 UFW 白名单里。

新建一个 Cloudflare IPs 自动更新脚本

Terminal window
sudo nvim /usr/local/bin/ufw-cf-whitelist

该脚本用于:

  • 移除之前旧的 Cloudflare IP 白名单规则
  • 获取 Cloudflare 最新的 IPv4 和 IPv6 列表
  • 允许列表中每个 IP 段访问 80/443 端口

脚本内容如下:

#!/bin/bash
# Cloudflare 官方 IP 列表
IPV4_URL="https://www.cloudflare.com/ips-v4"
IPV6_URL="https://www.cloudflare.com/ips-v6"
echo "=== 1. 清除现有的 Cloudflare UFW 规则..."
# 清除旧的规则(通过删除带有 "Cloudflare" 注释的规则)
# 注意:UFW 不直接支持注释删除,所以这个步骤需要手动或使用更复杂的工具,
# 这里我们采用简单的清理,如果规则不多,可以手动检查 `ufw status numbered`。
# 更好的方法是在每次运行前删除所有 80/443 的 ALLOW 规则,但风险更高。
# 暂时只删除明确的 Cloudflare 规则,以防万一
# sudo ufw delete allow in on any to any port 80/tcp
# sudo ufw delete allow in on any to any port 443/tcp
echo "=== 2. 下载最新的 Cloudflare IP 范围列表..."
# 使用 tempfile 确保下载的文件安全
IPV4_TEMP=$(mktemp)
IPV6_TEMP=$(mktemp)
curl -s $IPV4_URL -o $IPV4_TEMP
curl -s $IPV6_URL -o $IPV6_TEMP
echo "=== 3. 添加 IPv4 规则 (80/443)..."
while read ip; do
if [[ ! -z "$ip" ]]; then
sudo ufw allow proto tcp from $ip to any port 80 comment 'Cloudflare IPv4 HTTP'
sudo ufw allow proto tcp from $ip to any port 443 comment 'Cloudflare IPv4 HTTPS'
fi
done < $IPV4_TEMP
echo "=== 4. 添加 IPv6 规则 (80/443)..."
while read ip; do
if [[ ! -z "$ip" ]]; then
sudo ufw allow proto tcp from $ip to any port 80 comment 'Cloudflare IPv6 HTTP'
sudo ufw allow proto tcp from $ip to any port 443 comment 'Cloudflare IPv6 HTTPS'
fi
done < $IPV6_TEMP
echo "=== 5. 清理临时文件..."
rm $IPV4_TEMP $IPV6_TEMP
echo "=== 6. 完成 Cloudflare 白名单配置。"
ufw status numbered

赋予脚本可执行权限

Terminal window
sudo chmod +x /usr/local/bin/ufw-cf-whitelist

执行脚本,更新 ufw 规则

Terminal window
sudo ufw-cf-whitelist

启动 ufw 服务#

Terminal window
sudo ufw enable
sudo ufw reload

若是提示:

Terminal window
Command may disrupt existing ssh connections. Proceed with operation (y|n)?

检查 ufw 规则#

Terminal window
sudo ufw status numbered

计划任务#

实际上 Cloudflare IP 段几乎很少变动(最起码最近两年多完全没有变化),因此这个步骤不是必须的。使用 Crontab 计划:

Terminal window
sudo crontab -e

比如每天凌晨 3 点执行一次

Terminal window
0 3 * * * /usr/local/bin/ufw-cf-whitelist.sh > /dev/null 2>&1

防止 Docker 在 UFW 上打洞#

Docker 容器的网络,如果没有做到最佳实践,它是可以在 ufw 上「打洞」的(本质是 iptables),详情可见 chaifeng/ufw-docker

这个 check-if-docker-break-ufw.sh 脚本用于检查是否出现了这种情况

check-docker-ports.sh
#!/usr/bin/env bash
# ===============================================================
# 检查 Docker 容器端口暴露与 UFW 状态
# ===============================================================
RED="\033[0;31m"
GREEN="\033[0;32m"
YELLOW="\033[1;33m"
RESET="\033[0m"
echo "🔍 正在检查 Docker 端口暴露情况..."
echo "=============================================================="
# 获取 docker ps 输出
docker_ps=$(docker ps --format '{{.Names}}|{{.Ports}}')
if [ -z "$docker_ps" ]; then
echo "❌ 没有正在运行的容器。"
exit 0
fi
printf "%-25s %-25s %-20s\n" "容器名" "绑定地址" "状态"
echo "--------------------------------------------------------------"
while IFS='|' read -r name ports; do
if [[ -z "$ports" ]]; then
printf "%-25s %-25s ${GREEN}%-20s${RESET}\n" "$name" "无对外端口" "安全"
continue
fi
# 分析每个映射
for port in $(echo "$ports" | tr ',' '\n'); do
port=$(echo "$port" | sed 's/ //g')
if [[ "$port" =~ 0\.0\.0\.0 ]]; then
printf "%-25s %-25s ${RED}%-20s${RESET}\n" "$name" "$port" "⚠️ 公网暴露"
elif [[ "$port" =~ 127\.0\.0\.1 ]]; then
printf "%-25s %-25s ${GREEN}%-20s${RESET}\n" "$name" "$port" "本机安全"
else
printf "%-25s %-25s ${YELLOW}%-20s${RESET}\n" "$name" "$port" "内部网络"
fi
done
done <<< "$docker_ps"
echo "--------------------------------------------------------------"
echo "🧱 检查宿主机端口监听状态..."
ss -tlnp | grep -E 'docker|LISTEN' | awk '{print $4, $6}' | sed 's/users://g' | sed 's/"//g' | sed 's/,//g' | sed 's/\[::\]://g'
echo "--------------------------------------------------------------"
echo "🧩 检查 UFW 规则..."
sudo ufw status numbered
echo "=============================================================="
echo "✅ 检查完成。绿色=安全,黄色=内部安全,红色=公网暴露。"

最简单的方式,不要将任何 Docker 容器的端口绑定到 0.0.0.0 上,只需将暴露端口绑定到 127.0.0.1 上即可。

(完)

新到手的 Linux 服务器,我这样设置
https://www.oferry.com/posts/a16/
作者
晨平安
发布于
2025-11-20
许可协议
CC BY-NC-SA 4.0
封面
示例歌曲
示例艺术家
封面
示例歌曲
示例艺术家
0:00 / 0:00