【转】服务器与网站的开荒入坑

作者:焕昭君 原帖地址:https://blog.huan666.de/posts/server-website-getting-started/

前言#

作者搜集各类教程自己边折腾边记录整理了以下这篇文章内容。本文概要:

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

终端软件#

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

Tabby#

官网地址 和 GitHub地址

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

FinalShell#

官网地址

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

Termora#

官网地址 GitHub地址

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

Termius#

官网地址

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

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

termius

Xterminal#

官网地址

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

参考文章
SSH 客户端收集 – 砖头@runbrick – LINUX DO
其他的,在这篇文章有人搜集了很多客户端软件

SSH远程连接#

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

  • 主机地址:即 IP地址 或 域名
  • 端口:默认是22,但你的服务商可能有所不同,还有网络策略组会限制端口放行。默认端口数字不安全,下文会介绍到如何修改端口
  • 用户:登录的用户,默认一般是root,这通常不安全下文-系统安全配置会详细介绍怎么修改用户。
  • 密码密钥:验证登录所需。常见是直接使用密码,但不安全,后续会关闭密码而使用密钥🔐

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

基础命令#

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

密钥登录#

1、生成公私密钥对#

选取 ed25519[这是什么?- Gemini深度研究🧐] 这个现代安全且高效的加密算法,在自己电脑生成密钥对。

⚠️警告

注意⚠️:如果之前有生成过密钥对或者用过其他的SSH服务如GitHub免密登录,小心密钥对被覆盖导致失效!请使用-f指定路径和文件名

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 "[email protected]"

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

2、上传公钥#

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

ssh-copy-id 命令#

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

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

编辑 authorized_keys 文件#

1.手动编辑:

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

或者自动上传编辑:

#在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.设置权限

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

3、进行连接#

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

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

日志查看:#

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

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

