服务器面板写着 100 Mbps,打开网站却觉得慢,这两件事未必矛盾。网页还要经过 DNS、TLS、应用查询和图片加载;套餐带宽也不等于你所在网络到这台机器的实际速度。想先把网络这一段单独看清楚,可以在 VPS 上放一个 OpenSpeedTest,用浏览器向自己的服务器上传、下载测试数据。
它适合回答一个范围明确的问题:这台设备、这条访问路径,到这台服务器,此时能跑出怎样的吞吐。换手机网络、换家庭宽带,再在同一入口测一次,就有了可比较的记录。它不能替你证明某个机房对所有地区都快,也不能用一次结果解释网站的全部加载时间。
这篇用 Docker 部署独立版本,先从只有本机能访问的入口开始,再说明如何临时开放给自己的浏览器。测速服务不需要账户体系或数据库,但也正因为如此,入口范围要另外安排。
先看清楚浏览器到底在测谁
OpenSpeedTest 的独立版本把网页和测试接口放在自己的服务器上。浏览器下载测试数据时,方向是 VPS 到浏览器,消耗 VPS 的出站带宽;浏览器上传时,方向相反,消耗 VPS 的入站带宽。两边结果不一样,并不奇怪,家用宽带、手机网络和服务器套餐本来就可能不对称。
这里用的是官方 Docker 镜像,不是把官网的测速组件嵌入自己的网页。嵌入一个外部测速组件,测的可能仍是组件提供方的服务器,不能据此判断自己的 VPS。官方的自托管说明把嵌入、托管组件和完全自托管几种方式分别列了出来,选的时候要看实际测试请求发往哪里。
如果浏览器开着代理,访问路径就包括代理节点;如果入口走了 CDN 或反向代理,请求就还经过这些中间环节。结果可以用来判断这条完整路径,却不能直接当作浏览器直连源站的成绩。尤其不要把经过缓存、压缩或额外缓冲的结果拿来解释源站公网带宽。
测速也会真正传输数据。按理论值计算,100 Mbps 持续传输 10 秒,对应约 125 MB 数据,尚未计算协议开销。这个算式不是软件每次固定消耗的流量,只是帮助理解量级。流量包不大的 VPS,不适合把入口长期公开,让陌生人反复运行。
准备一个独立目录,先只监听本机
需要一台已经安装 Docker Engine 和 Compose 插件的 Linux 服务器,以及能通过 SSH 登录的账号。本文不涉及已有站点的 Caddy、Nginx 或数据库配置,单独建目录即可。先确认 Compose 命令可用:
docker version
docker compose version
mkdir -p ~/openspeedtest
cd ~/openspeedtest
如果当前账号没有 Docker 权限,按服务器原有的管理方式使用 sudo;不要为了这一篇教程临时放宽 Docker socket 的权限。能控制 Docker 的账号通常也能影响宿主机,测速服务本身并不要求额外给普通访问者这种能力。
镜像使用 openspeedtest/latest:v2.0.6。这是 Docker 镜像的标签,不是桌面客户端的版本号;latest 在这里还是镜像仓库名称的一部分。固定 :v2.0.6 可以避免每次重建时无意换到不同镜像。后续升级前,去官方镜像说明和镜像标签页核对变化,不要仅凭名字认为它代表某年最新版本。
创建 .env:
SPEEDTEST_BIND_IP=127.0.0.1
再创建 compose.yaml:
services:
openspeedtest:
image: openspeedtest/latest:v2.0.6
restart: unless-stopped
ports:
- "${SPEEDTEST_BIND_IP:?请设置实际绑定地址}:3000:3000"
logging:
driver: json-file
options:
max-size: "20m"
max-file: "5"
SPEEDTEST_BIND_IP 是这份 Compose 文件自己定义的变量,用来决定宿主机监听地址,不是 OpenSpeedTest 内部的产品设置。初始值 127.0.0.1 表示仅在服务器回环地址发布 HTTP 端口。我们没有顺手发布 3001,也没有挂载宿主机目录或 Docker socket。
日志轮转限制的是容器日志文件,和测速传输量不是同一回事。没有数据库,不代表没有资源消耗:测速会使用网络、CPU 和连接数,和同机网站共享出口。正式比较时,最好避开大文件备份、镜像拉取等任务正在运行的时段。
启动并检查:
docker compose config
docker compose pull
docker compose up -d
docker compose ps
docker compose logs --tail=50 openspeedtest
config 用来发现变量缺失、缩进等配置问题;ps 确认容器和端口状态。容器启动成功只说明服务运行起来,还不等于公网访问已经正确,更不等于测速结果已经有代表性。
用 SSH 先确认页面,但别把隧道成绩当直连成绩
在自己的电脑上建立端口转发。把 USER 和 SERVER_IP 换成实际 SSH 用户与服务器地址:
ssh -N -L 127.0.0.1:13000:127.0.0.1:3000 USER@SERVER_IP
SSH 如果使用非默认端口,沿用自己的 -p 参数或已有 SSH 别名。保持这个终端打开,在浏览器访问 http://127.0.0.1:13000,能看到页面就可以确认容器里的网页经由隧道可达。关闭 SSH 连接后,本机这个转发入口也会消失。

