SSD Nodes Learn Hosting plans →
指南 Matt Connor作者: Matt Connor · 更新于 2026-08-16

如何在VPS上运行UniFi控制器

了解UniFi Network Application的VPS部署:2 GB为最低内存、4 GB更稳妥,使用Docker和MongoDB,通过set-inform进行三层网络采用,并说明应保持私有的端口。

VPS 上的 UniFi 控制器实际负责什么

VPS 上的 UniFi 控制器是一台管理服务器。只要它保持可访问,即使所管理的站点发生故障,它仍可运行。该软件是 Ubiquiti 的 UniFi Network Application:一个以 Java 编写、后端使用 MongoDB 数据库的程序。它负责配置接入点和交换机、存储这些设备的统计信息,并提供管理界面。它不承载客户端网络流量。

这一点决定了控制器的部署位置。将控制器放在所管理的办公室内,办公室网络和用于查看该网络的工具可能会在同一分钟同时不可用。将控制器放在具有稳定公网地址的 VPS 上,它就能持续运行、持续收集数据,并从一个位置管理多个站点的设备。控制器需要的是高可用性,而不是高计算性能。

控制器离线时,已采用的接入点和交换机会继续使用已下发的配置转发流量。您会失去管理面板和统计信息,以及所有要求控制器在线的功能,例如访客门户登录;如果控制器同时充当 RADIUS 服务器,也会失去 RADIUS(远程身份验证拨入用户服务)功能。客户端仍会保持连接。

UniFi 控制器需要多少 RAM?

2 GB 是最低要求,4 GB 是建议购买的配置。同一台服务器上有两个内存消耗者:Java 和 MongoDB。它们会分别确定自身的内存需求。

Java 堆受 MEM_LIMIT 限制,容器镜像默认将其设置为 1024 MB。另一部分内存由 MongoDB 使用。其 WiredTiger 存储引擎会将缓存设置为高于 1 GB 的 RAM 的一半,或 256 MB,取两者中的较大值。在 2 GB VPS 上,这大约意味着 512 MB 缓存、1 GB 堆、JVM 自身的非堆内存,以及操作系统占用的内存。系统在负载较低时可以运行,但繁忙时段可能触发内核的 out-of-memory killer,终止两个进程中的一个。出现无法解释的重启后,运行 dmesg -T | grep -i 'killed process',确认是否发生了这种情况。如果只有 2 GB RAM,请添加 swap 文件。

CPU 和磁盘的要求不高。一个或两个 vCPU 足以处理几十台设备。先分配 20 GB 磁盘并持续监控,因为数据库会随着客户端数量和统计数据保留时间增长。单独运行控制器时,4 GB 服务器的大部分内存都会闲置。因此,如果计划在同一台服务器上运行其他服务,应优先按该服务的需求分配资源,因为 PhotoPrism 和 Immich 的最低 RAM 要求差异很大,而且它们中的任意一个所需内存都高于控制器。

有一个 CPU 特性很重要,但在低价套餐中很容易被忽略:

grep -m1 -o avx /proc/cpuinfo

MongoDB 5.0 及更高版本需要 x86_64 硬件支持 AVX(高级向量扩展)。如果该命令没有输出内容,mongod 会在启动期间退出,容器也会不断重启,因为二进制程序执行了 CPU 不支持的指令。较旧的 Intel Celeron 和 Pentium 主机通常会导致此问题,隐藏 CPU 标志的虚拟机管理程序也可能导致此问题。MongoDB 4.4 不需要 AVX,是唯一的回退方案,但上游已经不再为该数据库版本提供补丁。迁移到使用较新 CPU 的主机是更好的解决方案。在 ARM VPS 上不会遇到这个问题,因为 AVX 属于 x86 指令集,并且两个镜像都提供 arm64 构建版本。如果要在两者之间选择,ARM 和 x86 VPS 套餐之间的差异不只体现在价格上。

