如何在 Ubiquiti 路由器上使用 nginx 作为反向代理

Dav*_*ard 1 linux router nginx reverse-proxy

几天来,我一直在尝试设置我的 Ubiquiti ErPoe-5(固件 1.9.1)以使用 nginx 运行反向代理,似乎我的大部分麻烦都是由于我无法获得设备上最新版本的 nginx。

我看过的关于在其上安装 nginx的教程只让我知道 nginx 1.2,它不支持 websockets 或 HTTP2。HTTP2 不是必需的,但对于我想通过反向代理公开的内部资源,websockets 支持是必须的。事实上,路由器本身在其自己的 Web 管理界面中使用它们,并且从ubiquiti 论坛中的这篇文章中可以看出,您可能也需要 HTTP2。

Dav*_*ard 6

注意:升级到固件 2.x 或更高版本将允许您使用新的 Stretch 存储库,如问题中链接教程中所述。Stretch 存储库将 nginx 包更新到 1.10,它支持 websockets 和 HTTP2。但是,下面的步骤和脚本在 2.x 下仍然适用,因此不会更新答案以反映新的固件/软件包版本,以避免任何不想升级到 2.x 固件(初始版本)的人混淆固件的一些问题给早期采用者带来了一些麻烦,并且 2.x 固件版本中仍然存在已知的性能下降问题)。

注意 2:此答案假设您对常见的 Linux 命令有足够的了解和/或至少能够通过 SSH 登录到您的路由器。如果你不这样做,那么你应该在继续之前复习你的技能以满足这些先决条件,因为我不打算在答案或后续评论中介绍 Linux 脚本或命令的基础知识。


背景信息和免责声明(1.2 是安全的,但 1.14 有效)

