1. 首页 > 云服务器

Nginx配置在线测试工具怎么用?免费Playground实战教程

如果能有个 Nginx Playground 网站就好了,可以直接粘贴 Nginx 配置来测试。后来我意识到这其实很容易实现,于是就兴奋地开始写代码,把它做出来了。网址是 https://nginx-playground.wizardzines.com,源代码在 github.com/jvns/nginx-playground。

以下是屏幕截图:

在文章的剩余部分,我主要会谈谈我是如何构建这个项目的,因为其中有一些决定对我来说并不显而易见。

什么是 Nginx Playground?

简单来说,这是一个在浏览器中即可运行的 Nginx 配置沙箱环境。你无需在本地安装 Nginx,也不用担心错误配置搞崩服务器,只需在网页左侧编辑框里写入 nginx.conf 配置,右侧编写一条 curlhttp 命令,点击“运行”,系统就会在云端临时拉起一个 Nginx 实例执行你的配置,并返回执行结果或错误日志。

这种“所见即所得”的交互方式,特别适合:
- 学习 Nginx 指令语法和匹配规则
- 快速验证反向代理、负载均衡、重写规则等复杂配置
- 复现生产环境问题,进行安全隔离的调试

如何使用它

您需要同时输入 nginx 配置和命令curl才能http向该 nginx 实例发出 HTTP 请求。

然后点击右上角的“运行”,它会输出以下结果之一:

  1. 您执行的命令的结果(如果 nginx 已成功启动)
  2. nginx 错误日志(如果 nginx 启动失败)

小贴士:配置中可以使用 http://backend 作为上游地址,因为系统会自动启动一个 go-httpbin 服务(监听在 7777 端口)来充当模拟后端,方便你测试代理转发、重试、超时等高级功能。

为什么需要游乐场?

我发现游乐场真的能帮助我学习——能够快速、安全地进行实验,尝试不同的选择,而不用担心犯错后会发生什么可怕的事情,这真的非常有用。