使用 Docker Compose 安装 UniFi Network Application

Docker 是最少意外的方案,因为它可以将 MongoDB 固定到应用支持的版本,而不是直接使用发行版提供的版本。如果服务器上还没有 Docker,请先在 VPS 上安装 Docker

mkdir -p ~/unifi/config ~/unifi/db
cd ~/unifi

应用登录 MongoDB 前,MongoDB 必须先创建用户。官方 MongoDB 镜像在首次启动时,会运行它在 /docker-entrypoint-initdb.d 中找到的所有脚本。将以下内容保存为 ~/unifi/init-mongo.sh

#!/bin/bash
if which mongosh > /dev/null 2>&1; then
  mongo_init_bin='mongosh'
else
  mongo_init_bin='mongo'
fi
"${mongo_init_bin}" <<EOF
use ${MONGO_AUTHSOURCE}
db.auth("${MONGO_INITDB_ROOT_USERNAME}", "${MONGO_INITDB_ROOT_PASSWORD}")
db.createUser({
  user: "${MONGO_USER}",
  pwd: "${MONGO_PASS}",
  roles: [
    "clusterMonitor",
    { db: "${MONGO_DBNAME}", role: "dbOwner" },
    { db: "${MONGO_DBNAME}_stat", role: "dbOwner" },
    { db: "${MONGO_DBNAME}_audit", role: "dbOwner" },
    { db: "${MONGO_DBNAME}_restore", role: "dbOwner" }
  ]
})
EOF

该脚本在数据库目录为空时运行。如果首次使用错误的密码启动堆栈,用户就会以错误密码创建。之后编辑 Compose 文件不会产生任何变化,因为脚本不会再次运行。此时的表现是应用容器持续记录 MongoDB 身份验证失败,而 Web 界面始终无法显示。全新安装时,解决方法是停止堆栈,删除 ~/unifi/db,然后重新启动。

然后写入 ~/unifi/compose.yaml

services:
  unifi-db:
    image: docker.io/mongo:8.0
    container_name: unifi-db
    environment:
      - MONGO_INITDB_ROOT_USERNAME=root
      - MONGO_INITDB_ROOT_PASSWORD=change-this-root-password
      - MONGO_USER=unifi
      - MONGO_PASS=change-this-unifi-password
      - MONGO_DBNAME=unifi
      - MONGO_AUTHSOURCE=admin
    volumes:
      - ./db:/data/db
      - ./init-mongo.sh:/docker-entrypoint-initdb.d/init-mongo.sh:ro
    restart: unless-stopped

  unifi-network-application:
    image: lscr.io/linuxserver/unifi-network-application:10.5.67-ls141
    container_name: unifi-network-application
    depends_on:
      - unifi-db
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Etc/UTC
      - MONGO_USER=unifi
      - MONGO_PASS=change-this-unifi-password
      - MONGO_HOST=unifi-db
      - MONGO_PORT=27017
      - MONGO_DBNAME=unifi
      - MONGO_AUTHSOURCE=admin
      - MEM_LIMIT=1024
      - MEM_STARTUP=1024
    volumes:
      - ./config:/config
    ports:
      - "8080:8080"
      - "3478:3478/udp"
      - "127.0.0.1:8443:8443"
    restart: unless-stopped

这里有意固定了两个镜像标签。10.5.67-ls141 是 2026 年 8 月的当前应用版本,因此安装时请查看镜像的发布列表,并固定当时的当前版本。数据库标签更重要。MongoDB 不会自动跨主要版本升级数据文件,因此 mongo:latest 未来可能拉取新的主要版本,拒绝打开现有文件,并不断重启。请固定主要版本,并有计划地升级。UniFi Network 8.1 及更高版本支持 MongoDB 3.6 到 7.0,9.0 新增了对 MongoDB 8.0 的支持。