在固件 2.x 版本之前,Ubiquiti 路由器基于 Debian 7.11 - 即。wheezy - 因此,在不违反规范的情况下,您将获得的最佳版本是 nginx 1.6(通过使用wheezy-backports存储库而不是wheezy. 这将适用于 websocket 支持,但仍会缺少诸如 http2 之类的较新选项。

要获得 1.14 等较新版本,您必须稍微走出舒适区并开始使用较新的 Debian 9.5 存储库 - 即stretchstretch-backports. 我说“走出你的舒适区”并不是因为体验不好,而是因为逻辑决定了 Ubiquitiwheezy在 2.x 之前的固件版本的路由器上使用可能是有原因的。因此,stretch当软件包依赖于升级路由器可能正在使用的其他软件包(即 libc6)时,使用软件包意味着一些风险。

因此,虽然我不能说下面的解决方案不会破坏路由器上的任何功能,但我可以说我使用了相当数量的路由器功能(包括 openvpn 服务器/客户端、负载平衡和 VLAN)并且我没有没有任何问题。

我还能够成功地重新刷新当前版本的 Ubiquiti EdgeMax 操作系统/固件 (2.0.8),没有任何问题将所有包恢复到它们的库存/默认版本。(但请注意,重新刷新固件也会擦除您所做的任何未存储在/config目录中的调整/自定义- 始终将它们存储在/config某处,然后添加一个启动脚本以/config/scripts/post-config.d在其他位置维护到它们的链接如所须)

所以,我觉得很舒服地说,在这次安装之后,未来的 Ubiquiti 更新可能会安装得很好——尽管你必须再次重新安装 nginx(可能使用下面的脚本)。

现在通常的免责声明已经不存在了,这就是对我有用的方法。


我的解决方案(打破规则并获得 1.14)

安全第一

  1. 备份您的配置

  2. 如果您已经在尝试安装 nginx,那么继续并重新安装最新的固件可能也是一个好主意,以便让一切恢复到一个良好的基点(如果您进行了任何调整,请小心/通常的 CLI 配置或 Web 界面选项之外的自定义 - 您可能会丢失它们)。

  3. 由于您将修补驱动 Web 界面的服务,因此熟悉从 SSH 刷新固件更新所需的命令可能是明智之举(提示:)add system image https://dl.ui.com/firmwares/edgemax/v1.10.x/ER-e100.v1.10.10.5210345.tar

现在是有趣的部分

SSH* 进入您的路由器并运行以下脚本(或等效语句),它将:

  • 设置适当的 Debian 存储库 (stretchstretch-backports)
  • 将存储库优先级设置为首选stretch-backports(如果您想使用 nginx 1.10.3,请修改下面的脚本以首选,stretch而不是stretch-backports将其从优先级中删除 - 910)
  • 配置一个启动脚本,用于在每次系统启动时创建 nginx 日志目录(否则路由器重启时 nginx 不会启动)
  • 下载/安装最新的稳定版nginx-light包(撰写本文时为 1.14.0)。

*您应使用CLI功能在Web界面为SSH的替代品,因为Web界面将有可能成为作为这个过程的一部分暂时不可用。

#! /bin/bash

vcfg=/opt/vyatta/sbin/vyatta-cfg-cmd-wrapper

echo Updating package repositories ...
echo

$vcfg begin

$vcfg delete system package

$vcfg set system package repository stretch url http://http.us.debian.org/debian
$vcfg set system package repository stretch components "main contrib non-free"
$vcfg set system package repository stretch distribution stretch

$vcfg set system package repository stretch-backports url http://http.us.debian.org/debian
$vcfg set system package repository stretch-backports components "main contrib non-free"
$vcfg set system package repository stretch-backports distribution stretch-backports

$vcfg commit

$vcfg end

apt-get update

echo
echo Setting repository priorities ...
echo

echo "Package: *
Pin: release a=stretch
Pin-Priority: 900

Package: *
Pin: release a=stretch-backports
Pin-Priority: 910">/etc/apt/preferences.d/stretch

echo
echo Temporarily stopping the current web interface ...
echo
kill -SIGTERM $(cat /var/run/lighttpd.pid)

echo
echo Installing nginx-light ...
echo

echo "#! /bin/bash
[ -d /var/log/nginx ] || mkdir /var/log/nginx">/config/scripts/post-config.d/create_nginx_log_dir
chmod a+x /config/scripts/post-config.d/create_nginx_log_dir

[ -d /var/log/nginx ] || mkdir /var/log/nginx

apt-get install nginx-light -V -y

echo
echo Restarting the old web interface ...
echo
service nginx stop
/usr/sbin/lighttpd -f /etc/lighttpd/lighttpd.conf

echo
echo Updating the nginx default site listen on non-standard ports ...
echo

sed -i -E 's/^(\s*)(listen\s+(:|\[|\])*)([0-9]+)(;|\s)/\1\2\4\4\5/g' /etc/nginx/sites-enabled/default

echo
echo Starting the nginx service ...
echo

service nginx start

echo
echo Installation complete.
Run Code Online (Sandbox Code Playgroud)

[Enter关于重启服务的提示回答“y ”]

现在你应该有一个可以工作的 nginx 安装,你应该能够通过http://<router IP address>:8080在你的 web 浏览器中导航到来测试它。请注意,其使用端口8080应该由sed上面脚本中的命令配置,而不是80可能与默认路由器 Web 界面冲突的默认端口。

nginx 会作为路由器的反向代理吗?

我个人更喜欢为lighttpd路由器上默认提供的服务/GUI使用非标准端口(下面示例配置中的 553),然后使用 nginx(侦听标准端口 80/443)作为lighttpd. 这让我可以为我的所有本地网络网站使用一个域名,包括路由器(即 router.myhouse.com、nas.myhouse.com 等)如果您希望这样做,您可以使用configure -> set service gui http(s)-port ###声明或通过Config Tree在 Web 界面/GUI 部分进行相同的更改。

使用反向代理配置文件配置 nginx

接下来,您需要将 nginx 配置为充当某些资源的反向代理。通常,这将是一个本地网络资源,可通过在 URL 中使用特定主机/域名来访问,该 URL 解析为路由器的 nginx 侦听端口。

为此,您需要在您的/etc/nginx/sites-enabled目录中创建一个 nginx 配置文件(或者最好在下面创建它/config/user-data,然后在该/etc/nginx/sites-enabled目录下创建一个指向该文件的链接- 这将更容易从重置/etc目录内容的升级中恢复)。

网上有很多 nginx 配置文件的例子,但如果你打算将你的路由器接口(或其他一些使用 websockets 的网站)放在 nginx 反向代理后面,下面的例子可能会证明是有益的。或者,如果您特别希望将 Synology NAS 置于其后(尤其是照片站有点棘手)。

upstream edgemax {
  server 192.168.1.1:553;
  keepalive 32;
}

upstream nas {
  server 192.168.1.7:5001;
  keepalive 32;
}

upstream nasphoto {
  server 192.168.1.5:443;
  keepalive 32;
}

upstream nasfile {
  server 192.168.1.7:7001;
  keepalive 32;
}

server {
  listen 443 ssl http2;
  server_name router.*;
  
  ssl_certificate /config/user-data/ssl_chain_key.pem;
  ssl_certificate_key /config/user-data/ssl_chain_key.pem;
  
  client_max_body_size 0;
  proxy_http_version 1.1;
  proxy_buffering off;
  proxy_set_header Upgrade $http_upgrade;
  proxy_set_header Connection "Upgrade";
  proxy_set_header Host $host;
  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  
  location / {
    proxy_pass https://edgemax;
  }
}

server {
  listen 443 ssl http2;
  server_name nas.*;
  
  ssl_certificate /config/user-data/ssl_chain_key.pem;
  ssl_certificate_key /config/user-data/ssl_chain_key.pem;

  client_max_body_size 0;
  proxy_http_version 1.1;
  proxy_buffering off;
  proxy_set_header Upgrade $http_upgrade;
  proxy_set_header Connection "Upgrade";
  proxy_set_header Host $host;
  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header X-Forward-For $proxy_add_x_forwarded_for;

  location / {
    proxy_pass https://nas;
  }
  
  location /photo {
    proxy_pass https://nasphoto/photo;
  }
}

server {
  listen 443 ssl http2;
  server_name files.*;

  ssl_certificate /config/user-data/ssl_chain_key.pem;
  ssl_certificate_key /config/user-data/ssl_chain_key.pem;

  client_max_body_size 0;
  proxy_http_version 1.1;
  proxy_buffering off;
  proxy_set_header Upgrade $http_upgrade;
  proxy_set_header Connection "Upgrade";
  proxy_set_header Host $host;
  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header X-Forward-For $proxy_add_x_forwarded_for;

  location / {
    proxy_pass https://nasfile;
  }
}

server {
  listen 443 ssl http2;
  server_name photos.*;
 
  ssl_certificate /config/user-data/ssl_chain_key.pem;
  ssl_certificate_key /config/user-data/ssl_chain_key.pem;

  client_max_body_size 0;
  proxy_http_version 1.1;
  proxy_buffering off;
  proxy_set_header Upgrade $http_upgrade;
  proxy_set_header Connection "Upgrade";
  proxy_set_header Host $host;
  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header X-Forward-For $proxy_add_x_forwarded_for;
  
  rewrite ^/photo/(.*)$ /$1;
  
  location / {
    proxy_pass https://nasphoto/photo/;
  }
}
Run Code Online (Sandbox Code Playgroud)

一旦反向代理配置文件就位,您可以运行sudo service nginx restart以使其生效。/var/log/nginx/error.log有问题请参考。

提示 #1:如果您计划为您的 nginx 反向代理使用非标准端口(即,您的反向代理的配置说明除了listen 80and/or之外的其他内容listen 443),那么您可能会很好地替换proxy_set_header Host $host;上述配置与proxy_set_header Host $http_host;. 这对于似乎总是想让 Web 客户端从默认端口请求流量的 websocket 尤其重要——否则会导致接口丢失组件或实时数据。(您也可以尝试proxy_set_header Host $host:$server_port;,但请注意,这明显不同,因为即使原始请求中未使用端口,它也会始终向标头添加端口)

提示#2:还要注意使用server_name router.*which 仅仅意味着使用 URLrouter.<anything>.<anything>浏览 nginx 反向代理将导致应用该部分的配置。(您会发现大多数示例都使用完整/显式域名,例如router.domain.com

这不仅对于可能更改域名/dns 名称的目的很有用(即router.home.com,在router.home.net不更改配置的情况下工作),而且有助于保持您的server_name条目简短。这很重要,因为当您启动 nginx 时,长名称通常会导致错误提示“增加存储桶大小”。如果您必须有长名称,那么您可能需要在配置中调整server_names_hash_max_size和/或server_names_hash_bucket_size的值。


更新: 我已成功将我的路由器从 EdgeOS 1.9.1 版更新到 2.0.8 之间(包括 2.0.8 版)的每个版本,基本上零问题。更新后路由器上没有 nginx(正如预期的那样),但是我能够运行我的脚本(此答案中的第一个代码块)并且它又回来了。保持您的自定义/config并使用脚本/config/scripts/post-config.d来维护在重新启动/升级后无法生存的任何更改是在这里顺利航行的关键。

更新 #2: 此过程也适用于较小的路由器,例如 ER-X。但是,由于设备上可用的存储空间有限,您将被迫删除不活动的固件映像以为 nginx 腾出空间。这也需要在每次更新后完成。要删除不活动的固件映像,请运行delete system image并对提示回答是。

-- 我的 ER-X 更新过程 --

  1. 备份我的配置!!!!
  2. 更新到最新固件并重新启动(并验证除 nginx 之外的基本功能)
  3. 使用delete system image命令删除旧固件(现在是非活动映像)(show system storage报告删除前使用了76%,之后使用了 37%)
  4. 验证外部 ping 工作(ping 8.8.8.8),如果没有,则重新启动路由器。这是最近固件版本中的一个已知问题,与此过程或使用的脚本无关。
  5. 使用上面的脚本/步骤重新安装nginx(安装show system storage后报告71%在使用)
  6. 运行sudo apt-get clean以释放临时文件等使用的空间(show system storage报告清理后使用了 56%)