尤其是 nginx,配置起来极其挑剔,所以我认为为 nginx 提供一个测试环境来快速测试各种功能就显得尤为重要。例如:
- 一条 location 匹配规则的细微差异(/api//api 是否带斜杠)可能导致完全不同的路由结果;
- proxy_pass 后面是否加斜杠,会影响最终请求 URL 的拼接方式;
- try_filesrewrite 的执行顺序,在没有实际运行前很难凭直觉判断。

有了 Playground,这些疑问都可以在几秒内得到验证,极大降低了试错成本。

以下是我过去制作的 3 个游乐场:

  • SQL Playground 使用 sql.js ,允许您在一些小型示例数据上运行任意 SQLite 查询。
  • CSS 示例,使用 CodePen 展示了一些令人惊讶的 CSS 行为示例,您可以亲自体验。
  • DNS 查询,即向你想要的任何网站发出 DNS 查询。

以及其他一些人制作的一些很棒的游乐场:

名称适用领域特点
CodePenCSS/JS/HTML社区庞大,支持实时协作预览
Regexr正则表达式可视化匹配过程,提供常用正则库
db-fiddleSQL(MySQL/PG/SQLite)支持多种数据库方言,可分享执行计划
nginx.viraptor.infoNginx 位置匹配用 TypeScript 重写了匹配逻辑,但仅模拟匹配,不运行完整配置

相比之下,我的 Nginx Playground 是全真运行一个完整 Nginx 进程,因此能测试更多运行时行为(如缓存、限流、SSL 握手等),而不仅是静态匹配规则。

保持简单,快速构建。

这个网站有

  1. 一个静态前端(使用 vue.js 和 tailwind,这是我常用的前端技术栈)
  2. 一个使用 Go 语言编写的后端,只有一个 API 端点,该端点只做一件事(运行 nginx 配置)。

这使得项目构建非常容易且快捷(我只需要编写一个后端接口,然后再编写一个使用该接口的前端!)。我开发的 DNS 查询 工具也是这样工作的——我非常喜欢这种方法,我想我会用同样的方法开发其他项目。

我们来谈谈当前端向后端代码发出请求时,后端代码会执行哪些操作!

当你提出请求时会发生什么?

点击“运行”按钮后,Go 后端会执行以下操作:(这里还有一个 包含当前代码的 gist)

  1. 将配置写入临时文件(路径如 /tmp/nginx-xxxxx.conf
  2. 创建一个新的网络命名空间(ip netns add $RANDOM_NAMESPACE_NAME)——这类似于轻量级虚拟网络堆栈,该空间内的网络接口、路由表、iptables 规则与宿主机隔离,并且默认无法访问外网
  3. 在 7777 端口启动 go-httpbin,以便用户可以在 nginx 配置中将其用作后端(go-httpbin 是一个 HTTP 测试服务,能返回 JSON 格式的请求头、来源 IP、响应延迟等信息,比 Python 版更轻量)
  4. 启动 nginx(使用 nginx -c $CONFIG_FILE,并指定错误日志到临时文件)
  5. 等待 100 毫秒以确保 nginx 已启动,如果启动失败,则将 nginx 的错误日志返回给客户端(常见错误如端口冲突、语法错误、路径权限问题等)
  6. 运行用户请求的命令(并确保命令以 \n``curl\n``http 开头,防止执行任意危险指令)
  7. 返回命令的输出(stdout + stderr)
  8. 清理临时文件、终止 nginx 进程、删除网络命名空间(使用 defer 确保资源释放)

术语解释:网络命名空间(Network Namespace)
Linux 内核提供的资源隔离机制,每个命名空间拥有独立的网络栈(网卡、路由表、防火墙规则)。这里将每个 Nginx 实例放入单独命名空间,即使配置中恶意监听 0.0.0.0:80,也不会影响宿主机或其他用户的端口。

安全问题

这个工具的全部意义就在于允许用户运行任意的 Nginx 配置,很容易想象这会导致服务器被入侵。但我希望免费运行这项服务,不想在服务器托管上花费太多钱。所以我只想用一台共享服务器来处理所有请求。

这种事常常让我放弃做这类项目,但这个项目我觉得更容易一些。

实际上,运行任意 Nginx 配置的风险包括但不限于:
- 利用 Nginx 模块漏洞(如 ngx_http_lua_module 执行 Lua 脚本)
- 通过 proxy_pass 访问内网服务(SSRF 攻击)
- 写入文件(如果配置了 proxy_storeclient_body_temp 路径)
- 消耗资源(CPU、内存、文件句柄)导致服务拒绝

安全策略:略微隔离,略带冒险精神

在和朋友讨论之后,我决定先从以下方式着手解决安全问题:

  1. 将前端托管在 CDN 上,与后端分开(这样,即使后端遭到入侵,也不会有人通过前端传播恶意软件)。
  2. 不要使用数据库,直接使用浏览器本地存储(如果没有数据库,就无法入侵数据库!)
  3. 将每个 nginx 实例放在各自的网络命名空间中,不要让它连接到互联网(即 ip netns exec 时禁用默认路由,且不配置 NAT 转发,所以无法访问外网)。
  4. 使用 fly.io 的免费套餐(这样它就隔离在自己的虚拟机上,据我所知它无法访问任何敏感信息,而且如果需要的话,我可以每小时销毁并重新部署虚拟机)。
  5. 在常见问题解答中要求大家友善待人(这就是“YOLO”的精髓所在:))。

我认为在这些限制条件下,唯一可能发生的坏事是:

a. 有人获取了其他同时使用该网站的用户的测试版 Nginx 配置(因为临时文件命名空间隔离,实际概率很低)。
b. 有人替换了后端 API 服务器,使其返回恶意或攻击性输出(但 fly.io 每重启一次会重置环境)。
c. 有人试图在运行该网站的小型实例(1 个共享 CPU,256 MB 内存)上挖比特币(但 CPU 资源受限,且网络隔离,矿池通信会被阻断)。

我觉得从整体上看,这些东西都不算太危险,当然也可能是我忽略了什么。已经有人演示过如何读取这个 /etc/passwd 文件了,挺有意思的,不过里面并没有什么敏感信息。

我之后可能会把每个 nginx 都放在一个容器里运行(如 Docker),而不是放在一个网络命名空间里运行,但我一开始没这么做是因为我觉得这样速度可能会太慢——其实现在速度已经有点慢了。容器虽然隔离性更强(拥有独立的文件系统、用户命名空间),但启动开销比网络命名空间要大,尤其是镜像拉取和层解压会显著增加响应时间。未来若采用容器,可考虑使用 gvisorfirecracker 提供更强的安全边界。

专家建议:对于类似在线沙箱,最低限度应采用 网络命名空间 + 只读文件系统 + cgroup 资源限制。若对安全性要求更高,建议使用专门的虚拟机或微虚机(如 AWS Firecracker),并设置每次运行后自动销毁实例。

关于性能的一些说明

正如我之前提到的,这个后端运行在一个非常小的实例上(1 个共享 CPU,256 MB 内存)。以下是一些相关说明:

  1. 前端运行在 CDN 上,因此只有当有人实际执行 nginx 配置时才会调用后端。这大大减轻了小型后端服务器的压力。
  2. 根据服务器日志,目前每个请求大约需要 400 毫秒。这还不错!(其中包含网络命名空间创建、nginx 启动、go-httpbin 启动、执行 curl 和清理等步骤)
  3. 它目前运行在多伦多的服务器上,所以对于远离多伦多的人来说速度可能会比较慢。不过我可以通过在更多地点运行更多飞行服务器来解决这个问题(fly.io 支持全球多区域部署)。
  4. 我使用了 httpbin 的 Go 克隆版本,而不是原始的 Python 版本,因为我认为 Go 版本会更轻量级(Python 版本每个请求需要 fork 进程,而 Go 版本是协程并发,内存占用更低)。
  5. 前端性能不太好——CSS 和 JS 都放在不同的文件中。我不想用 npm build 构建步骤把它们合并,因为我的 JavaScript 水平很差,总是担心 JavaScript 构建会出错,然后我又懒得去修复,最后就没法部署更改了。但如果你有前端工程化经验,可以考虑用 Vite 或 Webpack 进行打包压缩,提升加载速度。
  6. 我添加了一个火箭飞行动画,会在后端运行期间播放,这样等待的时候就不会那么无聊了。

我遇到的最愚蠢的性能问题是,我最初是通过发送 SIGKILL 信号来停止 nginx 工作进程的。但这只会终止主进程,而不会终止工作进程,导致 nginx 工作进程泄漏,最终造成实例内存耗尽。后来我改用 nginx 进程的 SIGTERM 信号,它就能正确地关闭所有进程,从而解决了这个问题。

注意事项:生产环境中的 nginx 停止应始终使用 nginx -s quit(SIGQUIT)或 nginx -s stop(SIGTERM),避免直接 kill -9 导致子进程僵死。在 Go 中,可以通过 cmd.Process.Signal(syscall.SIGTERM) 优雅终止。

设计

这个设计基本上就是照搬了 jsfiddle 和 codepen。

JSFiddle 特别巧妙地实现了一个简单易行的功能:它计算主区域的高度,calc(100vh - 60px) 而标题的高度也由另一个高度决定 60px。我自己肯定想不到这一点,但它确实效果很好。

我用 CodeMirror 做语法高亮,因为 jsfiddle 和 codepen 似乎都支持这个功能,设置起来超级简单,而且它居然还有高亮 nginx 和高亮 shell 模式!简直完美,满足了我所有的期待 :)