PUIDPGID 必须与主机上的实际用户匹配,否则 ./config 下的文件最终会归属于无法写入这些文件的用户标识。运行 id 获取当前值。了解容器镜像中的 PUID 和 PGID 工作方式,其中介绍了不匹配时的表现。

启动堆栈并监控日志:

docker compose up -d
docker compose ps
docker compose logs -f unifi-network-application

docker compose ps 应显示两个容器均为 running。如果 unifi-db 停留在 restarting,原因可能是前文所述的 AVX 问题,也可能是 ./db 的权限问题。日志稳定后,检查两个监听端口:

curl -sk -o /dev/null -w '%{http_code}\n' https://127.0.0.1:8443/
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8080/inform

只要返回任意 HTTP 状态码,就表示监听器已绑定并能响应。Connection refused 表示应用仍在启动。首次运行时,小型 VPS 可能需要一两分钟;也可能表示应用根本没有启动。

在不暴露管理界面的情况下访问它

上面的文件将端口 8443 发布到 127.0.0.1,因此 VPS 外部的任何主机都无法访问管理界面。通过 SSH 将其转发出来,以运行设置向导:

ssh -L 8443:127.0.0.1:8443 you@vps.example.com

保持该会话打开,然后访问 https://127.0.0.1:8443。证书是自签名证书,因此浏览器只会警告一次。创建管理员帐户,为站点命名,暂时跳过设备接入。

SSH 隧道适合单个管理员使用。对于团队,应为 VPS 配置一个私有地址,并让管理界面绑定到该地址。在自己的 VPS 上配置 WireGuard VPN配置 Tailscale 子网路由器 都可以提供一个只有团队成员能够路由访问的地址。使用 WireGuard 时,将发布端口改为 10.8.0.1:8443:8443;使用 Tailscale 时,将其改为 Tailscale 分配的地址。需要注意:Docker 无法发布到尚不存在的地址,因此隧道接口必须在容器启动前就已启动,否则容器会因绑定错误而启动失败。

为什么远程 UniFi 设备无法采用

UniFi 设备开箱后会通过本地网络上的 UDP 端口 10001 进行广播,以查找控制器。广播不会离开 LAN,因此,位于另一座城市办公室中的设备永远无法发现 VPS 上的控制器。这就是三层采用,也是大多数人遇到问题的地方。设备本身没有故障,控制器也没有故障。只是没有任何配置告诉设备应向哪里查找。

首先,告诉控制器应向设备提供哪个地址。在控制器的 Settings 中,进入 System 部分,找到带有 override 选项的 inform host 设置。将其设置为 VPS 的公网主机名或 IP。否则,控制器会通告其自身接口上看到的地址。在 Docker bridge 网络中,这通常是类似 172.18.0.3 的私有地址。设备收到该地址后无法路由到它,于是会重新开始搜索。

然后,让设备连接到该地址。通过 SSH 连接到远程 LAN 中的设备。恢复出厂设置的设备接受用户名 ubnt 和密码 ubnt

ssh ubnt@192.168.1.20
set-inform http://vps.example.com:8080/inform

较新的设备固件会进入菜单,而不是 shell。将相同操作作为单条命令运行:

ssh ubnt@192.168.1.20 mca-cli-op set-inform http://vps.example.com:8080/inform

此时,设备会在控制器中显示为可以采用。单击 Adopt,状态会变为 Adopting。这里最容易让人困惑:通常必须再次运行 set-inform。设备会重启并进入配置流程,然后回退到其自身配置中保存的 inform URL,而控制器尚未完成替换该 URL。状态显示为 Adopting 时再次运行该命令,即可完成交接。在设备上输入 info,可以查看它当前保存的 inform URL 和状态。

如果设备之前已被其他控制器采用,仅运行 set-inform 无法完成操作,因为设备仍保存着原控制器的凭据。请先将其恢复为出厂设置。可以按下 reset 按钮,也可以使用旧凭据通过 SSH 运行 set-default

