想知道你的 VPS 服务器到本地的真实网络速度吗?传统的测速方法常常会因为服务器的硬盘读写速度(I/O)而产生瓶颈,导致测试结果不准确。本文将向你展示一个完美、高效的解决方案:利用 Caddy Web 服务器和 Linux 的内存文件系统 tmpfs 搭建一个完全消除磁盘瓶颈的测速服务器。

核心思路

  1. 在内存中开辟一块空间,并将其挂载为一个虚拟目录(tmpfs)。
  2. 在这个内存目录中,生成一个用于测试的大文件。
  3. 配置 Caddy,使其网站根目录指向这个内存目录。

当用户请求测速文件时,Caddy 将直接从内存中读取数据并发送,整个过程行云流水。


详细搭建步骤

本教程以 Debian/Ubuntu 系统为例,其他 Linux 发行版的操作类似。

第 1 步:创建内存文件系统 (tmpfs)

首先,我们需要创建一个目录,然后将一块内存挂载到这个目录上。

  1. 创建挂载点
    我们将使用 /mnt/ramdisk 作为内存盘的挂载目录。

    sudo mkdir /mnt/ramdisk
    
  2. 临时挂载 tmpfs
    我们分配 50MB 的内存空间给这个目录,用于存放一个 30MB 的测速文件。

    sudo mount -t tmpfs -o size=50M tmpfs /mnt/ramdisk
    
    • -t tmpfs: 指定文件系统类型为 tmpfs
    • -o size=50M: 指定这个内存盘的大小为 50MB。
  3. 验证挂载

    使用 df -h 命令查看是否挂载成功。

    df -h
    

    你应该能看到类似下面的一行,证明挂载成功:

    Filesystem      Size  Used Avail Use% Mounted on
    tmpfs            50M     0   50M   0% /mnt/ramdisk
    

第 2 步:生成测速文件

现在,在刚刚创建的内存盘中生成我们的 30MB 测速文件。

提示:我们使用 /dev/urandom 作为数据源,它提供的是随机数据,比全零的 /dev/zero 更能模拟真实文件,可以有效避免网络传输链路中的压缩算法影响测速结果。

sudo dd if=/dev/urandom of=/mnt/ramdisk/testfile_30m.bin bs=1M count=30
  • if=/dev/urandom: 输入文件为随机数据源。
  • of=/mnt/ramdisk/testfile_30m.bin: 输出文件到我们的内存盘。
  • bs=1M: 设置块大小为 1MB。
  • count=30: 写入 30 个块,总计 30MB。

第 3 步:安装并配置 Caddy

  1. 安装 Caddy (以 Debian/Ubuntu 为例)

    sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https
    curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
    curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
    sudo apt update
    sudo apt install caddy
    
  2. 配置 Caddy (Caddyfile)
    编辑 Caddy 的主配置文件 /etc/caddy/Caddyfile

    sudo nano /etc/caddy/Caddyfile
    

    将文件内容完全替换为以下配置。请将 your-domain.com 替换为你的域名或 VPS 的 IP 地址。

    your-domain.com {
        # 将网站根目录指向我们创建的内存盘
        root * /mnt/ramdisk
    
        # 启用文件服务器,提供文件下载
        file_server
    
        # (重要) 为测速文件添加响应头,防止浏览器或CDN缓存
        # 这样每次测速都是从你的服务器真实拉取数据
        @nocache {
            path *.bin
        }
        header @nocache Cache-Control "no-store, no-cache, must-revalidate"
        header @nocache Pragma "no-cache"
        header @nocache Expires "0"
    
        # (可选) 允许跨域请求,如果你的测速前端页面在别处
        header Access-Control-Allow-Origin *
    
        # (可选) 开启日志记录,方便调试
        log {
            output file /var/log/caddy/access.log
        }
    }
    

第 4 步:启动 Caddy 并测试

保存 Caddyfile 后,重载或启动 Caddy 服务。

sudo systemctl reload caddy
# 或者首次启动
# sudo systemctl start caddy
# sudo systemctl enable caddy

