---
url: /blog/m76wyire/index.md
description: >-
  鸽了这么久的文章，之前说在写了在写了，到时候会发出来；现在终于完善最后一下，是时候该结束了。本文亦同步发布在我的博客上，恭候光临~
  前言之前我在四月底复活节活动买了 netcup 的 RS 1000 G11 iv SE NUE OS…
---
[焕昭君](https://linux.do/u/huan) [huan](https://linux.do/u/huan) 不二之选

鸽了这么久的文章，之前说在写了在写了，到时候会发出来；现在终于完善最后一下，是时候该结束了。本文亦同步发布在 [**我的博客**](https://blog.huan666.de/posts/server-website-getting-started/) 上，恭候光临~

## 前言

之前我在四月底复活节活动买了 [**netcup**](https://www.netcup.com/en) 的 **RS 1000 G11 iv SE NUE OST25** 的 VDS 服务器 4C8G512GB。

详细配置

* **4 dedicated** cores - AMD EPYC™ 9634
* **8 GB** DDR5 ECC RAM
* **512 GB** NVMe SSD
* **2.5 Gbps** Bandwidth - **Unlimited** network traffic
* Location: **Nuremberg, Germany**
* DDOS protection: 2 Tbit/s

光有了自己的第一个服务器才刚刚开始，接下来开始大张旗鼓地折腾和配置了，我搜集各类教程自己边折腾边记录整理了以下这篇文章内容。

本文概要

* **从零开始** ，由浅入深地介绍配置服务器到网站上线的全流程指南。本文涵盖了终端软件选择、SSH配置、系统优化、安全加固、Docker和Nginx部署、域名和Cloudflare配置等核心内容。
* **实操性强** ：包含大量命令行示例、配置文件范例和一键脚本，能够直接复制使用。
* **内容详细** ：文章内容层次分明，逻辑清晰。不仅告诉你"怎么做"，还解释"为什么"。引用大量参考文献，便于更深入研究
* **解决常见痛点** ：SSH安全加固、VSCode增强远程连接、docker与ufw防火墙兼容、彻底隐藏源站IP、从Cloudflare获取原始访客IP等等

[![服务器与网站的开荒入坑](./assets/服务器与网站的开荒入坑%20-%20文档共建/b6dcb02fbb0eb4472b67b6515046064321700114.webp)](https://blog.huan666.de/images/%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%B8%8E%E7%BD%91%E7%AB%99%E7%9A%84%E5%BC%80%E8%8D%92%E5%85%A5%E5%9D%91.svg)

## 终端软件

为了更好使用命令行和 SSH 连接服务器管理，一个好的终端软件必不可少。以下推荐几个软件（个人主观次序排名）：

## Tabby

[官网地址](https://tabby.sh/) 和 [GitHub地址](https://github.com/eugeny/tabby)

* 开源免费
* 简洁 **美观**
* 支持SSH和SFTP
* 用于纯命令行很舒服，该有功能不少，没有太多繁杂的花里胡哨，看着也美观舒心。

[![Tabby](./assets/服务器与网站的开荒入坑%20-%20文档共建/a6b8cb7d8171500fcafbcdab8b4902d8a318a9f9_2_690x458.png)](https://cdn3.linux.do/original/4X/a/6/b/a6b8cb7d8171500fcafbcdab8b4902d8a318a9f9.png "Tabby")

## FinalShell

[官网地址](https://www.hostbuf.com/)

* 闭源+基础免费/增值付费
* 简洁，简单显示必要信息
* 支持SSH和SFTP
* 特点：底部有命令输出框和 **方便使用的SFTP**

[![FinalShell](./assets/服务器与网站的开荒入坑%20-%20文档共建/22c1fb485dd5e5a9e8771f9c825516d41c206c2b_2_622x500.jpeg)](https://cdn3.linux.do/original/4X/2/2/c/22c1fb485dd5e5a9e8771f9c825516d41c206c2b.jpeg "FinalShell")

## Termora

[官网地址](https://www.termora.app/) [GitHub地址](https://github.com/TermoraDev/termora)

* 开源免费
* **极简**
* 支持SSH和SFTP
* 比上面的Tabby简陋，喜欢极简的可以尝试。

[![termora](./assets/服务器与网站的开荒入坑%20-%20文档共建/63778db5ae7e23a9b87f2442315b260ab171ccac_2_690x431.png)](https://cdn3.linux.do/original/4X/6/3/7/63778db5ae7e23a9b87f2442315b260ab171ccac.png "termora")

## Termius

[官网地址](https://termius.com/)

* **没有简体中文**
* 闭源+大部分功能 **收费** (如代理设置)
* **多端数据同步** ，无缝切换
* 现代化UI、高颜值

如果愿意付费的话，亦是一个不错的选择。

[![termius](./assets/服务器与网站的开荒入坑%20-%20文档共建/649a0a539edf85ecec076058041d0c5752454ea3_2_690x362.png)](https://cdn3.linux.do/original/4X/6/4/9/649a0a539edf85ecec076058041d0c5752454ea3.png "termius")

## Xterminal

[官网地址](https://www.terminal.icu/)

* 闭源+基础免费/增值付费(换肤要钱)
* 功能丰富，但也非常 **繁杂和花里胡哨** ，一般我不用。

[![img](./assets/服务器与网站的开荒入坑%20-%20文档共建/29ce19d4412c5e9fdf24dcf3a6046630adc1e2da_2_690x421.png)](https://cdn3.linux.do/original/4X/2/9/c/29ce19d4412c5e9fdf24dcf3a6046630adc1e2da.png "img")

**参考文章** ：\
[SSH 客户端收集 - 砖头@runbrick - LINUX DO](https://linux.do/t/topic/489989)\
其他的，在这篇文章有人搜集了很多客户端软件

## SSH远程连接

阅读完前面相信你已经选上一个好的软件用于 SSH 来连接你的服务器了吧。想要使用 SSH 连接服务器首先要知道以下这几个概念：

* **主机地址** ：即 `IP地址` 或 `域名`
* **端口** ：默认是 `22` ，但你的服务商可能有所不同，还有网络策略组会限制端口放行。默认端口数字不安全， [下文](https://blog.huan666.de/posts/server-website-getting-started/#%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6) 会介绍到如何修改端口
* **用户** ：登录的用户，默认一般是 `root` ，这通常 **不安全** ， [下文](https://blog.huan666.de/posts/server-website-getting-started/#%E6%B7%BB%E5%8A%A0%E6%96%B0%E7%94%A8%E6%88%B7) -系统安全配置会详细介绍怎么修改用户。
* **密码密钥** ：验证登录所需。常见是直接使用密码，但不安全，后续会关闭密码而使用密钥

尽管软件提供可视化页面方便操作，但接下来我会展示 **命令** 操作，概念原理是一致的，理解了命令其他就简单了。

## 基础命令

```bash
#默认22端口连接
ssh <user>@<HostIP>
ssh <user>@<HostName>
#指定端口连接
ssh <user>@<HostName> -p <port>
#指定密钥文件
ssh <user>@<HostName> -p <port> -i <filePath>
```

## 密钥登录

### 1、生成公私密钥对

选取 **ed25519** \[[这是什么？- Gemini深度研究](https://docs.google.com/document/d/1mATNYwg9FxOYZisbLvnSUtsoOHe1Y6BnOQ1ATtljhJI/edit?usp=sharing)] 这个现代安全且高效的加密算法，在自己电脑生成密钥对。

> Warning
>
> **注意** ：如果之前有生成过密钥对或者用过其他的SSH服务如GitHub免密登录， **小心密钥对被覆盖导致失效！** 请使用 `-f` 指定路径和文件名

```bash
ssh-keygen -t ed25519

#指定文件名
ssh-keygen -t ed25519 -f ~/.ssh/my_key_ed25519
#或在Windows PowerShell下使用：
ssh-keygen -t ed25519 -f $HOME\.ssh\my_key_ed25519

#添加注释
ssh-keygen -t ed25519 -f $HOME\.ssh\my_key_ed25519 -C "注释"
#为密钥设置密码
ssh-keygen -t ed25519 -f $HOME\.ssh\my_key_ed25519 -N "your_passphrase" -C "your_email@example.com"
```

然后就会生成 **私钥** `id_ed25519` 和 **公钥** `id_ed25519.pub` ，把公钥上传到服务器。

### 2、上传公钥

两种方式，一是 **命令自动** 上传、二是 **手动编辑** ，无论哪种方法最终是要把公钥追加保存在 **对应用户主目录的** `~/.ssh/authorized_keys` 文件。

#### ssh-copy-id 命令

```bash
#Linux、macOS
ssh-copy-id -i key_file user@host
```

很遗憾，window并不直接支持。

#### 编辑 authorized\_keys 文件

1.手动编辑：

```bash
mkdir ~/.ssh
vi ~/.ssh/authorized_keys 或 echo "<复制的公钥粘贴到这里>" >> ~/.ssh/authorized_keys
```

**或者** 自动上传编辑：

```bash
#在windows下(但追加的密钥的中文注释会乱码)
type $HOME\.ssh\filename.pub -Encoding UTF8 | ssh user@host "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
#Linux或macOS
cat ~/.ssh/filename.pub | ssh user@host "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys
```

**2.设置权限**

```bash
chown -R username:somegroup ~/.ssh #设置文件所有者(如果配置者和所有者不同)
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
#查看权限
ls -ld ~/.ssh
ls -l ~/.ssh/authorized_keys
```

### 3、进行连接

```bash
#指定客户端本机的对应私钥文件
ssh <user>@<HostName> -p <port> -i <filePath>
```

更多操作比如 **关闭密码登录** 等具体看 **配置文件** 的设置

## 日志查看：

```bash
#系统使用Systemd，可以使用journalctl命令查看日志
journalctl -u ssh
journalctl -u ssh | code - #使用VSCode打开缓存的日志
```

查看最近一天的SSH日志并统计处理缓存输出到VSCode（去掉 `| code -` 直接输出到命令行）

```bash
(
  CMD="sudo journalctl -u ssh -r --since -1d"
  echo "=== 密码失败登录尝试总数 ==="
  $CMD | grep "Failed password" | wc -l
  echo -e "\n=== 其他登录错误总数 ==="
  $CMD | grep "error:" | wc -l
  echo -e "\n=== 按 IP 统计密码失败尝试 ==="
  $CMD | grep "Failed password" | awk '{print $(NF-3)}' | sort | uniq -c | sort -nr
  echo -e "\n=== 按 IP 统计其他错误尝试 ==="
  $CMD | grep "error:" | awk '{for(i=1;i<=NF;i++) if($i ~ /^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/) {print $i; break}}' | sort | uniq -c | sort -nr
  echo -e "\n=== 按用户名统计的失败尝试 ==="
  $CMD | grep "Failed password" | awk '{for(i=1;i<=NF;i++) if($i=="for") print $(i+1)}' | sort | uniq -c | sort -nr
  echo -e "\n=== 最近25次失败尝试 ==="
  $CMD | grep -E "(Failed password|error:)" | tail -25
) | code -
```

## 配置文件

SSH的配置文件不仅有服务端，还有客户端的。

### SSH服务端

**SSH服务端** 配置文件路径： `/etc/ssh/sshd_config` ，注意是否有 `/etc/ssh/sshd_config.d` 文件夹下配置覆盖生效。

想要密钥连接确保以下配置设置（一般默认不用改）

```bash
#PubkeyAuthentication yes
#AuthorizedKeysFile    .ssh/authorized_keys
```

**关闭密码登录**

> Caution
>
> **警告！！！关闭前请确保你能密钥登录成功！妥善保管好私钥！以防云服务器失联！**

```bash
PasswordAuthentication no
```

**重启和应用服务端配置文件**

```shell
#1.测试配置文件是否有语法错误
sudo sshd -t

#2.使用systemctl 重启 SSH 服务
sudo systemctl restart sshd
#或
sudo systemctl restart ssh
#或老旧系统使用service
sudo service sshd restart

#3.验证重启是否成功-检查 SSH 服务状态，确保它正在运行
sudo systemctl status sshd
#或
sudo systemctl status ssh
```

### SSH客户端

本地主机的 `~/.ssh` 下还存在 `config` 和信任主机列表 `known_hosts`

`config` 文件举例：

```
Host *
    Port <端口>
    # 每隔 60 秒自动发送一个 keepalive 信号以保持连接
    ServerAliveInterval 60
    # 断开时重试连接的次数
    ServerAliveCountMax 15

Host <自定义别名>
    HostName <服务器地址>
    Port <端口>
    User <用户名>
    IdentityFile <私钥路径>
```

`Host *` 表示对所有主机生效，设置了端口对所有主机配置项都生效。\
`IdentityFile` 指定私钥路径。这下VSCode不用每次远程连接手动输入密码了，自动验证登录。

## VSCode远程连接

只要安装了VSCode [**远程系列插件**](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.vscode-remote-extensionpack) 就能使用 [**VSCode的SSH**](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-ssh-edit) 功能远程连接服务器，有时候不想使用 Vim 或者不熟悉它，就能用”宇宙第一编辑器“──VSCode来查看和编辑服务器的文件了，实在太方便了\
缺点：貌似服务器 **内存占用不低** ， **内存小** 的小鸡很可能 **无法承受** …

[**官方文档**](https://code.visualstudio.com/docs/remote/ssh)

## 测试脚本

整到一台服务器首先要干的事情是什么？当然是立马上鸡测试一下配置！CPU、内存硬盘的性能，IP质量、网络质量等。

**[融合怪测试脚本-GO版本(无环境依赖)](https://github.com/oneclickvirt/ecs)**

```bash
export noninteractive=true && curl -L https://raw.githubusercontent.com/oneclickvirt/ecs/master/goecs.sh -o goecs.sh && chmod +x goecs.sh && bash goecs.sh env && bash goecs.sh install && goecs
```

在 [【存档】Netcup的RS1000硬盘翻倍版的测试和一些测试脚本的使用](https://blog.huan666.de/posts/vps-test/netcup-rs1000-double-storage-version-testing-scripts-guide/) 中我使用过一些测试脚本测试了我的rs1000小鸡，详细可以去看看~

## 重装系统

使用一键DD重装脚本 \[[什么是DD脚本？- Gemini深度研究](https://docs.google.com/document/d/1wdHWNapEaYdcFees7u2UIWR5qXSFEX3y4n--uinG7Qk/edit?usp=sharing)] ，比较出名的有两个：\
① [**leitbogioro/Tools**](https://github.com/leitbogioro/Tools) 和搭配 [黑海洋Wiki](https://blog.upx8.com/4100) 的文章\
② [**bin456789/reinstall**](https://github.com/bin456789/reinstall) 这个更加整洁和方便，直接下载官方源，而且近期有更新。

## bin456789/reinstall：

下载（Linux）：

国外服务器：

```bash
curl -O https://raw.githubusercontent.com/bin456789/reinstall/main/reinstall.sh || wget -O reinstall.sh $_
```

国内服务器：

```bash
curl -O https://cnb.cool/bin456789/reinstall/-/git/raw/main/reinstall.sh || wget -O reinstall.sh $_
```

安装 [**Debian12**](https://www.debian.org/download.zh-cn.html) 改SSH端口和设置 root 密码，仅供参考命令：

```bash
bash reinstall.sh debian 12 --password 你的密码 --ssh-port 你的端口
```

更多请参阅 [GitHub文档](https://github.com/bin456789/reinstall?tab=readme-ov-file#%E5%8A%9F%E8%83%BD-1-%E5%AE%89%E8%A3%85--linux) …\
重装完服务器系统紧接着就是要配置系统了 [Gemini深度研究](https://g.co/gemini/share/546ab1d9deef) 和 [导出文档](https://docs.google.com/document/d/1vGDe2degt-v3lTNM7JHzyB4qKDKVCVN4T1oBwsoOzZc/edit?usp=sharing) 。第一时间就要去修改SSH配置如端口、密码和公私钥设置等和创建非root新用户。

## 系统配置

## 基础优化

### 更新系统的软件包

```bash
apt update && apt upgrade -y
```

### 安装一些常用的基础工具

如sudo、手册、网络、git、文件管理、系统监控、防火墙等，可以方便后续的管理操作

```bash
apt install sudo man-db curl wget telnet iperf3 git vim tree htop ufw -y
```

### 语言、地区和时区

```bash
locale
sudo update-locale LANG=en_US.UTF-8
timedatectl
sudo timedatectl set-timezone Asia/Shanghai
```

### IP地址

**直接查看本地 IPv6 地址**

```bash
ip -6 addr show
```

服务器主要对外网卡的那个IP一般就是本机IPV6了

或简化版：

```bash
ip a | grep inet6
```

你会看到类似：

```bash
inet6 2408:xxxx:xxxx::xx/64 scope global
```

其中 `scope global` 就是你的公网IPv6类型地址（不是 `fe80::...`这类链路本地地址）。

**查询外网看到的 IPv6（公网出口地址）**

使用curl等方式直接访问外网服务：

```bash
curl -6 ifconfig.co
curl -6 ip.sb
curl -6 icanhazip.com
```

### SWAP-虚拟内存

SWAP可以优化内存的使用，延缓内存压力，对于内存小的系统帮助很大。（用一定的硬盘、IO换取内存， **硬盘配置差的小鸡不建议开启** ）\
有两个一键自动脚本：spiritLHLS的 [**addswap**](https://github.com/spiritLHLS/addswap) 和 [**woniu336/open\_shell - swap.sh**](https://github.com/woniu336/open_shell/blob/main/swap.sh) ，根据具体情况 **测验** 后 **谨慎** 使用。下面是说明纯手动配置的方法步骤。

#### 检查现有SWAP

```bash
sudo free -h #查看当前内存
sudo swapon --show    #查看当前启用的SWAP
cat /proc/swaps
```

#### 创建SWAP文件

关于创建SWAP是选择创建 **分区** 还是创建 **文件** ，我最终选择创建 **SWAP文件** 的方式\
因为SWAP分区虽可能性能更好但创建需预留未分配空间来 **硬盘分区** ，操作 **繁琐** ，非常 **不灵活** ，后续调整大小麻烦，有一定 **风险** 。而SWAP文件 **更加灵活** 、可以随时创建、删除或调整大小； **管理方便** ，不需要处理分区表。

```bash
#1️⃣创建一个8GB大小的SWAP文件：
#这个大小根据个人所需自定义，后续也能修改。众说纷纭，有说一半也有说1~2倍，我的服务器8G内存
#\`fallocate\`和\`dd\`命令二选一
sudo fallocate -l 8G /swapfile    #快速预分配磁盘空间，仅支持现代文件系统如ext4、XFS、Btrfs
sudo dd if=/dev/zero of=/swapfile bs=1M count=8192    #(耗时较长)

#2️⃣权限设置
sudo chown root:root /swapfile  # 修改所有者为 root
sudo chmod 600 /swapfile           # 设置权限：仅允许root读写
sudo ls -lh /swapfile              # 检查文件的权限和大小是否符合预期

#3️⃣文件格式化为SWAP
sudo mkswap /swapfile
sudo file /swapfile             # 验证是否为 "Linux swap file"
#4️⃣启用SWAP（目前只是临时的）
sudo swapon /swapfile

#5️⃣永久启用：系统重启时自动激活SWAP：编辑/etc/fstab
#1.备份原文件
sudo cp /etc/fstab /etc/fstab.bak
#2.将SWAP文件配置信息追加到\`/etc/fstab\`文件末尾
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
#3.检查一下
sudo blkid /swapfile
sudo reboot        #重启一下看看是否持久化了

#6️⃣验证
sudo free -h #查看当前内存
sudo swapon --show    #查看当前启用的SWAP
cat /proc/swaps

#7️⃣设置SWAP策略：vm.swappiness值（可选）
#1.查看当前值（默认60）
cat /proc/sys/vm/swappiness
sudo sysctl vm.swappiness
#2.临时更改 (用于测试)：系统重启后失效
sudo sysctl vm.swappiness=40
#3.永久更改 (重启后保持生效)
sudo cp /etc/sysctl.conf /etc/sysctl.conf.bak #备份源文件
echo 'vm.swappiness=40' | sudo tee -a /etc/sysctl.conf
sudo sysctl --system        #显示即将应用的参数（不实际执行），验证配置正确性
sudo sysctl -p                #立即应用内核参数调整
```

#### 修改SWAP大小

**停用 → 删配置 → 删文件**

```bash
#1️⃣停用SWAP
sudo swapoff -a                # 停用所有SWAP
sudo swapoff /swapfile      # 停用SWAP文件：在调整Swap大小或删除前需要先执行此操作
sudo swapon --show          # 确认 Swap 已禁用（无输出或无 /swapfile）
free -h                     # 检查 Swap 是否归零

#2️⃣删除旧文件和删除\`/etc/fstab\`对应配置
#⚠️警告！在删除旧swap文件后请立即移除\`/etc/fstab\`中的配置！避免系统后续意外可能崩溃！
sudo rm /swapfile           # 删除旧文件（确保已禁用 Swap）
sudo sed -i '/\/swapfile/d' /etc/fstab  # 从 /etc/fstab 移除
sudo grep -i swapfile /etc/fstab        # 检查

#3️⃣重复上面👆\`创建SWAP文件\`的操作
```

#### 删除SWAP

重复上面 `修改SWAP大小` 的操作和

#### 额外的关于硬盘与分区？

```bash
#硬盘分区
sudo blkid
lsblk
sudo fdisk -x
df -hT
```

### zRAM - 压缩内存

zRAM 是一种在 RAM 中创建的压缩交换空间，而 SWAP 文件是硬盘上的交换空间。读写性能上 zRAM 在 **内存** 上比SWAP 在硬盘快很多，但需要一定 **CPU开销** 作为代价。（用CPU换内存，吃CPU， **CPU配置差的小鸡不建议开启** ）\
**压缩算法** 主要是二选一： [**zstd**](https://github.com/facebook/zstd) 压缩率高而速度相对慢（接近 **三倍** 的压缩率），而 [**lz4**](https://github.com/lz4/lz4) 速度快很多（ **2.1** 的压缩率，而速度是前者的几倍）。\
有两个一键配置脚本： [**spiritLHLS - addzram**](https://github.com/spiritLHLS/addzram) 和 [**woniu336/open\_shell - zram\_manager.sh**](https://github.com/woniu336/open_shell/blob/main/zram_manager.sh) 请根据具体情况 **测验** 后 **谨慎** 使用。下面是说明纯手动配置的方法步骤。

#### 手动配置zRAM

```bash
#1️⃣开启/加载 zRAM 模块
sudo modprobe zram num_devices=1
lsmod | grep zram
#持久化：开机自动开启/加载 zRAM 模块
echo "zram" | sudo tee -a /etc/modules-load.d/zram.conf
echo "options zram num_devices=1" | sudo tee -a /etc/modprobe.d/zram.conf

#2️⃣配置 zRAM
#⚠️警告！：必须按照\`指定压缩算法再指定大小\`的顺序配置！
sudo cat /sys/block/zram0/comp_algorithm    #查看压缩算法
sudo cat /sys/block/zram0/disksize            #查看压缩大小
echo "zstd" | sudo tee /sys/block/zram0/comp_algorithm    #设置压缩算法：lz4 或 zstd
echo "8G" | sudo tee /sys/block/zram0/disksize            #设置压缩大小
#持久化：自动进行 zRAM 配置
echo 'KERNEL=="zram0", ATTR{comp_algorithm}="zstd", ATTR{disksize}="8G", TAG+="systemd"' | sudo tee  /etc/udev/rules.d/99-zram.rules

#3️⃣挂载 zRAM
sudo mkswap /dev/zram0
sudo swapon -p 2 /dev/zram0
#持久化：自动挂载 zRAM
sudo bash -c 'cat > /etc/systemd/system/zram.service <<EOF
[Unit]
Description=zram
After=multi-user.target

[Service]
Type=oneshot
RemainAfterExit=true
ExecStartPre=/sbin/mkswap /dev/zram0
ExecStart=/sbin/swapon -p 2 /dev/zram0
ExecStop=/sbin/swapoff /dev/zram0

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl enable zram.service'

#4️⃣检验
sudo swapon --show        #检查一下
free -h                    #发现是SWAP和zRAM的累和
sudo lsblk
#查看 zRAM 的实际压缩效率
sudo zramctl
sudo zramctl --output-all
sudo cat /sys/block/zram0/mm_stat
sudo awk '{print "压缩率: " ($1/$2)}' /sys/block/zram0/mm_stat
sudo zramctl | awk 'NR>1 {printf "压缩率: %.2fx\n", $4*1024/$5}'
sudo watch -n 1 -c 'bash -c '\''
  read -r original compressed <<< $(cat /sys/block/zram0/mm_stat | awk "{print \$1,\$2}");
  ratio=$(awk "BEGIN {printf \"%.1fx\", $original/$compressed}");
  percent=$(awk "BEGIN {printf \"%.0f%%\", ($compressed/$original)*100}");
  echo -e "原始: \e[32m$(numfmt --to=iec --suffix=B $original)\e[0m";
  echo -e "压缩: \e[33m$(numfmt --to=iec --suffix=B $compressed)\e[0m";
  echo -e "压缩率: \e[36m$ratio\e[0m (\e[35m$percent\e[0m)";
'\'''
#或不支持numfmt，纯awk实现
sudo watch -n 1 -c 'awk '\''
  function fmtsize(bytes) {
    if(bytes > 1024^3) return sprintf("\033[32m%.1fGB\033[0m", bytes/1024^3);
    if(bytes > 1024^2) return sprintf("\033[33m%.1fMB\033[0m", bytes/1024^2);
    return sprintf("\033[36m%.1fKB\033[0m", bytes/1024);
  }
  NR==1 {
    printf "原始: %s\n压缩: %s\n压缩率: \033[35m%.1fx\033[0m (\033[31m%.0f%%\033[0m)\n",
    fmtsize($1), fmtsize($2), $1/$2, ($2/$1)*100;
  }
'\'' /sys/block/zram0/mm_stat'
```

#### 手动修改压缩算法和大小

```bash
# 1. 停用zram
systemctl stop zram.service
sudo swapoff /dev/zram0
# 2. 重置设备
echo 1 | sudo tee /sys/block/zram0/reset
# 3. 设置新算法和大小
echo "lz4" | sudo tee /sys/block/zram0/comp_algorithm
echo "4G" | sudo tee /sys/block/zram0/disksize
# 4. 重新挂载zram
sudo mkswap /dev/zram0
sudo swapon /dev/zram0
# 5. 更新持久化配置
echo 'KERNEL=="zram0", ATTR{comp_algorithm}="lz4", ATTR{disksize}="4G", TAG+="systemd"' | sudo tee  /etc/udev/rules.d/99-zram.rules
# 6. 重启服务（如果使用systemd）
sudo systemctl restart zram.service
```

#### 手动卸载zRAM

```bash
#停止并禁用 zram 的服务
sudo systemctl stop zramswap.service
sudo systemctl disable zramswap.service
#卸载 zram 模块
sudo swapoff /dev/zram0
sudo rmmod zram
#移除/注释相关的 fstab 条目
#如果 /etc/fstab 文件中有关于 zram 的条目，应该将其注释掉或删除
sudo sed -i '/^\/dev\/zram0 none swap/d' /etc/fstab
```

#### 调优：zRAM与SWAP搭配

##### 优先级（Priority）

确保zRAM的优先级高于SWAP即可，这在前面 `swapon` 的时候已经设置好了

```bash
sudo swapon --show        #查看所有SWAP设备
```

##### 内核参数调优

通常这三个参数 **保持默认** 即可，不调整也没啥问题\*\*？？？\*\*\
具体看 [路人甲的世界的 **这篇文章**](https://segmentfault.com/a/1190000041578292#item-5) 关于不同参数调优会有更深理解。\
根据文中的推荐，在使用 **zRAM** 与SWAP分层共存下：vm.swappiness=100， **vm.page-cluster=0** （避免不必要的预读和CPU解压缩开销， **提高 zRAM 的效率** ）

| 参数                                                          | 推荐值                                    | 作用说明                                                                       | 适用场景                   |
| ------------------------------------------------------------- | ----------------------------------------- | ------------------------------------------------------------------------------ | -------------------------- |
| **`vm.swappiness`** `/proc/sys/vm/swappiness`                 | **默认:`60`** 保守:`10-30` 激进:`100以上` | 回收文件页和 **匿名页** 的权重，越高 **越积极** 把匿名页换出zRAM/SWAP          | 机械硬盘：默认 SSD：降低值 |
| **`vm.vfs_cache_pressure`** `/proc/sys/vm/vfs_cache_pressure` | **默认:`100`** 敏感 `50`                  | 调整内核回收 **inode/dentry 缓存** 的倾向。 值越低，保留缓存越多。             | 文件服务器、数据库         |
| **`vm.page-cluster`** `/proc/sys/vm/page-cluster`             | **默认:`3`** SSD建议:`1` **zRAM:`0`**     | **每次 SWAP I/O 预读的页面数** (`2^n`),SSD降低减少开销,**zRAM** 为0减少CPU开销 | 机械硬盘：默认；SSD：调低  |

```bash
# 查看
sudo cat <具体路径>
sudo sysctl <参数名>
# 临时修改
sudo sysctl <参数名>=<数字>
# 永久生效
echo "<参数名>=<数字>" | sudo tee -a /etc/sysctl.conf
sudo sysctl --system
sudo sysctl -p
```

#### stress - 压测工具

stress 是一个常用的系统压力测试工具，用于模拟 CPU、内存、I/O 或磁盘负载，帮助管理员测试系统在高负载下的稳定性。

```bash
sudo apt update
sudo apt install stress
sudo apt install stress-ng        #更强大的压力测试工具（支持更多选项）

#CPU 压力测试：
stress --cpu 4 --timeout 10s     #启动4个进程占用CPU，持续10秒
#内存压力测试：
stress --vm 2 --vm-bytes 1G --timeout 10s  #启动2个进程，每个占用1GB内存
stress-ng --vm 1 --vm-bytes 90% --vm-keep --timeout 10s #进程持久占用内存
#磁盘 I/O 压力测试：
stress --io 4 --timeout 10s -v    # 启动4个I/O密集型进程
#混合负载：
stress --cpu 2 --io 1 --vm 1 --vm-bytes 512M --timeout 1m
```

### BBR - 网络优化

BBR 是 Google 提出的一种新型 **TCP 拥塞控制算法** （Bottleneck Bandwidth and RTT）\
**特点和作用** ： **提高网络性能和稳定性** ，显著提高吞吐量和降低 TCP 连接延迟； **适应不同网络环境** ，尤其是高延迟、高丢包网络。目前 BBR 已被集成到 Linux 新版内核中。

#### BBR 启用

```bash
# 1.备份原有配置（谨慎起见）
sudo cp /etc/sysctl.conf "/etc/sysctl.conf.bak_$(date +%Y%m%d_%H%M%S)"
# 2.启用BBR（无需重启服务器）
printf "%s\n" "net.core.default_qdisc=fq" "net.ipv4.tcp_congestion_control=bbr" | sudo tee -a /etc/sysctl.conf        # 写入两行配置;
sudo sysctl --system         # 检查
sudo sysctl -p                 # 立即生效
# 3.检查是否生效
sudo sysctl net.core.default_qdisc net.ipv4.tcp_congestion_control #应输出\`fq\`和\`bbr\`
sudo lsmod | grep bbr         # 检查内核模块
```

#### iperf3

**iperf3** 是一款 [**开源**](https://github.com/esnet/iperf) 的 **网络性能测试工具** ，用于测量 **带宽、延迟、抖动、丢包率** 等网络性能指标。它通过发送和接收 TCP/UDP 数据流来评估网络的最大吞吐量，广泛应用于服务器、路由器、VPN、云服务等场景的网络调优和故障排查。\
[**Windows 版本下载**](https://github.com/ar51an/iperf3-win-builds/releases/download/3.18/iperf-3.18-win64.zip) ，添加 `iperf3.exe` 所在路径作为系统环境变量 `PATH` ，就能使用 `iperf3` 命令了。

```bash
#1.安装
sudo apt update && sudo apt install iperf3
#2.启动 iperf3 服务器模式
sudo iperf3 -s                        # 默认端口：5201
sudo systemctl status iperf3         # 查看状态
#3.防火墙临时允许端口 5201 入站
sudo ufw allow 5201
sudo ufw delete allow 5201            # 测试完之后记得删除规则
sudo ufw status

#4.客户端测试： (确保能访问服务器的 5201 端口，防火墙放行)
# 测试上传 (客户端 -> 服务器):
iperf3 -c <服务器IP>
iperf3 -c <服务器IP> -u -b 100M      # 测试100Mbps UDP 上传
# 测试下载 (服务器 -> 客户端): 添加 -R 参数
iperf3 -c <服务器IP> -R
iperf3 -c <服务器IP> -u -b 100M -R   # 测试100Mbps UDP 下载
# 常用选项
-s    以服务器模式运行。
-c    以客户端模式运行，连接到指定的主机。
-t    控制测试总时长
-R    反向模式：让服务器发送数据，客户端接收（用于从客户端角度测试下载速度）。
-u    使用 UDP 协议，而不是默认的 TCP。
-b    设置目标比特率(带宽)：UDP是必须指定速率，TCP是设置带宽上限。K, M, G 作为单位后缀。
-P    并发数
-p    指定服务器监听或客户端连接的端口号（默认是 5201）。
-i    每次报告时间间隔

#5.停用
sudo systemctl stop iperf3            # 停用服务
sudo systemctl disable iperf3        # 禁止自启
```

## 系统安全

### SSH配置

第一时间修改强密码和端口，使用密钥登录和禁用密码登录。

### 添加新用户

```bash
adduser 新用户名            #创建新用户
usermod -aG sudo 新用户名    #赋予新用户管理员权限
#切换新用户检测是否添加了管理员权限
su - 新用户名
sudo apt update
```

如果SSH配置了密钥登录和关闭密码登录，那需要为用户添加公钥

```bash
#假如新用户和root用户共用同一个公钥
su - 新用户名
mkdir -p ~/.ssh
sudo cp /root/.ssh/authorized_keys ~/.ssh/authorized_keys
#设置所有者和权限
sudo chown -R 新用户名:新用户名 ~/.ssh
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
#检查
ls -ld ~/.ssh
ls -l ~/.ssh/authorized_keys
cat ~/.ssh/authorized_keys
```

（可选）修改 `sudo` 生效时间：

```bash
sudo visudo /etc/sudoers.d/sudo_timeout
#添加以下的配置项并保存
Defaults timestamp_timeout=30
```

### UFW-防火墙

UFW（Unfirewall）是一款 **简单易用** 的防火墙配置工具，通过简化 iptables 命令帮助用户快速管理网络规则，非常适合初学者使用。服务器和外网中间有一层防火墙防止非法入站流量，比如不开放端口外网无法访问。

> Important
>
> 值得注意的是： **UFW 和 docker 的网络不兼容，需要特殊配置！！！**

#### 安装

```bash
sudo apt install ufw
```

#### 设置默认策略

> Caution
>
> **注意** ：避免锁死 SSH！请开放对应的 SSH 端口！

```bash
sudo ufw default deny incoming   #默认拒绝所有入站
sudo ufw default allow outgoing  #默认允许所有出站
```

#### 允许开放对应的服务和端口

```bash
#查看所有的应用程序配置文件
#所有配置都在 /etc/ufw/applications.d/,如需修改，前往此目录修改即可。
sudo ufw app list
sudo ufw app info OpenSSH #查看app具体信息
less /etc/services #查看服务和端口

#允许SSH
sudo ufw allow ssh
sudo ufw allow OpenSSH
sudo ufw allow SSH自定义端口/tcp #如果自定义SSH端口

#开放WEB
sudo ufw allow http
sudo ufw allow https
#或
sudo ufw allow 80/tcp    # HTTP
sudo ufw allow 443/tcp   # HTTPS
```

#### 查看添加的规则

> Warning
>
> **注意** ：请检查是否开启 SSH 端口！自定义 SSH 端口是否正确！

```bash
sudo ufw show added #查看添加的规则
sudo ufw delete <自定义规则> #删除添加的规则
```

#### 开启防火墙

> Caution
>
> 警告！请再次检查是否 **允许 SSH 端口** ！以防被锁住失联

```bash
sudo ufw enable #启动
sudo systemctl enable ufw #设置成自动重启
sudo ufw reload  #重启
sudo ufw disable #关闭

#检查 UFW 的状态
sudo ufw status verbose
sudo ufw status numbered
sudo systemctl status ufw
```

UFW具体语法规则在 **Ubuntu 的文档wiki** 讲的很清楚了；全部语法使用 `man ufw` 或 `sudo ufw --help` 查看。

#### 日志查看

```bash
# 查看所有被防火墙拦截的网络连接
sudo journalctl -r -g "UFW BLOCK"        #倒序查看
sudo journalctl -g "UFW BLOCK" -f        #实时查看
```

### Fail2Ban

Fail2Ban 用于系统防御入侵，保护SSH，自动封禁多次错误的SSH登录防止系统被爆破密码

> Important
>
> **注意：Debian12及以上因弃用rsyslog，Fail2Ban 直接安装和使用可能会有问题！需要特殊配置！**

#### 安装

```bash
sudo apt install fail2ban        #安装

#Debian12:检查python3-systemd是否安装（默认和fail2ban一起安装了）
dpkg -s python3-systemd
sudo apt install python3-systemd -y #如果不存在就安装

sudo systemctl start fail2ban    #启动
sudo systemctl enable fail2ban    #重启后自动运行
sudo systemctl status fail2ban  #查看状态
```

#### 配置

**主配置文件** ： `/etc/fail2ban/fail2ban.conf` ，可复制 `fail2ban.local` 副本来修改。\
**封禁行为配置文件** ： `/etc/fail2ban/jail.conf` ，可复制 `jail.local` 副本来修改。\
**默认日志文件路径**: `/var/log/fail2ban.log`

```bash
#复制为本地配置文件
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
sudo cp /etc/fail2ban/fail2ban.conf /etc/fail2ban/fail2ban.local
```

**jail.local** 文件配置参考：\
**这里在 `[sshd]` 中设置 `backend` 为 `systemd` 使得适用于 Debian12 的 `systemd-journal`**\
`banaction = ufw` 设置集成了 UFW 来封禁IP，这个选项根据使用的防火墙配置。

```
#默认配置：封禁时间、查找时间、最大重试次数、封禁动作（集成UFW防火墙）等
[DEFAULT]
bantime = 600
findtime = 300
maxretry = 5
banaction = ufw
banaction_allports = ufw

#SSH：白名单、读取日志方式、启用功能、SSH端口、最大重试次数、查找时间为、封禁时间(会覆盖DEFAULT部分设置)
#⚠️注意修改端口！
[sshd]
ignoreip = 127.0.0.1/8 192.168.1.0/24
backend = systemd
enabled = true
filter = sshd
port = 你的SSH端口
maxretry = 3
findtime = 5m
bantime = 10m
```

一般修改完 sshd 部分就能满足日常防御所需。

#### 应用生效配置

```bash
# 重启 Fail2ban
sudo systemctl restart fail2ban
# 检查 Fail2ban状态
sudo systemctl status fail2ban
sudo fail2ban-client status
sudo fail2ban-client status sshd
# 查看日志
sudo journalctl -u fail2ban -f #实时查看
sudo less /var/log/fail2ban.log #分页查看
sudo tail -f /var/log/fail2ban.log
```

查看封禁IP和手动封禁IP

```bash
sudo fail2ban-client banned
fail2ban-client set sshd banip 封禁的IP地址            #封禁
sudo fail2ban-client set sshd unbanip 封禁的IP地址    #解封
```

## 应用安装

## Docker

必装之一，现在很多服务使用 docker 容器来部署实在太方便不过辣！不过国内的服务器是连不上 docker 的还需要配置镜像的麻烦（当然也是有一键脚本解决这个问题)，而直接整国外服务器直接没有这个麻烦了。。

> Warning
>
> 警告！！！ docker不兼容UFW！Docker 暴露容器端口会绕开防火墙！需要后续特殊配置！

### 安装

分为 **一键安装脚本** 和 **手动安装** 两个办法。docker官方有便捷脚本但按官方的说法：“ **不建议在生产环境中使用此便捷脚本** ”，手动安装可以掌握更多配置细节。（笔者：未考证过不清楚~）

> **关于 Docker Compose** ：默认 **自动安装** ，Docker Compose 自 V2 版本起开始作为 Docker CLI 的一部分，不再需要单独安装，请使用 **`docker compose`** 命令替代 `docker-compose` 。

#### 一键脚本

都需要 **`sudo` 或 `root` 管理员** 权限执行命令

##### 官方：

```bash
curl -fsSL https://get.docker.com | sudo sh
```

测试安装步骤（不会实际安装）：

```bash
curl -fsSL https://get.docker.com | sudo sh -s -- --dry-run
```

**来源** ： [**脚本官方说明**](https://docs.docker.com/engine/install/debian/#install-using-the-convenience-script) ， [GitHub源仓库](https://github.com/docker/docker-install)

##### 国内：

```bash
bash <(curl -sSL https://linuxmirrors.cn/docker.sh)
```

**来源** ：大名鼎鼎的 [**linuxmirrors** 脚本](https://linuxmirrors.cn/) ， [GitHub仓库](https://github.com/SuperManito/LinuxMirrors)

#### 手动安装

教程来自 – [**官方安装教程（Debian系统）**](https://docs.docker.com/engine/install/debian/) 的翻译和整理

##### 卸载旧的冲突软件包

```bash
for pkg in docker.io docker-doc docker-compose podman-docker containerd runc; do sudo apt-get remove $pkg; done
```

##### 设置 Docker 的 apt 仓库

```bash
# 添加Docker官方GPG密钥：
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

# 将仓库添加到Apt源：
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
```

##### 安装 Docker 软件包

```bash
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
```

##### 运行镜像验证安装

```bash
sudo docker run hello-world
```

##### 卸载

有时候因为一些原因比如安装错误、版本依赖、从头再来等想要卸载干净docker。

1、卸载 Docker Engine、CLI、containerd 及 Docker Compose 软件包：

```bash
sudo apt-get purge docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin docker-ce-rootless-extras
```

2、主机上的镜像、容器、卷或自定义配置文件不会被自动删除。要删除所有镜像、容器和卷：

```bash
sudo rm -rf /var/lib/docker
sudo rm -rf /var/lib/containerd
```

3、移除软件源列表及密钥环

```bash
sudo rm /etc/apt/sources.list.d/docker.list
sudo rm /etc/apt/keyrings/docker.asc
```

您需要手动删除所有修改过的配置文件。

### 配置

```bash
#1.创建 docker 用户组。
sudo groupadd docker
#2.将您的用户添加到 docker 用户组中
sudo usermod -aG docker $USER
#3.注销并重新登录或命令激活 对用户组的更改
newgrp docker
#4.验证是否能在无需 sudo 的情况下运行 docker 命令
docker run hello-world
```

#### 设置开启自启

```bash
#查看当前docker状态
systemctl status docker
systemctl status containerd
#设置开启自启
sudo systemctl enable docker.service
sudo systemctl enable containerd.service
#禁用
sudo systemctl disable docker.service
sudo systemctl disable containerd.service
```

#### docker-ufw防火墙 兼容问题

先来个简单小脚本，全选复制到命令行后回车执行。\
这将创建一个 Nginx 测试容器来检测 Docker 是否绕过了 UFW 防火墙规则， **浏览器访问显示的IP地址和端口即可判断** 。测试完成后按回车即可自动清理所有测试痕迹，不会对系统造成任何残留。

```bash
#!/bin/bash
d=~/d_$(date +%s);mkdir -p $d
echo "<html><meta charset=UTF-8><h1>Docker UFW绕过测试</h1><p>如果您能看到此页面，<b style=color:red>Docker可能绕过了UFW防火墙！</b></p>">$d/index.html
trap 'docker rm -f ufw_test 2>/dev/null;rm -rf $d;echo 已清理' EXIT
echo 启动容器，端口12345...;docker run --name ufw_test -d -p 12345:80 -v $d:/usr/share/nginx/html nginx >/dev/null
echo 测试: $(hostname -I|awk '{print $1}'):12345
echo 若能访问，Docker绕过了UFW;echo 按回车清理...;read
docker rm -f ufw_test 2>/dev/null;rm -rf $d;echo 已清理
```

**发现没有？！** UFW并没有放行 `12345` 端口但 docker 容器居然绕过了！这真是一件 **非常危险** 的事情！！！

这就不得不提到 [**ufw-docker**](https://github.com/chaifeng/ufw-docker) 和 [ufw-docker-automated](https://github.com/shinebayar-g/ufw-docker-automated) 这两个GitHub项目就是为解决这个而诞生的！

##### 下载 ufw-docker 脚本

```bash
sudo wget -O /usr/local/bin/ufw-docker \
  https://github.com/chaifeng/ufw-docker/raw/master/ufw-docker
sudo chmod +x /usr/local/bin/ufw-docker
```

##### 使用ufw-docker

在开始一切之前，建议先 **手动备份** 一下规则文件以防万一：

```bash
sudo cp /etc/ufw/after.rules "/etc/ufw/after.rules.bak.$(date +"%Y-%m-%d_%H-%M-%S")"
```

使用 **管理员权限** 执行这个命令，修改 `ufw` 的 `after.rules` 文件。\
本质其实就是在 `/etc/ufw/after.rules` 末尾增加一块修复的规则。

```bash
ufw-docker install
```

然后 **重启 `ufw`** 就能生效了。存在特殊情况，还需要额外重启docker服务或者重启服务器。

```bash
#重启ufw
sudo systemctl restart ufw
#或
sudo ufw reload
```

赶紧来测试一下！ **用回开头那个测试脚本** ，这时候发现 `公网IP:123456` 再也不能访问了！成功有效拦住了！\
这时候再执行 `sudo ufw allow 12345` 命令放行 `12345` 端口对于docker容器是无效的，需要通过别的方式。

实际上是 ufw 防火墙路由允许外部访问容器的 `80` 端口，而不是映射绑定主机的 `12345` 端口。路由转发行了之后公网就能通过容器映射的端口访问到容器80端口了。

```bash
#ufw路由转发规则
sudo ufw route allow 80
sudo ufw route delete allow 80
sudo ufw status        #查看ufw规则
```

或者 `ufw-docker` 也提供对应的命令

```bash
ufw-docker allow 容器名 80                    #暴露容器的80端口
ufw-docker allow 容器名                    #暴露容器所有已发布端口
ufw-docker allow 容器名 443/tcp myNet        #暴露容器443的端口、协议为TCP、网络为\`myNet\`
ufw-docker delete allow 容器名                #移除容器相关所有规则
ufw-docker delete allow 容器名 80            #移除容器80端口的规则
ufw-docker status                          #显示当前防火墙允许的转发规则
```

**更多用法** 请参阅： [**GitHub文档**](https://github.com/chaifeng/ufw-docker?tab=readme-ov-file#usage)

当然这种还是有一定的缺陷， `ufw-docker` 加的规则是 **静态** 的，只对当前容器有效，万一容器重启、服务器重启、容器对应的那个 `172.17.0.X` IP发生变化了呢？\
所以 [**ufw-docker-automated**](https://github.com/shinebayar-g/ufw-docker-automated) 就是为了解决这个而生，这个工具是一个常驻后台小程序， **自动监听Docker事件** 。它能检测到容器启动、停止、IP变化，自动同步UFW规则， **不用你手动维护** 。

个人感觉暂时先用不上了，因为在实际生产环境更多是 **`-p 127.0.0.1:8080:80`** ， **只允许服务器本地访问** ！然后本地所有暴露端口的服务或者 docker 容器全部通过 **Nginx** 作为最终网关来管理，最后统一对外开放 `443` 端口提供 web 服务。

### 运行用户安全

未完待续…

## Nginx

Nginx 是一款轻量级、高性能的Web服务器和反向代理服务器，以高并发、低资源占用著称。\
虽然说可以docker快速部署，但这种管理全局网络应用入口的我更喜欢原生安装。

想要 **快速入门** 配置又不想这么枯燥无味，这里推荐几个我觉得不错的视频：

* [Nginx入门必须懂3大功能配置 - Web服务器/反向代理/负载均衡 - 技术蛋老师 - bilibili](https://www.bilibili.com/video/BV1TZ421b7SD/)
* [Nginx实战 - 配置HTTPS | 数字证书和私钥 | Docker Compose容器 - 技术蛋老师 - bilibili](https://www.bilibili.com/video/BV1uH4y1w7je)
* [【GeekHour】30分钟Nginx入门教程 - bilibili](https://www.bilibili.com/video/BV1mz4y1n7PQ/)

### 安装

```bash
#1️⃣安装必备组件
sudo apt install curl gnupg2 ca-certificates lsb-release debian-archive-keyring

#2️⃣导入官方的 nginx 签名密钥，以便 apt 能够验证软件包的真实性
#1.获取密钥：
curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor \
    | sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null
#2.验证下载的文件是否包含正确的密钥
gpg --dry-run --quiet --no-keyring --import --import-options import-show /usr/share/keyrings/nginx-archive-keyring.gpg | grep "573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62" > /dev/null && echo -e "\e[32m✅ Nginx key verified successfully with fingerprint: \e[34m573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62\e[0m" || echo -e "\e[31m❌ Key verification failed\e[0m"

#3️⃣设置 stable-稳定版 的Nginx软件包的apt仓库
echo "deb [signed-by=/usr/share/keyrings/nginx-archive-G7DNlW9Zt4cV5e9keyring.gpg] \
http://nginx.org/packages/debian \`lsb_release -cs\` nginx" \
    | sudo tee /etc/apt/sources.list.d/nginx.list

#4️⃣设置仓库优先级，使官方软件包优先于发行版提供的版本
echo -e "Package: *\nPin: origin nginx.org\nPin: release o=nginx\nPin-Priority: 900\n" \
    | sudo tee /etc/apt/preferences.d/99nginx

#5️⃣正式安装
sudo apt update
sudo apt install nginx
#Nginx的所有命令要以sudo管理员身份运行
sudo nginx -V                #查看版本
sudo systemctl enable nginx    #开启自启
sudo systemctl status nginx    #查看状态
```

如果一切顺利和成功，浏览器访问 `公网IP地址:80` 将会看见 **`Welcome to nginx!`** 的经典 Nginx 测试界面。

### 配置

首先我们来明确配置文件在哪？Nginx相关的文件在 **`/etc/nginx/`** 路径下，其中 `/etc/nginx/nginx.conf` 是 Nginx 默认的 **主配置文件** （当然可以通过命令修改成其他文件）， `/etc/nginx/conf.d` 路径下包含所有的 **子配置文件** ，一般会在这里面定义各种网站服务，然后通过主配置文件 **导入加载** 生效。(还不明白？继续往下看就悟透！)

先来简单看看 Nginx 配置文件的 **层次结构**

```bash
+--------main---------+
| +-----events------+ |
| +------http-------+ |
| | +---server----+ | |
| | |  location   | | |
| | |  location   | | |
| | |  location   | | |
| | +-------------+ | |
| | +---server----+ | |
| | +-------------+ | |
| | +---server----+ | |
| | +-------------+ | |
| +-----------------+ |
+---------------------+

main                    # 全局配置，对全局生效
├── events                # 配置影响 nginx 服务器或与用户的网络连接
├── http                # 配置代理，缓存，日志定义等绝大多数功能和第三方模块的配置
│   ├── upstream        # 配置后端服务器具体地址，负载均衡配置不可或缺的部分
│   ├── server           # 配置虚拟主机的相关参数，一个 http 块中可以有多个 server 块
│   ├── server
│   │   ├── location    # server 块可以包含多个 location 块，location 指令用于匹配 uri
│   │   ├── location
│   │   └── ...
│   └── ...
└── ...
```

在一切开始动手操作之前，我们来备份一下配置文件以防万一

```bash
#备份配置文件
sudo cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak
sudo cp /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf.bak
```

修改完配置文件可以 **测试语法** 和 **热重载** 来生效：

```bash
nginx -t                        #测试配置文件语法
nginx -s reload                    #热重载
systemctl reload nginx
#检查 Nginx 的错误日志 (error_log) 和访问日志 (access_log)在\`/var/log/nginx/\`路径
```

**nginx.conf 配置文件的语法规则**

1. 配置文件由指令与指令块构成
2. 每条指令以 “;” 分号结尾，指令与参数间以空格符号分隔
3. 指令块以 {} 大括号将多条指令组织在一起
4. include 语句允许组合多个配置文件以提升可维护性
5. 通过 # 符号添加注释，提高可读性
6. 通过 $ 符号使用变量
7. 部分指令的参数支持正则表达式，例如常用的 location 指令

```nginx
# 全局块 (Main context) - 配置影响 Nginx 全局的指令
user nginx;                   # Nginx 工作进程运行的用户和组
worker_processes auto;        # 工作进程数量，通常设置为 auto 或 CPU 核心数
error_log /var/log/nginx/error.log warn; # 错误日志路径和级别
pid       /var/run/nginx.pid;          # Nginx 主进程的 PID 文件路径

# events 块 - 配置影响 Nginx 服务器与用户的网络连接
events {
    worker_connections 1024;  # 每个工作进程允许的最大连接数
}

# http 块 - 配置 HTTP 服务器的主要参数
http {
    include       /etc/nginx/mime.types;   # 引入文件扩展名与文件类型的映射表
    default_type  application/octet-stream; # 默认文件类型

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"'; # 日志格式

    access_log  /var/log/nginx/access.log  main; # 访问日志路径和使用的格式

    sendfile        on;    # 开启高效文件传输模式
    #tcp_nopush     on;    # 防止网络阻塞
    keepalive_timeout  65; # 长连接超时时间
    #gzip  on;               # 开启 Gzip 压缩

    # 可以在 http 块中包含其他的配置文件，通常用于定义虚拟主机 (server 块)
    include /etc/nginx/conf.d/*.conf;        # CentOS/RHEL 风格
    include /etc/nginx/sites-enabled/*;      # Debian/Ubuntu 风格

    # server 块 (虚拟主机配置) - 每个 server 块定义一个虚拟主机
    server {
        listen       80;                # 监听的端口
        server_name  localhost;         # 服务器名 (域名或 IP)

        # location 块 - 根据请求的 URI 进行匹配和处理
        location / {
            root   /usr/share/nginx/html;  # 网站根目录 (存放网页文件的地方)
            index  index.html index.htm;   # 默认首页文件
        }

        # 错误页面重定向
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /usr/share/nginx/html;
        }

        # 示例：反向代理配置
        # location /myapp/ {
        #     proxy_pass http://backend_server_address; # 代理到后端的应用服务器
        #     proxy_set_header Host $host;
        #     proxy_set_header X-Real-IP $remote_addr;
        #     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        #     proxy_set_header X-Forwarded-Proto $scheme;
        # }
    }

    # 可以定义更多的 server 块来配置多个网站或应用
    # server {
    #     listen 80;
    #     server_name example.com www.example.com;
    #     root /var/www/example.com/html;
    #     index index.html;
    #     ...
    # }
}
```

nginx 常用的内置全局变量，可以在配置中随意使用：

| **变量名称**          | **含义**                                                        |
| --------------------- | --------------------------------------------------------------- |
| `$host`               | 请求信息中的 Host，如果请求中没有 Host 行，则等于设置的服务器名 |
| `$request_method`     | 客户端请求类型，如 GET、POST 等                                 |
| `$remote_addr`        | 客户端的 IP 地址                                                |
| `$remote_port`        | 客户端的端口号                                                  |
| `$args`               | 请求中的查询字符串参数（如 `?key=value&key2=value2` ）          |
| `$content_length`     | 请求头中的 Content-length 字段                                  |
| `$http_user_agent`    | 客户端的 User-Agent 信息（通常是浏览器或爬虫标识）              |
| `$http_cookie`        | 客户端发送的 Cookie 信息                                        |
| `$server_protocol`    | 请求使用的协议，如 HTTP/1.0 或 HTTP/1.1                         |
| `$server_addr`        | 服务器的 IP 地址                                                |
| `$server_name`        | 服务器名称（匹配 `server_name` 指令）                           |
| `$server_port`        | 服务器监听的端口号                                              |
| `$document_root`      | 当前请求的根目录（对应 `root` 指令的值）                        |
| `$uri`                | 请求的 URI（不包含查询字符串部分）                              |
| `$request_uri`        | 请求的完整 URI（包含查询字符串）                                |
| `$query_string`       | 查询字符串部分（与 `$args` 类似）                               |
| `$status`             | 响应的 HTTP 状态码（如 200、404、500）                          |
| `$scheme`             | 请求的协议，如 `http` 或 `https`                                |
| `$is_args`            | 如果有查询字符串则为 `?`，否则为空                              |
| `$binary_remote_addr` | 客户端 IP 的二进制表示形式                                      |
| `$time_local`         | 当前请求的时间（本地时间）                                      |

## 域名与Cloudflare

前面辛苦配置服务器，终于到了最后一个环节──配置域名和Cloudflare，网站能够正式投入使用的最后一步。

## 添加到Cloudflare托管

Cloudflare 是全球领先的云安全和性能服务提供商，主要提供 CDN、DDoS 防护和 DNS 服务。也被称作“ **大善人** ”──CDN（小橙云）、DDoS 防护、DNS 服务等都是免费开箱即用的，还有更多功能等待探索。

1. 首先在 Cloudflare **账户主页** → **加入域** → 填入你的域名。
2. 根据 Cloudflare 提示，在你购买域名所处 → **DNS** → 修改 **名称服务器** (Name Server)为 Cloudflare 提供的名称服务器。
3. 等待生效。根据不同域名商有快有慢，生效时间大约为 **1~ 48 小时** 内。成功生效后 Cloudflare 会第一时间发送邮件通知。
4. 成功将域名托管到 Cloudflare 后，接下来你可以修改 DNS、使用免费的 CDN、DDoS 防护设置、免费的 SSL 证书等等

## 修改DNS和使用CDN

域名托管到 Cloudflare 之后，我们就可以来修改域名的 **DNS 记录** 和使用免费的 **小橙云(CDN)** ![Cloudflare CDN](./assets/服务器与网站的开荒入坑%20-%20文档共建/Image.svg)

导航至：Cloudflare **账户主页** → 选择对应域名 → **DNS** → **记录** ，点击 **添加记录** ，我们主要关心三种类型： **A** 、 **AAAA** 、 **CNAME**

* **A** ：指向 **IPv4** 地址
* **AAAA** ：指向 **IPv6** 地址
* **CNAME** ： **别名** ，指向其他域名

1. 比如现在有一个服务器，有 **IPv4** 和 **IPv6** 的独立公网地址，在这个服务器上面部署了 web 网页等服务。那可以添加 DNS 记录，根据自己的喜好，根域名或者子域名甚至二三级子域名指向这个服务器的 IP 地址。可以多个子域名指向同一个 IP 地址，区分哪个子域名是哪个部署的网页──这就是服务器的任务了──即前面所说的 Nginx 配置
2. **Cloudflare CDN** （小橙云）在添加新的 DNS 记录时是默认开启的， **代理状态** 显示 `已代理` ，并且还有一个小橙云的图标。这样我们就用了 Cloudflare **大善人** 的免费 CDN 了，好处多多！比如 **隐藏服务器的源 IP** （对此，想要更进一步请看后面的内容）、自动缓存静态资源、节省流量带宽、DDoS 防护、WAF 防火墙、 **全球加速** （除了中国…国内延迟没这么好看，相对高些，但也没有很夸张，直连是完全能正常访问的，直连 [我博客](https://blog.huan666.de/) 看~一点也不慢。这 Cloudflare 胜在 **免费** 、简单！如果追求极致低延迟访问，你还是选择国内的吧，域名备案先搞个十天半个月，然后多爆点金币买流量计费的 CDN 服务，速度肯定嘎嘎快，不过你最好祈祷睡一觉起来没有”欠下一套房子“的天价账单好吧没有这么夸张但小小博客网站平时没啥人看的，除非是被人 DDoS 攻击刷爆了）
3. **CNAME** 的用法常见有：部署的 **静态博客** 在 **GitHub Page** 或 **Netlify** 上，它们会提供一个子域名，这时候就可以使用 **CNAME** 来让我们的域名指向这个子域名。如果你想了解更多这方面的内容亦对搭建博客感兴趣，可以看我博客另外一篇教程── [《Hugo搭建博客入坑》](https://blog.huan666.de/posts/hugo-blog-setup-guide/#%E6%9E%84%E5%BB%BA%E4%B8%8E%E9%83%A8%E7%BD%B2) ，其中谈到了这一点。

## SSL证书

域名托管到了 Cloudflare 并开启了小橙云（CDN）之后，Cloudflare 已经默认开启了 **HTTPS** 了，Cloudflare 会 **自动** 帮我们管理和续订三个月有效期的证书。

### 加密模式

导航至：Cloudflare **账户主页** → 选择对应域名 → **SSL/TLS** → **概述** 的页面，可以看到当前 **加密模式** ，默认是 `自动模式` 。点击 **配置** 按钮，我们可以自定义选择不同的模式，这将会影响：\
**访问者 → Cloudflare → 源服务器** 的流量加密。\
**还没完！** 目前只是 `访问者 -> Cloudflare` 这一段是流量加密的，但 `Cloudflare -> 源服务器` 这一段的流量没有加密，仍然是 **HTTP** ！\
所以需要设置 **加密模式** 为 `完全（严格）` ，这有个前提是源服务器要有一个公开可信的证书，你可以使用诸如 [**acme.sh**](https://github.com/acmesh-official/acme.sh) 来自动管理证书，或者直接使用 Cloudflare 最高可达15年的证书。

### 配置证书

接下来我将以使用 Cloudflare 的证书为例，当然你使用其他公开可信的证书也是没问题的

1. 导航至：Cloudflare **账户主页** → 选择对应域名 → **SSL/TLS** → **源服务器** (Origin Server)，点击创建证书。
2. 配置：私钥类型可选 RSA (2048) 或 ECC，有效期最高可选15年。
3. 创建了之后 **下载保存** 证书文件： **原始证书** (Origin Certificate)（**.pem** 格式）和 **私钥** Private Key（**.key** 格式）。
4. 然后在服务器 `/etc/nginx/ssl` 保存这两个文件，自定义有标识性的名字，注意文件 **.pem** 和 **.key** 的文件格式！
5. 接下来配置 **Nginx** 。只需要在 **server** 块中配置 `ssl_certificate` 和 `ssl_certificate_key` 就完成了~

`/etc/nginx/nginx.conf` 文件示例：

```nginx
user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log notice;
pid        /run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    include /etc/nginx/conf.d/*.conf;
}
```

`/etc/nginx/conf.d/test.conf` 示例：

```nginx
# HTTP (端口 80) - 自动重定向到 HTTPS
server {
    listen 80;
    listen [::]:80; # 支持 IPv6
    server_name 你的域名;

    # 将所有 HTTP 请求重定向到 HTTPS
    location / {
        return 301 https://$host$request_uri;
    }
}

# HTTPS (端口 443)
server {
    listen 443 ssl;
    listen [::]:443 ssl; # 支持 IPv6
    http2 on;
    server_name 你的域名;

    # SSL 证书文件
    ssl_certificate /etc/nginx/ssl/Cloudflare_你的域名.pem;
    ssl_certificate_key /etc/nginx/ssl/Cloudflare_你的域名.key;

    # SSL/TLS 配置
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-%% POLY1305 %%:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:10m;

    # OCSP Stapling
    ssl_stapling on;
    ssl_stapling_verify on;

    # 网站根目录和默认索引文件
    root /usr/share/nginx/html; # !!! 请务必修改为您的网站文件实际存放路径 !!!
    index test.html; # 根据您的应用需求调整

    # Location 块: 尝试匹配文件或目录, 否则返回 Nginx 默认 404 错误
    location / {
        try_files $uri $uri/ =404;
    }

    # 错误页面处理
    # 对于 404 错误, 上面的 try_files 会直接返回 404 状态码, Nginx 将使用其内置的默认 404 页面。
    # 对于 50x 系列服务器错误, 使用 Nginx 默认的 50x.html 页面。
    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
        root /usr/share/nginx/html; # Nginx 默认错误页面的存放路径
    }

    # 日志文件路径
    access_log /var/log/nginx/test.你的域名.access.log;
    error_log /var/log/nginx/test.你的域名.error.log warn;
}
```

应用生效

```bash
# 测试配置语法
sudo nginx -t
# 热重载
sudo nginx -s reload
```

最后配置完成了后，可以设置 **加密模式** 为 `完全（严格）` 了。然后访问域名 `https://你的域名` 测试一下，看看是否能正常连接访问。不过你可能会发现，访问 `https://服务器IP` 显示证书不安全，其实对于 Cloudflare 与 源服务器之间的加密用 Cloudflare 证书完全够了；况且下文我还会讲到 `仅允许CloudFlare的IP段访问80/443端口` ，直连IP不能访问网站。

### Cloudflare配置

访客与 Cloudflare 节点之间流量还有一些 **必要的配置选项** ，导航至： **SSL/TLS** → **边缘证书** 。

| 选项            | 建议    | 备注 |
| --------------- | ------- | ---- |
| 始终使用 HTTPS  | 开启    |      |
| 最低 TLS 版本   | TLS 1.2 |      |
| 随机加密        | 开启    |      |
| TLS 1.3         | 开启    |      |
| 自动 HTTPS 重写 | 开启    |      |
| 证书透明度监视  | 开启    |      |

## \[UFW仅允许CloudFlare的IP段访问80/443端口]

前面开启了小橙云隐藏了服务器源 IP 了， **看似高枕无忧** ，但还 **暗藏隐患** 。殊不知，还能通过反向扫服务器 IP 地址的网页与域名的网页一一 **反映射** 起来，这不就建立域名与 IP 地址的关联了么？不信的话，你现在可以自动尝试一下，直接在浏览器输入你的服务器 IP 地址或者加上 `https://` | `http://` 的前缀来访问~

所以现在就需要限制：只能 CloudFlare 的 IP 段访问 80/443 端口~ 好在，Cloudflare 提供了 [CDN 的 IP 段](https://www.cloudflare.com/zh-cn/ips/) ，把它们添加到防火墙规则了里面即可。\
当然不能一个个手动添加，这里我从别处复制了一个 bash 脚本，你可以直接粘贴运行（注意可能存在的 root **权限问题** ，可以使用 `sudo -i` 切换），或者保存成单独的脚本文件设置定期执行：

```bash
#!/bin/bash

# 下载最新 Cloudflare IP 列表
cf_ips_v4=$(curl -s https://www.cloudflare.com/ips-v4)
cf_ips_v6=$(curl -s https://www.cloudflare.com/ips-v6)

# 给新规则添加特殊标记 comment，便于识别
RULE_COMMENT="cf-update-$(date +%s)"

# 先添加新的 Cloudflare IP规则（带标记）
for ip in $cf_ips_v4; do
    ufw allow proto tcp from $ip to any port 80 comment $RULE_COMMENT
    ufw allow proto tcp from $ip to any port 443 comment $RULE_COMMENT
done

for ip in $cf_ips_v6; do
    ufw allow proto tcp from $ip to any port 80 comment $RULE_COMMENT
    ufw allow proto tcp from $ip to any port 443 comment $RULE_COMMENT
done

# 等待1-2秒，确保新规则生效
sleep 2

# 删除旧的 Cloudflare 80/443 端口规则（但排除刚刚加的）
EXISTING_RULES=$(ufw status numbered | grep -E '80\/tcp|443\/tcp' | grep -v "$RULE_COMMENT" | awk -F'[][]' '{print $2}' | sort -rn)

for rule in $EXISTING_RULES; do
    ufw --force delete $rule
done

# 设置默认拒绝 80/443 的外来访问（如果没有就添加一次）
ufw status | grep -q "DENY.*80" || ufw deny 80/tcp
ufw status | grep -q "DENY.*443" || ufw deny 443/tcp

echo "✅ Cloudflare IP 更新完成（零中断），80/443 只允许 Cloudflare访问。其他端口规则未受影响。"
```

## 在用 Cloudflare CDN 后获取真实的用户 IP

当我们为网站启用 **Cloudflare CDN（小橙云）** 后，所有访客流量都会先经过 Cloudflare 的全球网络节点，再转发到我们的源服务器。这就有个核心问题摆在面前──── **服务器看到的所有请求都来自 Cloudflare 的 IP 地址，而不是真实的客户端 IP**

**这会导致：**

* **日志记录错误** ：访问日志中全是 Cloudflare 的 IP
* **安全防护失效** ：基于 IP 的访问控制、限流等功能失效
* **数据分析偏差** ：无法准确统计访客地理位置等信息
* **应用功能异常** ：依赖客户端 IP 的功能（如登录异常检测）无法正常工作

幸运的是，Cloudflare 在转发请求时，会在 **HTTP 头** 中添加 **`CF-Connecting-IP`** ，记录 **真实的客户端 IP** 。我们只要简单配置一下 Nginx，让它智能识别并使用这个请求头。

### 基于原理：Nginx 的 RealIP 模块

Nginx 内置了 `ngx_http_realip_module` 模块来处理这个问题。这个模块的功能是，从指定的 HTTP 头中提取真实 IP，并用它 **覆盖 Nginx 内部的 `$remote_addr` 变量** 。

其工作原理包含两个关键部分，缺一不可：

1. **信任代理 (`set_real_ip_from`)**: 定义一个或多个受信任的 IP 地址或地址段。Nginx 只会处理来自这些 IP 的请求头。这是至关重要的安全措施，可以防止恶意用户直接访问你的服务器并伪造 IP 请求头。接下来我们就是需要添加只信任来自 **Cloudflare IP 段** 的请求
2. **指定头 (`real_ip_header`)**: 告诉 Nginx 去哪个 HTTP 头里寻找真实 IP。对于 Cloudflare，就是 `CF-Connecting-IP` 。

当 Nginx 收到一个请求时，它会检查：

> “这个请求的来源 IP 是否在我的信任列表中？如果是，我就读取 `CF-Connecting-IP` 头，并用它的值作为真实 IP；如果不是，我就忽略这个头，保持来源 IP 不变。”

通过这个机制，我们就能安全、准确地恢复真实访客的 IP。

### 配置步骤

#### 创建配置文件并下载 Cloudflare 的 IP 地址范围

```bash
sudo touch /etc/nginx/conf.d/cloudflare-ips.conf
# IPv4
echo "# Cloudflare IPv4 ranges" | sudo tee /etc/nginx/conf.d/cloudflare-ips.conf > /dev/null
curl -s https://www.cloudflare.com/ips-v4 | sed 's/^/set_real_ip_from /' | sed 's/$/;/' | sudo tee -a /etc/nginx/conf.d/cloudflare-ips.conf > /dev/null

# IPv6
echo "" | sudo tee -a /etc/nginx/conf.d/cloudflare-ips.conf > /dev/null
echo "# Cloudflare IPv6 ranges" | sudo tee -a /etc/nginx/conf.d/cloudflare-ips.conf > /dev/null
curl -s https://www.cloudflare.com/ips-v6 | sed 's/^/set_real_ip_from /' | sed 's/$/;/' | sudo tee -a /etc/nginx/conf.d/cloudflare-ips.conf > /dev/null
```

如果一切正常，最终 `/etc/nginx/conf.d/cloudflare-ips.conf` 文件内容就像这样：

```nginx
# Cloudflare IPv4 ranges
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
... (更多IP段)
# Cloudflare IPv6 ranges
set_real_ip_from 2400:cb00::/32;
set_real_ip_from 2606:4700::/32;
... (更多IP段)
```

当然，这个 [**Cloudflare IP地址范围**](https://www.cloudflare.com/zh-cn/ips/) 肯定会变的，不过我看最近一次更新还是2023 年 9 月 28 日；\
也可以写一个定时脚本定期获取IP地址列表。

#### 编辑 /etc/nginx/nginx.conf，在 http 块中引入 Cloudflare IP 配置

```nginx
include /etc/nginx/conf.d/cloudflare-ips.conf;
```

#### 在站点配置文件的server模块中添加真实 IP 头

```nginx
real_ip_header CF-Connecting-IP;
```

**完整示例：**

`/etc/nginx/nginx.conf` 文件：

```nginx
user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log notice;
pid        /run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    # 自动加载所有配置文件（推荐）
    include /etc/nginx/conf.d/*.conf;
    # 或者，如果想精确控制加载顺序：
    # include /etc/nginx/conf.d/cloudflare-ips.conf;
    # include /etc/nginx/conf.d/你的项目名.conf;
}
```

**`/etc/nginx/conf.d/你的项目名.conf`** ：

```nginx
server {
    listen 80;
    listen [::]:80;
    server_name 你的域名;

    # HTTPS强制重定向（如有证书，建议加上）
    location / {
        return 301 https://$host$request_uri;
    }
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    http2 on;

    server_name 你的域名;

    # 从 Cloudflare 获取源客户端请求IP
    real_ip_header CF-Connecting-IP;

    # SSL 证书文件
    ssl_certificate /etc/nginx/ssl/Cloudflare公钥证书.pem;
    ssl_certificate_key /etc/nginx/ssl/私钥.key;

    # SSL/TLS 配置
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:10m;

    # OCSP Stapling
    ssl_stapling on;
    ssl_stapling_verify on;

    location / {
        proxy_pass http://127.0.0.1:端口号;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }

    # 日志、错误
    access_log /var/log/nginx/你的项目名.access.log;
    error_log /var/log/nginx/你的项目名.error.log warn;
}
```

#### 测试并应用配置

```bash
# 测试配置语法
sudo nginx -t
# 热重载
sudo nginx -s reload
# 查看日志-访问IP
tail -f /var/log/nginx/你的项目名.access.log
```

## 参考资料

* [SSH 客户端收集 - 砖头@runbrick - LINUX DO](https://linux.do/t/topic/489989)
* [SSH 教程 - 阮一峰 - 网道](https://wangdoc.com/ssh)
* [VPS 初体验（二）使用 SSH 连接远程主机 - Kiku 的个人博客](https://kiku.vip/2021/10/14/%E4%BD%BF%E7%94%A8%20SSH%20%E8%BF%9E%E6%8E%A5%E8%BF%9C%E7%A8%8B%E4%B8%BB%E6%9C%BA/)
* [SSH 工具教程 (Tutorial of SSH tools) - Jarvis’ Blog](https://www.jarvis73.com/2022/09/17/SSH-Keygen/)
* [SSH小白入门教程一次弄懂SSH入门到精通 - Colin Chang](https://a-nomad.com/ssh)
* [服务器配置SSH密钥登录 - 繁星点点](https://blog.52013120.xyz/post/34.html#%E6%9C%8D%E5%8A%A1%E5%99%A8%E9%85%8D%E7%BD%AEssh%E5%AF%86%E9%92%A5%E7%99%BB%E5%BD%95)
* [史上最强 Linux一键DD重装脚本 - 黑海洋 - Wiki](https://blog.upx8.com/4100)
* [VPS 基本配置：新买的 VPS 怎么整备和调教？ - 怪文](https://www.guai.win/notes/0003/new-vps)
* [\[长期更新\]VPS脚本收集和分享 - ggsmida - LINUX DO](https://linux.do/t/topic/238531)
* [【配置优化】我拿到VPS服务器必做的那些事 - Yuju - LINUX DO](https://linux.do/t/topic/160305)
* [一台新到手的VPS服务器必做十二项配置（以Ubuntu为例）- pppfz- LINUX DO](https://linux.do/t/topic/115839)
* [一台新到手的VPS服务器必做的十二项配置（以Ubuntu为例）- PPPFZ’s Blog](https://blog.pppfz.com/posts/new-vps-common-setup.html)
* [Debian 12 系统安装及个人常用配置分享 - 开发调优 - LINUX DO](https://linux.do/t/topic/229933)
* \[拿到新的 digital ocean 的一台 vps 需要做哪些事情 - azuginnen]
* \[年轻人的第一台 VPS 设置 - Layton]
* [路飞工具箱 - 路飞博客](https://blog.lufei.de/p/87/)
* [小内存服务器生存指南——SWAP虚拟内存-我不是咕咕鸽](https://blog.laoda.de/archives/vps-swap)
* [Linux 服务器如何更改 swap 分区大小、优化内存 - SkyWT](https://skywt.cn/blog/changeswap)
* [Linux 交换分区要点汇总 - 知乎](https://zhuanlan.zhihu.com/p/414913356)
* [在Linux创建和使用swap文件以替代swap分区 – Orz小窍门](https://www.orztip.com/?p=748\&article_title=linux-swap-space-use-swap-file-vs-swap-partition)
* [Linux 修改swap虚拟内存 | Timber\_Blog](https://timberkito.com/?p=98)
* [linux 之虚拟内存swap - X-Wolf - 博客园](https://www.cnblogs.com/xingxia/p/memory_fdisk.html)
* [一键开启 zram 内存脚本，解决硬盘读写不佳 (或容量小) 的鸡鸡](https://woniu336.github.io/p/422/)
* \[【Linux内核】另一种增大内存方法:适合CPU性能过剩但RAM少，硬盘读写不佳(或容量小)的鸡鸡]
* [配置 ZRAM，实现 Linux 下的内存压缩，零成本低开销获得成倍内存扩增 - 个人文章 - SegmentFault](https://segmentfault.com/a/1190000041578292)
* [配置 ZRAM，实现 Linux 下的内存压缩，零成本低开销获得成倍内存扩增 - 知乎](https://zhuanlan.zhihu.com/p/484408336)
* [【Linux内核工具】zram的开启、挂载与使用-Crzax的博客](https://blog.zsfirst.top/zram/)
* [关于Ubuntu下ZRAM的配置和使用 - LibXZR 的小本本](https://blog.xzr.moe/archives/88/)
* [Linux zram 开启 | myfreax](https://www.myfreax.com/linux-zram-enabled/)
* \[Linux开启zram命令]
* [ubuntu开启zram彻底解决高I/O引起的卡顿，复制文件无比流畅\_ubuntu zram-CSDN博客](https://blog.csdn.net/u010066597/article/details/138431703)
* [zram: Compressed RAM-based block devices - Documentation-guide - torvalds/linux - github](https://github.com/torvalds/linux/blob/master/Documentation/admin-guide/blockdev/zram.rst)
* \[ZRAM 与磁盘交换分区对比测试]
* [TCP 网络优化配置指南 - 路飞博客](https://woniu336.github.io/p/392/)
* [VPS基本安全措施 - Raven95676 - LINUX DO](https://linux.do/t/topic/267502)
* [ufw简易使用教程 - 咸鱼的小站](https://blog.xianyu.one/2022/03/22/Linux/tutorial/ufw/)
* [简明教程｜Linux中UFW的使用 - 知乎](https://zhuanlan.zhihu.com/p/98880088)
* [ubuntu防火墙ufw使用教程 - zqifa - 博客园](https://www.cnblogs.com/zqifa/p/ubuntu-ufw-1.html)
* \[How to Set Up a Firewall with UFW on Ubuntu - DigitalOcean]
* \[UFW - \*\*\* Help Wiki - Ubuntu documentation]
* [Fail2ban详细教程 · IT迷途小书童](https://yan-jian.com/Fail2ban%E8%AF%A6%E7%BB%86%E6%95%99%E7%A8%8B.html)
* [保护好自己的服务器，fail2ban使用基本教程 - 知乎](https://zhuanlan.zhihu.com/p/528392777)
* [保护服务器，fail2ban使用教程 - 幽夜卡尔 - 博客园](https://www.cnblogs.com/Alwayslearn/p/16545500.html)
* \[I can’t get fail2ban working on Debian 12]
* [在防火墙或代理后端的fail2ban配置 - 阅心笔记](https://opswill.com/articles/iptables-fail2ban-behind-a-proxy.html)
* [怎样使用 Debian 的 ufw 和 Fail2ban - 柏舟](https://blog.thris.me/archives/ufw-and-fail2ban-firewall.html)
* [在 Debian 上安装 Docker Engine - Docker 文档](https://docs.docker.com/engine/install/debian/)
* [chaifeng/ufw-docker: 在不禁用 iptables 的情况下修复 Docker 和 UFW 的安全漏洞](https://github.com/chaifeng/ufw-docker)
* [ufw-docker 防火墙工具 - 路飞博客](https://woniu336.github.io/p/434/#%E4%B8%8B%E8%BD%BD-ufw-docker-%E8%84%9A%E6%9C%AC)
* [Nginx + SSL + Acme + Frp SSL免费证书申请+自动续期+反向代理配置 极细致教程 - 资源荟萃 - LINUX DO](https://linux.do/t/topic/427538)
* [Nginx入门必须懂3大功能配置 - Web服务器/反向代理/负载均衡 - 技术蛋老师 - bilibili](https://www.bilibili.com/video/BV1TZ421b7SD/)
* [Nginx实战 - 配置HTTPS | 数字证书和私钥 | Docker Compose容器 - 技术蛋老师 - bilibili](https://www.bilibili.com/video/BV1uH4y1w7je)
* [【GeekHour】30分钟Nginx入门教程 - bilibili](https://www.bilibili.com/video/BV1mz4y1n7PQ/)
* [这是一个 Nginx 极简教程，目的在于帮助新手快速入门 Nginx - dunwu/nginx-tutorial - GitHub](https://github.com/dunwu/nginx-tutorial)
* [Nginx配置最全详解(万字图文总结) - 知乎](https://zhuanlan.zhihu.com/p/721542933)
* [Nginx 最全操作总结 - 知乎](https://zhuanlan.zhihu.com/p/384752564)
* [Nginx全面配置 - 知乎](https://zhuanlan.zhihu.com/p/625184405)
* [分享一套Cloudflare功能系列教程（教程+实践）（强烈推荐！！！）(已完结) - 资源荟萃 - LINUX DO](https://linux.do/t/topic/170108)
* [Cloudflare - IP 范围](https://www.cloudflare.com/zh-cn/ips/)
* \[UFW仅允许CloudFlare的IP段访问80 443端口脚本 彻底防止源站泄露]
* [开源的 SSL 证书管理工具 - certimate - 路飞博客](https://woniu336.github.io/p/431/)
* [ZeroSSL 免费证书申请与自动配置 - 路飞博客](https://woniu336.github.io/p/446/)