如果设备数量超过少数几台,请改用 DHCP。DHCP(动态主机配置协议)选项 43 携带供应商特定值,UniFi 设备会从子选项 2 中读取 inform URL。在任意 Linux 主机上生成十六进制字符串:

URL="http://vps.example.com:8080/inform"
HEX=$(printf '%s' "$URL" | od -An -tx1 | tr -d ' \n')
printf '02%02x%s\n' "${#URL}" "$HEX"

对于 http://192.168.3.10:8080/inform 这个 31 字节字符串,命令会输出 021f687474703a2f2f3139322e3136382e332e31303a383038302f696e666f726d。将结果作为十六进制值粘贴到路由器的 DHCP option 43 字段中。之后,在该网络上启动的每台设备都会从 DHCP 租约中获知控制器地址,无需使用 SSH。较早的指南会使用子选项 1,即 0104 后接 IPv4 地址的 4 个十六进制字节;设备仍然接受这种格式。

如果站点运行 DNS,还有第三种方式。UniFi 设备启动时会尝试解析主机名 unifi。因此,创建一个指向 VPS 地址的 unifi A 记录后,设备无需逐台配置即可采用。此方法仅适用于您能够控制设备实际使用的 DNS 解析器的网络。

要开放哪些 UniFi 端口,哪些端口应保持私有

只有2个端口需要从远程站点访问。

  • TCP 8080 是 inform 通道,所有已采用的设备都会连接到此端口。通道中的负载使用控制器在设备采用期间提供的密钥进行 AES 加密,因此这里通常使用普通 HTTP。
  • UDP 3478 用于 STUN(NAT 会话穿越工具),设备通过它保持返回控制器的路径。

在 VPS 上,其他端口都应保持关闭。

  • TCP 8443 是管理界面。此端口绝不能公开。它保存控制器管理的所有站点配置,而这些配置只受一个密码保护。
  • UDP 10001 和 UDP 1900 用于广播发现。广播不会跨越互联网,因此开放这些端口没有作用。
  • TCP 8880 和 TCP 8843 用于访客门户重定向。只有运行访客门户时才开放。
  • TCP 6789 用于移动测速,UDP 5514 用于远程 syslog。使用这些功能时再添加相应端口。
  • TCP 27117 是 MongoDB。在上面的 compose 文件中,数据库完全没有发布端口,因此它只存在于内部 Docker 网络中。应保持这种配置。

如果站点使用静态公网地址,则只允许这些地址:

sudo ufw allow OpenSSH
sudo ufw allow proto tcp from 203.0.113.4 to any port 8080
sudo ufw allow proto udp from 203.0.113.4 to any port 3478
sudo ufw enable
sudo ufw status verbose

VPS 防火墙的 ufw 基础介绍了这些规则所依赖的默认拒绝配置。

这里有一个经常导致问题的陷阱:Docker 发布的端口会绕过 ufw。 发布端口会直接将 NAT 和转发规则写入 iptables,相关流量由 Docker 自己的链过滤,而不是由 ufw 管理的 INPUT 链过滤。因此,ufw deny 8443ufw status中看起来配置正确,但端口仍会对全网开放。应从另一台机器进行测试,不能从 VPS 本身测试:

nc -vz vps.example.com 8443

出现拒绝连接或超时才是预期结果。如果能够连接,无论 ufw 显示什么,该端口都已公开。可靠的修复方法就是 compose 文件中已有的方法:将端口发布到127.0.0.1或隧道地址上,使 Docker 不再将其绑定到公网接口。也可以在DOCKER-USER链中添加规则,但绑定端口更简单,而且不会因规则顺序错误而失效。

Ubiquiti 自己的安装程序怎么样?