上图为官方 Docker 项目文档。自己的部署是否可访问,要通过上述入口确认。
如果此时按下开始,测试数据会穿过 SSH 隧道。SSH 加密、隧道连接和两端处理能力都会参与结果。它可以用于比较同一隧道的使用体验,但不能拿来判断去掉隧道后的公网速度。只想确认安装是否正常,到这里不必跑完整测速。
很多人会在这一步看到页面就把端口改成公开监听。公开监听之前,先决定哪些客户端需要访问,再按这个范围设置网络规则。
临时直连测速,先限制来源,再开放端口
有现成 VPN 或可路由的私人网络时,可以把绑定地址改成服务器在那张网络上的实际接口地址,让浏览器经由该网络访问。这种方式的成绩包含 VPN 路径,适合衡量私人网络的传输能力。不要把内网地址填进去,却期待互联网中的设备能直接访问它。
如果要检查当前宽带到 VPS 的公网路径,可以临时开放 HTTP 3000,但应先在云平台安全组或确实生效的网络 ACL 中,只允许自己的当前公网 IPv4 /32 访问 TCP 3000。需要 IPv6 时,单独允许自己的 IPv6 /128;没有 IPv6 测试需求,就不要为这个服务新增 IPv6 放行。
先完成来源限制,再把 .env 改为:
SPEEDTEST_BIND_IP=0.0.0.0
然后重建容器:
docker compose up -d
docker compose ps
0.0.0.0 会在宿主机全部 IPv4 接口发布端口,安全组必须承担访问范围限制。公网 IP 有时由云平台做 NAT 映射,并不直接出现在服务器网卡上,因此不能总把控制台里的公网 IP 原样填成监听地址。若要绑定指定网卡,先确认该地址确实属于服务器接口,且客户端有到它的路由。
还要注意 Docker 的端口发布规则。Linux 上,Docker 通常会创建转发和 NAT 规则,已发布端口的流量可能绕过 UFW 的常规 INPUT 处理。Docker 防火墙文档专门说明了这点。因此,“UFW 没有允许 3000”不能单独证明 Docker 端口对外关闭;也不要清空 Docker、1Panel 或宿主机已有的防火墙链来试图修复。
开放后,先确认允许来源能访问,同时确认一个未放行来源不能连接。不能确认边界时,就保持回环监听或私人网络入口。本文不提供一条通用于所有云平台、Docker 后端和面板防火墙的命令,这些环境的规则位置并不相同。
从已放行的电脑访问 http://SERVER_IP:3000。这是临时的明文 HTTP 测试入口,不要在这个页面输入账户密码或其他敏感信息,也不要把它作为长期公开地址。这里选择短时直接访问,是为了减少中间代理对测试路径的影响,不表示已有网站应该撤掉 HTTPS。
如果准备长期使用域名和 HTTPS,需要单独配置经过检查的反向代理及访问控制。官方说明要求上传请求体至少能容纳 35 MB;代理默认的请求体限制、缓冲方式和协议处理可能改变上传行为。仅仅让首页返回 200,并不能证明上传接口也正常。官方源码讨论中涉及特定代理和版本的配置,不能直接当作所有现有 Caddy、Nginx 的通用配置。
测试记录要能回答问题
运行前,把浏览器代理状态、网络类型和服务器正在进行的任务记下来。手机连接家庭 Wi-Fi 和手机蜂窝网络是两条不同路径;桌面有线网卡和隔墙 Wi-Fi 也不宜混成一组数字。尽量用同一台设备、同一个浏览器,再逐项改变网络条件。
记录不必复杂。一行包含日期时间、访问入口、客户端网络、是否经过 VPN 或代理,以及页面显示的下载、上传和延迟即可。数字旁保留单位,尤其别把 Mbps 写成 MB/s。二者相差八倍,文件实际下载速度还会受协议和存储等因素影响。
不要只留最好看的那一次。若重复运行,把每次结果保留下来,间隔一会再比较;同时留意后台备份、其他访客和套餐限速。一次速度偏低只能说明当次测试结果偏低,不能直接断言运营商绕路、机房拥堵或服务器性能不足。需要定位原因时,再分别查看资源占用、请求路径和不同网络下的变化。
如果下载一直接近套餐出站上限,而上传明显更高,先看套餐入站、出站限制是否不同。如果两边都低,换一条客户端网络,可以帮助判断问题是否随客户端路径变化。如果手机很慢、同一路由器下有线电脑更快,家庭无线环境也值得检查。这些是排查顺序,不是已经确认的原因。
页面显示的延迟也不能代替网站的完整加载时间。测速请求、业务 API、图片和数据库查询可能走不同的处理过程。想改善网站,就继续查看浏览器网络面板里的请求耗时;测速入口主要帮你把一段网络传输单独拿出来观察。
首页能开,上传却失败时怎么查
先回到最简单的路径:回环监听加 SSH 转发,只用于确认服务是否可用。若简单路径正常,而域名入口异常,检查代理层的请求体大小、响应处理和访问控制,不要一开始就换服务器。跨域设置也不是登录保护;允许某个网页来源访问接口,不能阻止别人直接消耗你的测速端口。
在浏览器开发者工具的网络面板里看实际请求地址和状态码。413 往往与请求体限制有关,连接失败则先看入口、防火墙和容器状态。401、403 应检查自己的访问控制。每种情况都要对照发生在哪一层,不能只看页面上“失败”二字。
官方镜像已经带有服务测试端点的配置。自行替换内部 Nginx 配置时,要保留这些端点的行为,不能把普通静态网站配置整份覆盖上去。也不要把仓库里的历史 TLS 示例直接搬到公开服务:它解决的可能是当时的测速兼容问题,未必适合你现在的网站安全配置。
不使用反向代理的临时入口,排查范围更小,但仍需确认浏览器请求确实发往这台 VPS,而不是误打开官网测速。页面长得相似不代表服务地址相同,地址栏和请求目标比外观更可靠。
测完就收回入口
把 .env 恢复为回环地址,再应用配置:
SPEEDTEST_BIND_IP=127.0.0.1
docker compose up -d
同时删除安全组中这次临时新增的 3000 放行规则,确认公网入口已不可访问。若短期不再用,可以在项目目录运行:
docker compose down
这会停止并移除本项目的容器和网络,不需要执行全局 docker system prune,也不会替其他应用清理数据。保留 compose.yaml 和 .env,下次需要时重新启动即可。测速结果另存到自己的记录里,这个轻量服务不应被当作长期监控和报表系统。
入口收回后,一次有用的测试应留下可复查的信息:在哪条网络上,经过哪些中间节点,服务器当时有没有其他流量,以及记录的单位。下次结果发生变化时,可以先从这些条件查起。