CodeMirror 的 nginx 模式能识别 serverlocationproxy_pass 等指令并着色,shell 模式则对 curl 参数和 URL 进行高亮,大大提升了可读性。

使用 CodeMirror 的主要问题是,我最初想使用一个 vue-codemirror 集成,但 Vue 3 没有现成的集成。不过后来我觉得没必要,就自己写了一个很小的集成,当文本框更新时,Vue 也会更新。(基本上就是这样 this.nginx_codemirror.on('change', cm => this.nginx_config = cm.getValue())

您可以在 script.js 中看到 Javascript 代码,但实际上代码量并不多。

未来可能的改进方向

当前项目已经能很好满足基本测试需求,但若继续迭代,以下方向值得考虑:

  • 支持多版本 Nginx:允许用户在界面选择 Nginx 1.18、1.20 或最新主线版,方便测试不同版本的行为差异。
  • 保存与分享配置:通过 URL 参数编码配置内容,实现“一键分享”给同事或社区,类似 CodePen 的“Save”功能。
  • 内置常用配置模板:如静态文件服务、反向代理、负载均衡、SSL 终止等,帮助新手快速上手。
  • 更详细的错误诊断:不仅返回错误日志,还能给出高亮提示和修复建议(如“location 缺少斜杠可能导致 404”)。
  • 实时统计资源消耗:显示每次运行的内存、CPU 使用量,让用户感知配置对性能的影响。

结语

这个 Nginx Playground 虽然简单,但充分体现了“小工具解决大痛点”的理念。如果你也是 Nginx 学习者或日常维护者,不妨把它加入收藏夹,下次遇到疑难配置时,先用它验证一下,再应用到生产环境。欢迎使用,也欢迎提交 Issue 和 PR 共同改进!

本文由主机测评网发布,不代表主机测评网立场,转载联系作者并注明出处:https://zhuji.jb51.net/yunfuwuqi/9539.html

联系我们

在线咨询:点击这里给我发消息

Q Q:2220678578