Ubiquiti 为 Network Application 发布了 Debian 软件包。它可以正常运行,但在当前版本的 Ubuntu 上会引出一个发行版不再解决的 MongoDB 问题:Ubuntu 22.04 和 24.04 不提供 MongoDB 服务器软件包,因此您最终需要手动添加 MongoDB 自己的软件源,并匹配各组件的版本。上面的容器通过一个固定版本标签完成了版本匹配,因此这里采用这种方式。

Ubiquiti 较新的自托管产品是 UniFi OS Server。它在 Podman 容器中运行 UniFi 应用,并提供与其硬件控制台相同的 UniFi OS。截至 2026 年 8 月,它要求使用 x86_64 Ubuntu 22.04 或 24.04,以及带有 slirp4netns 的 Podman 4.3.1 或更高版本;最低要求为 2 vCPU 和 4 GB RAM,推荐使用 4 vCPU 和 8 GB RAM。安装程序需要通过其下载页面上的免费 Ubiquiti 账户获取,因此没有可稳定复制到指南中的单行 URL。它会创建名为 uosserver 的系统用户,并以该用户身份运行容器。如果您希望使用厂商自己的打包方式,请选择它。如果您希望自行固定版本,并让服务器保留资源运行其他任务,请选择容器堆栈。

UniFi 备份存放位置,以及如何将其导出到主机外

控制器会按照您在 Settings 的备份部分中设置的计划创建备份,并根据配置保留指定数量的备份。备份文件会写入容器内的 /config/data/backup/autobackup,该目录在主机上对应 ~/unifi/config/data/backup/autobackup,文件名格式类似 autobackup_10.5.67_20260813_1200_1755086400004.unf

确认备份文件确实已生成:

ls -l ~/unifi/config/data/backup/autobackup

设置计划一天后目录仍为空,是全新容器安装中已知的故障。应用要求 autobackup 目录已存在,但不会自动创建该目录,因此计划任务会静默地不写入任何内容。请使用容器运行所用的同一用户手动创建该目录,然后等待下一次计划任务运行:

mkdir -p ~/unifi/config/data/backup/autobackup
docker compose restart unifi-network-application

.unf 文件包含站点配置和管理员帐户信息,因此应将其视为加密密钥一样保护。将副本导出到您控制的计算机,并妥善限制其访问权限:

rsync -av you@vps.example.com:~/unifi/config/data/backup/autobackup/ ~/unifi-backups/

恢复只需一步。在新安装的设置向导首页中,可以选择从备份文件恢复;运行中的控制器也可在同一设置页面执行恢复。请恢复到相同版本或更高版本。使用比目标控制器更新的应用写入的备份进行恢复时会被拒绝,因此应同时记录文件对应的版本号。

控制器升级可能导致的问题

每次升级前都要手动创建备份并下载到本地。然后:

docker compose pull
docker compose up -d
docker compose logs -f unifi-network-application

数据库最先可能出问题。在与应用程序同一次编辑中,将 mongo 标签改为新的主版本,是导致控制器无法启动的最快方式。因为 MongoDB 未经分阶段升级,无法打开其他主版本创建的数据文件。先单独升级应用程序。然后单独迁移 MongoDB,每次只升级一个主版本,并确保手头有一份最新备份。

接下来是内存问题。较大的版本需要更大的堆。如果应用程序能够启动,运行几分钟后退出,请将 MEM_LIMITMEM_STARTUP 提高到 1536 或 2048,然后重启。主机上的 dmesg -T | grep -i 'killed process' 可以确认是否是内核终止了该进程。

设备固件是容易被忽略的风险。控制器完成自身升级后,会为已采用的设备提供固件升级。不要在同一次会话中接受这些升级。如果设备升级与控制器升级重叠,并且两者之间的连接中断,设备可能会处于配置未完成的状态。这样一来,您又得通过 SSH 使用 set-inform 处理另一栋楼中的硬件。

升级窗口本身没有听起来那么危险。控制器重启期间,设备会继续转发流量,因此用户不会察觉。访客门户和 RADIUS 会停止(如果由该控制器提供),因此应选择两者都未使用的时间。凌晨 3 点无声退出的控制器也值得及时发现,因此请将 Uptime Kuma 状态监控器指向端口 8080,让它通知您。

