主题
Linux
服务
开发与运维工具
| 服务名称 | 评价 | 内存占用 | 适用场景 |
|---|---|---|---|
| VS Code Server | 远程 Web IDE ,支持多人协作 | 中等 | 团队开发 |
| Docker | 轻量容器化,快速部署 | 低 | 微服务/测试环境 |
| Minikube | 本地 K8s 集群,开发测试用 | 高 | Kubernetes 学习 |
| GitLab Runner | 持续集成/交付代理 | 中等 | CI/CD 流水线 |
| Jenkins | 自动化构建工具,插件丰富 | 高 | 复杂构建任务 |
| PostgreSQL | 开源关系型数据库,扩展性强 | 中等 | 数据存储 |
| Redis | 内存数据库,超低延迟 | 低 | 缓存/消息队列 |
| MySQL | 经典关系型数据库 | 中等 | 传统应用 |
| MongoDB | 文档数据库,JSON 友好 | 中等 | NoSQL 需求 |
| Prometheus | 监控告警系统,时序数据 | 低 | 服务监控 |
| Grafana | 可视化仪表板,对接多数据源 | 低 | 监控展示 |
| Portainer | Docker 图形化管理工具 | 低 | 容器运维 |
| Nginx | 高性能 Web 服务器/反向代理 | 极低 | 静态站点/API 网关 |
| Apache | 传统 Web 服务器,模块化 | 低 | 兼容旧项目 |
| Node.js | JavaScript 运行时,事件驱动 | 低 | 全栈开发 |
| Python Flask | 轻量级 Web 框架 | 低 | 快速 API 开发 |
| Elasticsearch | 全文搜索引擎,分布式 | 高 | 日志分析/搜索服务 |
| RabbitMQ | 消息队列,AMQP 协议支持 | 中等 | 异步任务处理 |
| Hugo | 静态网站生成器,极速构建 | 极低 | 博客/文档站点 |
媒体与家庭服务
| 服务名称 | 评价 | 内存占用 | 适用场景 |
|---|---|---|---|
| Jellyfin | 开源媒体服务器,硬件加速 | 中等 | 家庭影库 |
| Plex | 商业媒体服务器,客户端丰富 | 中等 | 流媒体共享 |
| Homebridge | 非 HomeKit 设备接入苹果生态 | 低 | 智能家居中枢 |
| Home Assistant | 全能智能家居平台,自动化强 | 中等 | 复杂智能场景 |
| Pi-hole | 网络级广告拦截,DNS 过滤 | 极低 | 全家去广告 |
| AdGuard Home | 替代 Pi-hole ,支持 DoH/DoT | 低 | 隐私保护 |
| Calibre | 电子书管理服务器 | 低 | 个人数字图书馆 |
| Audiobookshelf | 有声书管理,支持多端同步 | 低 | 有声书爱好者 |
| Photoprism | 私有云相册,AI 分类 | 中等 | 照片备份与管理 |
| Nextcloud | 自建云盘,替代 Google Drive | 高 | 文件同步/协作 |
网络与安全
| 服务名称 | 评价 | 内存占用 | 适用场景 |
|---|---|---|---|
| OpenWRT | 旁路由功能,科学上网/广告过滤 | 低 | 网络优化 |
| Tailscale | 零配置内网穿透,WireGuard 协议 | 极低 | 远程访问 |
| Zerotier | 虚拟局域网,跨网络组网 | 极低 | 异地设备互联 |
| Nginx Proxy | 反向代理管理器,自动 SSL | 低 | 多服务域名暴露 |
| Traefik | 动态反向代理,支持容器 | 低 | 微服务网关 |
| Fail2Ban | 防暴力破解,自动封禁 IP | 极低 | 服务器安全 |
| WireGuard | 轻量级 VPN ,高性能 | 极低 | 加密通信 |
| Squid | HTTP 代理缓存,加速访问 | 中等 | 内网加速 |
| Snort | 网络入侵检测系统 | 高 | 安全监控 |
| Gitea | 轻量 Git 服务,替代 GitLab | 低 | 私有代码托管 |
自动化与工具
| 服务名称 | 评价 | 内存占用 | 适用场景 |
|---|---|---|---|
| Homer | 导航首页,聚合服务链接 | 极低 | 服务入口统一 |
| Uptime Kuma | 服务可用性监控,通知告警 | 低 | 运维监控 |
| Wiki.js | 知识库系统,Markdown 支持 | 中等 | 团队文档 |
| BookStack | 结构化文档管理 | 中等 | 技术手册 |
| Bitwarden | 密码管理器,自托管版 | 低 | 密码安全 |
| Vaultwarden | Bitwarden 轻量替代 | 极低 | 低资源密码管理 |
| ntfy | 推送通知服务,跨平台 | 极低 | 消息提醒 |
| Gotify | 简易消息推送服务器 | 极低 | 自定义通知 |
| Radarr | 电影自动下载管理 | 中等 | PT 爱好者 |
| Sonarr | 剧集自动下载管理 | 中等 | 追剧自动化 |
实验性/高阶服务
| 服务名称 | 评价 | 内存占用 | 适用场景 |
|---|---|---|---|
| LLM Local | 本地运行 Llama 3 等大模型 | 极高 | AI 实验 |
| Stable Diffusion | 本地 AI 绘图,依赖 GPU 加速 | 高 | 图像生成 |
| Ollama | 简化版本地 LLM 管理工具 | 中等 | 轻量 AI 开发 |
| IPFS | 分布式存储节点 | 中等 | Web3 开发 |
| Ethereum | 以太坊轻节点 | 高 | 区块链开发 |
| Folding@Home | 分布式计算贡献算力 | 极高 | 科研公益 |
| Kasm | 容器化桌面环境,远程隔离 | 高 | 安全沙箱 |
| CyberChef | 数据编解码 Web 工具 | 低 | 安全分析 |
| Grafana Loki | 日志聚合系统,轻量替代 ELK | 中等 | 集中式日志 |
| Meilisearch | 极速全文搜索引擎 | 低 | 替代 Elasticsearch |
总结建议
- 优先选择:Docker 容器化部署(节省资源)
- 内存敏感:限制单服务内存(如
docker run --memory 2g) - 性能瓶颈:避免同时运行 3 个以上高内存服务(如 LLM+DB+媒体转码)
通过合理分配,16GB 内存可同时承载约 10-15 个中低负载服务。
Debian系统上实现无需客户端配置的本地域名解析
Debian系统上可以使用mDNS(Multicast DNS)和Avahi服务来实现无需客户端额外配置就能通过子域名访问资源的功能。这种方式适用于本地网络环境,让设备可以通过类似 blog.wlg.local 、 api.wlg.local 这样的域名自动发现服务。
实现方案
1. 安装Avahi服务
sudo apt update
sudo apt install avahi-daemon avahi-utils2. 配置Nginx虚拟主机
sudo apt install nginx为每个子域名创建Nginx虚拟主机配置:
server {
listen 80;
server_name blog.wlg.local;
root /var/www/blog;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
server {
listen 80;
server_name api.wlg.local;
root /var/www/api;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}3. 配置Avahi服务发布
创建服务发布文件:
sudo nano /etc/avahi/services/nginx-http.service添加以下内容:
<?xml version="1.0" standalone="no"?>
<!DOCTYPE service-group SYSTEM
"avahi-service.dtd">
<service-group>
<name>Web Services</name>
<service>
<type>_http._tcp</type>
<port>80</port>
<host-name>blog.wlg.local</host-name>
</service>
<service>
<type>_http._tcp</type>
<port>80</port>
<host-name>api.wlg.local</host-name>
</service>
</service-group>4. 重启服务
sudo systemctl restart avahi-daemon
sudo systemctl restart nginx客户端访问
对于同一网段内的客户端:
Linux客户端 :通常已预装Avahi客户端,可直接访问 http://blog.wlg.local 或 http://api.wlg.local
macOS客户端 :原生支持mDNS,可直接访问这些域名
Windows客户端 :
- Windows 10/11可能需要安装Bonjour服务
- 或者使用 .local 域名访问
注意事项
- 这种方案仅适用于本地网络环境,不适用于公网
- 某些网络环境可能会阻止mDNS多播包
- 域名应使用 .local 后缀,这是mDNS的标准做法 如果需要更复杂的设置或公网访问,可能需要考虑配置本地DNS服务器。
概要
本文介绍每次上手一台新的 Linux 服务器后,我的一些 基本设置步骤,包括:
- 使用一键 DD 脚本重装纯净的 Debian GNU/Linux 操作系统
- SSH 安全和 Fail2ban 设置
- 配置 UFW 防火墙
- 安装 Nginx Web 服务器
- 安装 Docker CE 及必要插件
- 使用 Cloudflare CDN 保护服务和全球加速
并不一定适合所有人的需求,仅作为我每次快速设置新服务器的速查手册。建议搭配以下内容一起使用:
重装系统
选择脚本
网络上支持一键 DD 重装系统的脚本有很多,我主要使用这两个:
前者支持的系统选择更多,后者则专注于 Debian GNU/Linux 的最小发行版。两者都在 GitHub 上开源,且经过长期的社区关注和审查,安全性大可以放心。
无论如何,在正式开始之前,仔细阅读一遍脚本作者的说明(文档说明详细易读),知道自己在做什么,预期会出现什么。
我在所有服务器上都一直使用 Debian,下面以 debi 脚本为例。
下载脚本
bash
curl -fLO https://raw.githubusercontent.com/bohanyang/debi/master/debi.sh执行脚本
赋予脚本可执行权限
bash
chmod +x debi.sh开始重装系统
bash
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 拥塞控制算法),提升网络在高延迟或跨国网络环境下传输性能
一切就绪,开始重装系统
bash
sudo reboot期间你可以使用 VNC 查看系统安装进度,根据服务器性能或网络环境,稍等几分钟,新的系统即将就绪。之后,使用重装阶段预设的用户名密码或 SSH 密钥登录服务器。
安装常用软件包
我们的服务器正在运行的是一个纯净、最小、最新的 Debian GNU/Linux 操作系统,需要安装一些基础或常用的软件包。
基本工具包
bash
sudo apt update
sudo apt install \
ca-certificates \
apt-transport-https \
man \
build-essential \
git \
curl \
wget \
unzip \
screen \
btop \
net-tools \
tree \
neovim安装 Docker
参考 Docker 官方文档 说明的步骤,下列命令不保证时效性
bash
# 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 上的 安装步骤
bash
# 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设置默认虚拟主机,用于拒绝恶意访问及域名 Fallback 解析
bash
sudo nvim /etc/nginx/conf.d/00-default.conf建议使用自签或 Cloudflare 源服务器 TLS/SSL 证书
nginx
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
return 444;
}
server {
listen 443 ssl default_server;
listen [::]:443 ssl default_server;
server_name _;
ssl_certificate /path/to/your/cert.pem;
ssl_certificate_key /path/to/your/key.pem;
return 444;
}重载 Nginx 配置
bash
sudo nginx -t
sudo nginx -s reload设置 Swap
一般而言,swap 设置为 RAM 大小即可,** 适当 **的 swap 在一定程度上避免 Linux 内核 OOM。这里我们通过设置 Swap File 的方式,它更加灵活。
bash
# check swap status, there should be no output
sudo swapon --show
# ------
# create a swapfile equal to RAM
# my vds has a 8GB RAM
sudo fallocate -l 8G /swapfile
# or instead of fallocate,
# use dd command
# 8192 * 1MB = 8GB
sudo dd if=/dev/zero of=/swapfile bs=1M count=8192
# ------
# set permission
sudo chmod 600 /swapfile
# format a swap area
sudo mkswap /swapfile
# enable swapfile
sudo swapon /swapfile
# check swap file
sudo swapon --show
free -h
# update fstab auto mount when linux started
sudo nano /etc/fstab
# add following line to end
/swapfile none swap sw 0 0
# check fstab
sudo mount -aLinux 还有一个 swappiness 配置,用于控制系统对 swap 的倾向,感兴趣可以自行 Google 一下。
NTP 同步
可以看到当前的服务器是没有 NTP 同步时间的
bash
timedatectl
Local time: Sat 2025-11-29 06:41:13 UTC
Universal time: Sat 2025-11-29 06:41:13 UTC
RTC time: Sat 2025-11-29 06:41:29
Time zone: UTC (UTC, +0000)
System clock synchronized: no
NTP service: n/a
RTC in local TZ: no以使用 Chrony 客户端,配置 Cloudflare 的 NTP 服务器 来确保系统时间与 UTC 精准同步为例
bash
sudo apt update
sudo apt install chrony修改 NTP 服务器
bash
sudo nvim /etc/chrony/chrony.conf注释或删除默认的 pool 及 server 行(例如 pool 2.debian.pool.ntp.org iburst),在文件开头或 server 部分,添加以下四行:
bash
server time.cloudflare.com iburst
server time.cloudflare.com iburst
server time.cloudflare.com iburst
server time.cloudflare.com iburst启动 Chrony 服务
bash
sudo systemctl enable chrony
sudo systemctl restart chrony验证
bash
timedatectl
Local time: Sat 2025-11-29 06:43:52 UTC
Universal time: Sat 2025-11-29 06:43:52 UTC
RTC time: Sat 2025-11-29 06:43:53
Time zone: UTC (UTC, +0000)
System clock synchronized: yes
NTP service: active
RTC in local TZ: noSSH 基本加固
编辑 SSH 配置文件
bash
sudo nvim /etc/ssh/sshd_config这里有一些我们需要关注的配置项目:
Port 22122SSH 服务监听的默认端口,我们已在重装脚本中指定
PermitRootLogin no禁止 Root 用户直接登录,使用普通用户登录,使用 sudo 提权
PasswordAuthentication no禁止使用密码登录 SSH,我们应当使用密钥对或实体安全密钥(如 Yubikey、Canokey 等)进行登
PermitEmptyPasswords no禁止空密码登录ChallengeResponseAuthentication no禁用键盘交互式密码认证PubkeyAuthentication yes启用公钥认证,此前已在重装脚本中指定UseDNS no禁用 DNS 反查X11Forwarding no禁用 X11 转发,如果你不知道这是什么那就可以禁用
保持当前的 SSH 会话不要断开连接,重启 SSH 服务
bash
sudo systemctl restart sshd重开一个 SSH 会话,再次登录当前服务器,确保连接正常,否则返回第一个 SSH 会话中进行检查。
配置 Fail2ban
使用 Fail2ban 保护我们的服务器免受 SSH 爆破,并合理封禁异常的 IP 地址
安装 Fail2ban
bash
sudo apt update
sudo apt install fail2banSSH 守护配置
创建一个最小的,仅用于守护 SSH 登录的 Fail2ban 配置文件
bash
sudo nvim /etc/fail2ban/jail.local配置内容如下:
toml
[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
bash
sudo systemctl enable fail2ban
sudo systemctl restart fail2ban检查配置
bash
sudo fail2ban-client status sshd
sudo fail2ban-client status如果输出显示 Jail status: ... Status: running,在 Jail list 中看到了 sshd,应该就配置成功了。
配置 UFW 防火墙
安装 ufw
bash
sudo apt install ufw设置默认策略
默认拒绝所有传入/入站连接
bash
sudo ufw default deny incoming默认允许所有传出/出站连接
bash
sudo ufw default allow outgoing现在大多数服务器有 IPv6 公网 IP,启用 IPv6 支持
bash
sudo sed -i 's/IPV6=no/IPV6=yes/' /etc/default/ufw允许 SSH 传入/入站连接
千万不要忘记 SSH 端口,以免自己被「锁在」UFW 外面!
bash
# 替换为实际 SSH 端口
sudo ufw allow 22122/tcpCloudflare 回源访问规则
Nginx 默认监听端口 80(HTTP) 和 443(HTTPS),要允许 Cloudflare CDN 回源访问,必需将 Cloudflare IP 段添加到 UFW 白名单里。
新建一个 Cloudflare IPs 自动更新脚本
bash
sudo nvim /usr/local/bin/ufw-cf-whitelist该脚本用于:
- 移除之前旧的 Cloudflare IP 白名单规则
- 获取 Cloudflare 最新的 IPv4 和 IPv6 列表
- 允许列表中每个 IP 段访问 80/443 端口
脚本内容如下:
bash
#!/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赋予脚本可执行权限
bash
sudo chmod +x /usr/local/bin/ufw-cf-whitelist执行脚本,更新 ufw 规则
bash
sudo ufw-cf-whitelist启动 ufw 服务
bash
sudo ufw enable
sudo ufw reload若是提示:
bash
Command may disrupt existing ssh connections. Proceed with operation (y|n)?检查 ufw 规则
bash
sudo ufw status numbered计划任务
实际上 Cloudflare IP 段几乎很少变动(最起码最近两年多完全没有变化),因此这个步骤不是必须的。使用 Crontab 计划:
bash
sudo crontab -e比如每天凌晨 3 点执行一次
bash
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 脚本用于检查是否出现了这种情况
bash
#!/usr/bin/env bash
# ===============================================================
# check-docker-ports.sh
# 检查 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 上即可。
检查 Nginx 日志
Cloudflare IP 段是纯网段,检查时需要做 CIDR 运算,这里使用 ipcalc 和 sipcalc
bash
sudo apt install ipcalc sipcalc下面是一个巡检脚本,用于检查所有的 Nginx 虚拟主机的访问日志中的 IP 是否属于 Cloudflare IPs
bash
#!/usr/bin/env bash
set -u
NGINX_DIR="/var/log/nginx"
RECENT_LINES=2000
TMP_CF="/tmp/cf_all_ips.txt"
TMP_LOG="/tmp/nginx_logs_combined.txt"
cleanup(){
rm -f "$TMP_CF" "$TMP_LOG"
}
trap cleanup EXIT
echo "=== 获取 Cloudflare IPv4/IPv6 列表… ==="
curl -s https://www.cloudflare.com/ips-v4/ > "$TMP_CF"
curl -s https://www.cloudflare.com/ips-v6/ >> "$TMP_CF"
if [ ! -s "$TMP_CF" ]; then
echo "❌ 失败:无法获取 Cloudflare IP 列表"
exit 1
fi
echo "Cloudflare IP 段已加载:"
wc -l "$TMP_CF"
echo ""
echo "=== 收集 Nginx 日志… ==="
mapfile -d $'\0' LOGS < <(find "$NGINX_DIR" -maxdepth 1 -type f \( -iname "*access.log" -o -iname "*.log" -o -iname "*.gz" \) -print0)
if [ ${#LOGS[@]} -eq 0 ]; then
echo "未找到任何 Nginx access 日志"
exit 0
fi
# 合并最近日志
> "$TMP_LOG"
for LOG in "${LOGS[@]}"; do
if [[ "$LOG" =~ \.gz$ ]]; then
zcat "$LOG" 2>/dev/null >> "$TMP_LOG"
else
cat "$LOG" 2>/dev/null >> "$TMP_LOG"
fi
done
echo "合并日志完成:$(wc -l < "$TMP_LOG") 行"
echo ""
###################################
# 提取最近访问 IP 并对比 CF
###################################
echo "=== 检查最近 $RECENT_LINES 行访问中非 Cloudflare IP ==="
# 提取 IP
tail -n "$RECENT_LINES" "$TMP_LOG" | awk '{print $1}' | sort -u > /tmp/nginx_ips.txt
echo ""
echo "开始比对..."
# 逐个判断是否属于 CF 段
NON_CF_IPS=()
while read -r ip; do
if ! grep -qE "^$(echo "$ip" | sed 's/\./\\./g')(/|$)" "$TMP_CF"; then
# 不是直接文本匹配,而是 CIDR 检查
match=""
while read -r cidr; do
if [[ "$cidr" == *.* ]]; then
# IPv4 CIDR check
if ipcalc -c "$ip" "$cidr" >/dev/null 2>&1; then
match="1"
break
fi
else
# IPv6 CIDR
if sipcalc "$ip" "$cidr" >/dev/null 2>&1; then
match="1"
break
fi
fi
done < "$TMP_CF"
if [ -z "$match" ]; then
NON_CF_IPS+=("$ip")
fi
fi
done < /tmp/nginx_ips.txt
echo ""
if [ ${#NON_CF_IPS[@]} -eq 0 ]; then
echo "✔ 没有发现绕过 Cloudflare 的 IP(全部访问来自 Cloudflare)"
else
echo "⚠ 检测到 **非 Cloudflare** 源站访问(注意安全):"
printf '%s\n' "${NON_CF_IPS[@]}"
fi
echo ""
echo "=== 检查完成,临时文件已删除 ✔ ==="示例效果:
bash
sudo ./check-security.sh
=== 获取 Cloudflare IPv4/IPv6 列表… ===
Cloudflare IP 段已加载:
20 /tmp/cf_all_ips.txt
=== 收集 Nginx 日志… ===
合并日志完成:26384 行
=== 检查最近 2000 行访问中非 Cloudflare IP ===
开始比对...
✔ 没有发现绕过 Cloudflare 的 IP(全部访问来自 Cloudflare)
=== 检查完成,临时文件已删除 ✔ ===(完)