现在,你的测速服务器已经上线!

  • 浏览器测试:访问 http://your-domain.com/testfile_30m.bin,文件将开始下载。
  • 命令行测试:使用 curl 命令,下载内容直接丢弃,只看速度。
    curl -o /dev/null http://your-domain.com/testfile_30m.bin
    

高级篇:持久化与精确测速

上面的配置是临时的,服务器重启后内存盘和文件都会丢失。下面我们让它变得永久且更专业。

1. 实现开机自动挂载和生成文件

我们需要让系统在每次启动时自动完成挂载 tmpfs 和生成测速文件的操作。

a. 开机自动挂载 tmpfs

编辑 /etc/fstab 文件,让系统启动时自动挂载内存盘。

sudo nano /etc/fstab

在文件末尾添加下面这一行并保存:

tmpfs /mnt/ramdisk tmpfs defaults,size=50M 0 0

b. 开机自动生成测速文件

我们使用 systemd 服务来管理这个过程,确保它在 Caddy 启动前完成。

  1. 创建 systemd 服务文件

    sudo nano /etc/systemd/system/create-speedtest-file.service
    
  2. 粘贴以下内容

    [Unit]
    Description=Create speedtest file in tmpfs on boot
    # 确保在 Caddy 启动前,这个文件已经被创建
    Before=caddy.service
    
    [Service]
    Type=oneshot
    RemainAfterExit=yes
    ExecStart=/usr/bin/dd if=/dev/urandom of=/mnt/ramdisk/testfile_30m.bin bs=1M count=30
    
    [Install]
    WantedBy=multi-user.target
    
  3. 启用该服务

    sudo systemctl daemon-reload           # 重新加载 systemd 配置
    sudo systemctl enable create-speedtest-file.service  # 设置开机自启
    sudo systemctl start create-speedtest-file.service   # 立即执行一次以生成文件
    

现在,你的测速服务器拥有了“金刚不坏之身”,重启后一切都会自动准备就绪。

2. 精确化配置:强制单线程下载

默认情况下,现代浏览器可能会使用多线程(范围请求 Range Requests)来下载文件,这会掩盖真实的单点连接速度。为了进行更精确的单线程测速,我们需要禁用范围请求。

这需要修改 Caddyfile,明确告诉客户端服务器不支持此功能。

a. 更新 Caddyfile

再次编辑 /etc/caddy/Caddyfile

sudo nano /etc/cany/Caddyfile

file_server 指令下方添加两行 header 配置:

your-domain.com {
    root * /mnt/ramdisk
    file_server

    # (关键) 强制单线程下载的正确方法
    # 1. 首先,移除 file_server 模块默认添加的 Accept-Ranges 头部
    header -Accept-Ranges
    # 2. 然后,明确设置该头部为 "none",告诉客户端不支持范围请求
    header Accept-Ranges none

    # ... 其他配置保持不变 ...
    @nocache {
        path *.bin
    }
    header @nocache Cache-Control "no-store, no-cache, must-revalidate"
    header @nocache Pragma "no-cache"
    header @nocache Expires "0"
  
    header Access-Control-Allow-Origin *
  
    log {
        output file /var/log/caddy/access.log
    }
}

解释header -Accept-Ranges 中的 - 前缀会移除 Caddy 的 file_server 自动添加的 Accept-Ranges: bytes 响应头。随后,header Accept-Ranges none 再加上我们自己的声明,确保万无一失。

b. 重载 Caddy 并验证

sudo systemctl reload caddy

现在,使用 curl -I 来检查响应头:

curl -I http://your-domain.com/testfile_30m.bin

你会看到如下输出,Accept-Ranges: none 表示配置成功!

HTTP/2 200
accept-ranges: none
cache-control: no-store, no-cache, must-revalidate
content-length: 31457280
content-type: application/octet-stream
...

总结

恭喜你!现在你拥有了一个专业级、高性能、高精度的测速服务器。它不仅能准确反映你服务器的带宽性能,而且对服务器自身的负载和硬盘损耗都降到了最低。这个简单而强大的组合,是每一位 VPS 玩家工具箱中都值得拥有的利器。