诚实的替代方案:Ubiquiti 托管控制台

Ubiquiti 也提供同类服务。截至 2026 年 8 月,Official UniFi Cloud Console 的起价为每月 $29,最多可管理 500 台 UniFi 设备。Ubiquiti 负责运行更新和备份。刚刚安装的自托管应用免费使用,无需订阅。

如果您只管理一个站点,并且愿意付费而不是自行打补丁,请选择托管控制台。如果您管理多个站点,或者希望将控制器放在自己控制的网络中,并与运行的其他服务共用一台服务器,请选择 VPS。小规模部署时,两者的成本差异确实存在,但这不是唯一需要权衡的因素:托管控制台的可用性取决于他人,而 VPS 由您负责,包括磁盘空间耗尽的那一晚。如果无论如何这台服务器都能发挥价值,下一步应阅读VPS 上还可以运行什么

FAQ

为什么我的 UniFi 设备无法连接到 VPS 上的控制器?

设备通过 UDP 端口 10001 使用广播发现控制器。广播不会离开本地网络,因此远程站点中的设备无法找到公网中的控制器。将控制器系统设置中的 inform host override 设置为 VPS 主机名,然后使用 ssh ubnt@<device-ip>,再执行 set-inform http://vps.example.com:8080/inform,将设备指向该主机。如果设备处于 Adopting 状态,请在此状态下再次运行 set-inform。如果设备之前已被其他控制器采用,请先将其重置为出厂默认设置,因为设备仍保存着旧控制器的凭据。

自托管 UniFi 控制器需要多少 RAM?

2 GB 是可用下限,4 GB 较为充裕。该应用由 Java 和 MongoDB 组成,两者分别占用内存:容器镜像默认将 Java 堆限制为 1024 MB,而 MongoDB 的 WiredTiger 缓存会占用超过 1 GB 的 RAM 的一半。在 x86_64 上,还应使用 grep -m1 -o avx /proc/cpuinfo 确认 CPU 提供 AVX,因为 MongoDB 5.0 及更高版本缺少 AVX 时无法启动,数据库容器会不断重启。

是否应该将端口 8443 暴露到互联网?

不应该。端口 8443 是管理界面,其中保存着控制器管理的所有站点配置。通过 127.0.0.1 发布该端口,并使用 ssh -L 8443:127.0.0.1:8443 you@vps.example.com 访问,或者将其绑定到 WireGuard 或 Tailscale 地址。只有 TCP 8080 和 UDP 3478 需要允许站点访问;如果各站点使用固定公网地址,可以将访问范围限制为这些地址。请注意,Docker 发布的端口不会受到 ufw 过滤,因此应从外部机器测试,而不要仅依赖 ufw status

VPS 控制器停止运行后,我的网络会中断吗?

不会。已采用的接入点和交换机会继续使用控制器此前下发的配置转发流量,因此客户端仍可保持连接,Wi-Fi 也会继续工作。停止的是管理功能。您将无法使用控制面板和统计信息收集功能,也无法使用由控制器提供的实时功能,例如访客门户身份验证,或控制器作为 RADIUS 服务器时提供的 RADIUS 服务。

UniFi 控制器将自动备份存储在哪里?

在此处使用的容器镜像中,备份文件会写入 /config/data/backup/autobackup。该路径映射到主机上的数据路径加 data/backup/autobackup,文件为 .unf 格式,文件名包含版本和时间戳。在某些全新安装中,autobackup 目录不存在。此时定时备份不会写入任何内容,也不会报告错误。因此,设置计划一天后应列出该目录;如果目录为空,请自行创建。请将这些文件复制到 VPS 之外,因为 .unf 包含站点配置和管理员帐户。

#unifi#ubiquiti#network-management#Docker#自托管