(
  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文件夹📂下配置覆盖生效。

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

#PubkeyAuthentication yes
#AuthorizedKeysFile	.ssh/authorized_keys

关闭密码登录

🚨小心

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

PasswordAuthentication no

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

#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远程系列插件就能使用VSCode的SSH功能远程连接服务器,有时候不想使用 Vim 或者不熟悉它,就能用”宇宙第一编辑器“──VSCode来查看和编辑服务器的文件了,实在太方便了
缺点:貌似服务器内存占用不低🙁,内存小的小鸡很可能无法承受….😫

官方文档

测试脚本#

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

融合怪测试脚本-GO版本(无环境依赖)

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

NodeScriptKit – nodeseek社区驱动脚本合集

bash <(curl -sL https://sh.nodeseek.com)

NodeQuality – 沙箱测试并排版测试结果

bash <(curl -sL https://run.NodeQuality.com)

在 【存档】Netcup的RS1000硬盘翻倍版的测试和一些测试脚本的使用 中我使用过一些测试脚本测试了我的rs1000小鸡,详细可以去看看~

重装系统#

使用一键DD重装脚本[什么是DD脚本?- Gemini深度研究🧐],比较出名的有三个:
① leitbogioro/Tools 和搭配 黑海洋Wiki 的文章
② bin456789/reinstall 这个更加整洁和方便,直接下载官方源,而且近期有更新。
③ LloydAsp/OsMutation 这个脚本适用于 OpenVZ / LXC 虚拟化技术的 VPS

bin456789/reinstall:#

下载(Linux):

img

国外服务器:

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

国内服务器:

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

安装 Debian12 改SSH端口和设置 root 密码,仅供参考命令:

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

更多请参阅 GitHub文档 …
重装完服务器系统紧接着就是要配置系统了Gemini深度研究🧐导出文档。第一时间就要去修改SSH配置如端口、密码和公私钥设置等和创建非root新用户。

系统配置#

基础优化#

更新系统的软件包#

apt update && apt upgrade -y

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

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

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

语言、地区和时区#

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

IP地址#

直接查看本地 IPv6 地址

ip -6 addr show

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

或简化版:

ip a | grep inet6

你会看到类似:

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

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

查询外网看到的 IPv6(公网出口地址)

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

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

SWAP-虚拟内存#

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

检查现有SWAP#

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

创建SWAP文件#

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

#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大小#

停用 → 删配置 → 删文件

#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大小的操作1️⃣和2️⃣

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

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

zRAM – 压缩内存#

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

手动配置zRAM#

#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'

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

# 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#

#停止并禁用 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的时候已经设置好了

sudo swapon --show		#查看所有SWAP设备
内核参数调优#

通常这三个参数保持默认即可,不调整也没啥问题**???**
具体看 路人甲的世界的这篇文章 关于不同参数调优会有更深理解。
根据文中的推荐,在使用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:调低
# 查看
sudo cat <具体路径>
sudo sysctl <参数名>
# 临时修改
sudo sysctl <参数名>=<数字>
# 永久生效
echo "<参数名>=<数字>" | sudo tee -a /etc/sysctl.conf
sudo sysctl --system
sudo sysctl -p

stress – 压测工具#

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

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 启用#

# 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 是一款开源网络性能测试工具,用于测量带宽、延迟、抖动、丢包率等网络性能指标。它通过发送和接收 TCP/UDP 数据流来评估网络的最大吞吐量,广泛应用于服务器、路由器、VPN、云服务等场景的网络调优和故障排查。
Windows 版本下载,添加iperf3.exe所在路径作为系统环境变量PATH,就能使用iperf3命令了。

#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配置#

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

添加新用户#

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

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

#假如新用户和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 生效时间:

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

UFW-防火墙#

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

❗重要

值得注意⚠️的是:UFW 和 docker 的网络不兼容,需要特殊配置!!!

安装#

sudo apt install ufw

设置默认策略#

🚨小心

⚠️注意:避免锁死 SSH!请开放对应的 SSH 端口!

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

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

#查看所有的应用程序配置文件
#所有配置都在 /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

查看添加的规则#

⚠️警告

⚠️注意:请检查是否开启 SSH 端口!自定义 SSH 端口是否正确!

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

开启防火墙#

🚨小心

警告⚠️!请再次检查是否允许 SSH 端口!以防被锁住失联

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 ufwsudo ufw --help查看。

日志查看#

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

Fail2Ban#

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

❗重要

注意⚠️:Debian12及以上因弃用rsyslog,Fail2Ban 直接安装和使用可能会有问题!需要特殊配置!

安装#

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

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

jail.local 文件配置参考:
⚠️这里在[sshd]中设置backendsystemd使得适用于 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 部分就能满足日常防御所需。

应用生效配置#

# 重启 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

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

应用安装#

Docker#

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

⚠️警告

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

安装#

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

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

一键脚本#

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

官方:#
curl -fsSL https://get.docker.com | sudo sh

测试安装步骤(不会实际安装):

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

来源脚本官方说明GitHub源仓库

国内:#
bash <(curl -sSL https://linuxmirrors.cn/docker.sh)

来源:大名鼎鼎的 linuxmirrors脚本 ,GitHub仓库

手动安装#

教程来自 – 官方安装教程(Debian系统) 的翻译和整理

卸载旧的冲突软件包#
for pkg in docker.io docker-doc docker-compose podman-docker containerd runc; do sudo apt-get remove $pkg; done
设置 Docker 的 apt 仓库#
# 添加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 软件包#
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
运行镜像验证安装#
sudo docker run hello-world
卸载#

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

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

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

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

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

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

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

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

配置#

以非 root 用户身份管理 Docker#

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

设置开启自启#

#查看当前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地址和端口即可判断。测试完成后按回车即可自动清理所有测试痕迹,不会对系统造成任何残留。

#!/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 和 ufw-docker-automated 这两个GitHub项目就是为解决这个而诞生的!

下载 ufw-docker 脚本#
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#

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

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末尾增加一块修复的规则。

ufw-docker install

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

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

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

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

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

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

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文档

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

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

运行用户安全#

未完待续…

Nginx#

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

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

安装#

#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 配置文件的层次结构

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

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

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

#备份配置文件
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

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

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 指令
# 全局块 (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

导航至:Cloudflare 账户主页 -> 选择对应域名 -> DNS -> 记录,点击 ➕添加记录,我们主要关心三种类型:AAAAACNAME

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

SSL证书#

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

加密模式#

导航至:Cloudflare 账户主页 -> 选择对应域名 -> SSL/TLS -> 概述 的页面,可以看到当前加密模式,默认是自动模式。点击 配置 按钮,我们可以自定义选择不同的模式,这将会影响:
访问者 -> Cloudflare -> 源服务器 的流量加密。
还没完! 目前只是 访问者 -> Cloudflare 这一段是流量加密的,但Cloudflare -> 源服务器这一段的流量没有加密,仍然是 HTTP !
所以需要设置加密模式为 完全(严格),这有个前提是源服务器要有一个公开可信的证书,你可以使用诸如 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_certificatessl_certificate_key就完成了~

/etc/nginx/nginx.conf文件示例:


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示例:

# 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;
}

应用生效

# 测试配置语法
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 段,把它们添加到防火墙规则了里面即可。
当然不能一个个手动添加,这里我从别处复制了一个 bash 脚本,你可以直接粘贴运行(注意可能存在的 root权限问题,可以使用sudo -i切换),或者保存成单独的脚本文件设置定期执行:

#!/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。

配置步骤#

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

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文件内容就像这样:

# 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地址范围肯定会变的,不过我看最近一次更新还是2023 年 9 月 28 日;
也可以写一个定时脚本定期获取IP地址列表。

2️⃣编辑 /etc/nginx/nginx.conf,在 http 块中引入 Cloudflare IP 配置#

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

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

real_ip_header CF-Connecting-IP;

完整示例:

/etc/nginx/nginx.conf文件:


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


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;
}

4️⃣测试并应用配置#

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

参考资料#

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