1. 项目概述为什么选择Docker部署Unifi控制器如果你和我一样折腾过Ubiquiti优倍快的全家桶大概率会对那个官方的硬件控制器——Cloud Key——又爱又恨。爱的是它开箱即用把Unifi Network Application网络控制器这个核心服务打包得整整齐齐恨的是它的性能瓶颈、发热问题以及一旦硬件挂了所有配置都得重头来过的风险。更别提那些想用更强大的自有机比如一台闲置的迷你主机或NAS来集中管理多个站点却苦于官方软件安装过程繁琐、依赖复杂的朋友了。这就是我花时间折腾并整理出这套Docker化部署方案的初衷。把Unifi Network Application塞进Docker容器里带来的好处是实实在在的环境隔离再也不用担心它和宿主机上其他服务打架部署标准化无论底层是Ubuntu、Debian还是DietPi一套docker-compose.yml文件就能搞定备份和迁移变得极其简单整个应用的状态就是几个数据卷Volume直接打包复制就能带走。对于像CasaOS这类强调易用性的家庭服务器系统这种容器化的方式更是无缝契合。简单说这个项目就是为你提供一个最省心、最可靠的方案让你能在任何支持Docker的Linux系统上快速拉起一个功能完整的Unifi网络控制器替代Cloud Key或简化复杂的原生安装。接下来我会带你从设计思路到避坑实操完整走一遍这个流程。2. 方案设计核心理解“All-in-One”与“分而治之”在动手之前我们先拆解一下Unifi Network Application这个软件本身。它本质上是一个Java Web应用但它的运行严重依赖一个后端数据库——MongoDB。官方安装包会帮你把这两者以及一些系统服务一起装好但在Docker世界里我们有两种主流思路。第一种是寻找一个“All-in-One”的镜像即一个Docker镜像里同时包含了Unifi应用和MongoDB。这种方式最省事但灵活性差且数据库和应用的生命周期绑定在一起不利于单独维护或升级。第二种也是本项目采用并推荐的是“分而治之”的思路为Unifi应用和MongoDB分别创建独立的容器然后通过Docker网络让它们互联。为什么选择后者原因有三资源隔离与独立伸缩MongoDB和Java应用对CPU、内存的需求模式不同。分开后你可以根据各自容器的实际负载更精细地调整资源限制cpus,mem_limit。备份与恢复的粒度Unifi的配置、日志和MongoDB的数据可以分别挂载到宿主机的不同目录。这样你可以单独备份庞大的录像文件如果用了Unifi Protect而不用动数据库反之亦然。升级与排障的便利性你可以单独升级MongoDB的版本以获取安全补丁而无需触碰Unifi应用。当出现启动问题时也能清晰地判断是数据库服务没起来还是应用本身有问题。基于这个设计我们的核心架构就明确了一个docker-compose.yml文件定义两个服务unifi-controller和unifi-mongodb它们共享一个自定义的Docker网络确保低延迟、安全的内部通信。所有需要持久化的数据都通过volumes映射到宿主机这是保证数据不随容器销毁而丢失的关键。3. 环境准备与依赖检查无论你选择哪种安装方式一个干净的底层系统是成功的一半。以下步骤适用于绝大多数基于Debian/Ubuntu的发行版包括DietPi也是CasaOS的底层。3.1 系统更新与基础工具首先通过SSH连接到你的目标主机。我强烈建议使用一个具有sudo权限的非root用户来操作这更安全。# 更新软件包列表并升级现有软件 sudo apt update sudo apt upgrade -y # 安装一些后续可能用到的工具 sudo apt install -y curl wget git ufw net-tools3.2 安装Docker与Docker Compose这是最核心的依赖。Docker的安装已经非常标准化使用官方脚本是最快最可靠的方式。# 下载并执行Docker官方安装脚本 curl -fsSL https://get.docker.com -o get-docker.sh sudo sh get-docker.sh # 将当前用户加入docker组避免每次都要用sudo sudo usermod -aG docker $USER重要提示执行完usermod命令后你需要完全退出当前的SSH会话然后重新登录才能使组权限生效。否则后续的docker命令可能还是会报权限错误。接下来安装Docker Compose插件。现在Docker官方推荐将其作为CLI插件安装而不是独立的二进制文件。# 安装Docker Compose插件 sudo apt install -y docker-compose-plugin # 验证安装 docker compose version如果看到版本号输出如Docker Compose version v2.24.0说明安装成功。3.3 防火墙与端口规划可选但强烈推荐Unifi控制器需要开放几个端口与网络设备AP、交换机等及你的浏览器通信。在宿主机上配置防火墙如UFW可以提升安全性。请根据你的网络环境谨慎操作错误配置可能导致无法访问。# 启用UFW如果尚未启用 sudo ufw enable # 放行SSH端口确保你不会把自己关在外面 sudo ufw allow 22/tcp # 放行Unifi控制器所需的核心端口 # 8443: 控制器Web管理界面 (HTTPS) # 8080: 设备通信端口 (HTTP, 用于设备发现和注册) # 3478: STUN服务端口 (用于某些L3发现) # 10001/udp: 设备发现广播端口 sudo ufw allow 8443/tcp sudo ufw allow 8080/tcp sudo ufw allow 3478/udp sudo ufw allow 10001/udp # 查看规则状态 sudo ufw status numbered注意如果你在路由器后面且需要通过公网访问还需要在路由器上设置相应的端口转发将WAN口的8443等端口转发到宿主机的内网IP。这涉及网络安全请确保你了解其风险。4. 一键脚本安装详解与内部原理项目提供的一键安装脚本install.sh极大地简化了流程。但知其然更要知其所以然我们拆开看看这个脚本到底帮你做了什么。理解这些即使脚本运行出错你也能手动排查。4.1 脚本工作流程解析当你运行wget -O install.sh ... chmod x install.sh ./install.sh后脚本会按以下顺序执行环境检测检查当前用户是否具有sudo权限检查docker和docker compose命令是否存在。如果缺少Docker它会提示你安装但通常建议你按照我上面第3步的方法手动安装更可控。目录创建在/opt目录下创建unifi文件夹并在此文件夹内创建data、log等子目录用于后续绑定挂载。这一步确保了你的所有配置和数据都保存在宿主机上。生成配置文件脚本的核心是生成一个docker-compose.yml文件。它会交互式地询问你几个关键参数主机IP地址这是最关键的一步。脚本会尝试自动检测但你必须确认或手动输入宿主机在局域网内的真实IP地址如192.168.1.100而不是127.0.0.1或localhost。这个IP将用于构建容器内的INFORM_HOST环境变量直接关系到AP等设备能否正确找到控制器。时区设置容器的时区保证日志和时间戳准确。端口映射你可以选择修改默认的8443、8080等端口如果宿主机这些端口已被占用的话。拉取镜像并启动根据你的输入生成定制的docker-compose.yml后脚本会执行docker compose up -d在后台启动所有服务。输出访问信息最后脚本会打印出访问控制台的URL通常是https://你的主机IP:8443以及一些后续操作的提示。4.2 手动调整与验证脚本运行后我强烈建议你检查一下生成的docker-compose.yml文件位置通常在/opt/unifi/docker-compose.yml。version: 3.8 services: unifi-mongodb: image: mongo:4.4 container_name: unifi-mongodb restart: unless-stopped volumes: - ./data/db:/data/db networks: - unifi-net unifi-controller: image: lscr.io/linuxserver/unifi-controller:latest container_name: unifi-controller restart: unless-stopped depends_on: - unifi-mongodb environment: - PUID1000 - PGID1000 - TZAsia/Shanghai # 时区应根据你的位置修改 - MONGO_HOSTunifi-mongodb - MONGO_PORT27017 - MONGO_USERunifi - MONGO_PASSyour_secure_password # 脚本应生成一个随机密码 - MONGO_DBNAMEunifi - INFORM_HOST192.168.1.100 # 这里必须是宿主机的局域网IP volumes: - ./data:/config - ./log:/log ports: - 8443:8443/tcp - 8080:8080/tcp - 3478:3478/udp - 10001:10001/udp networks: - unifi-net networks: unifi-net: driver: bridge关键点检查INFORM_HOST必须是你局域网的固定IP且设备能访问到。MONGO_PASS应该是一个强随机密码。脚本生成的如果太简单建议你手动改成一个复杂的。端口映射确认宿主机的8443、8080等端口没有被其他程序占用。检查无误后你可以通过以下命令管理服务# 进入项目目录 cd /opt/unifi # 查看容器运行状态 docker compose ps # 查看Unifi控制器的实时日志用于排障 docker compose logs -f unifi-controller # 停止服务 docker compose down # 重新启动服务 docker compose up -d5. 经典Compose文件部署针对不同系统的微调一键脚本适合快速入门但手动部署能让你拥有完全的控制权。项目提供了针对不同系统的Compose文件其核心差异在于数据持久化路径和资源限制的优化。5.1 通用Linux系统部署这是最通用的方案。你需要手动创建目录和文件。# 1. 创建项目目录结构 sudo mkdir -p /opt/unifi/{data,log} sudo chown -R $USER:$USER /opt/unifi # 将所有权给当前用户避免权限问题 # 2. 创建 docker-compose.yml cd /opt/unifi nano docker-compose.yml将上面示例的docker-compose.yml内容粘贴进去并根据你的实际情况修改TZ、INFORM_HOST和MONGO_PASS。然后启动docker compose up -d5.2 DietPi系统优化部署DietPi是一个极度精简的Linux发行版常用于树莓派等嵌入式设备。它的优化核心在于资源限制防止Unifi控制器特别是Java进程吃光小内存设备的所有资源。在通用版docker-compose.yml的基础上你需要为unifi-controller服务添加资源限制services: unifi-controller: # ... 其他配置保持不变 ... deploy: resources: limits: memory: 1024M # 根据你的设备内存调整512M-1024M是常见范围 cpus: 1.0 # 限制使用1个CPU核心 # ... 其他配置保持不变 ...对于树莓派4B4GB内存这样的设备将内存限制在1GB左右可以保证系统和其他服务仍有足够资源运行避免因内存耗尽导致整个系统卡死或崩溃。5.3 CasaOS应用商店部署最简方式CasaOS的伟大之处在于其应用商店。本项目已成功合并到官方商店中这意味着部署简化到了极致在CasaOS桌面打开“App Store”。搜索 “Unifi”。找到 “Unifi Network Application”点击安装。在安装配置页面通常只需要填写一个关键项Host IP你的CasaOS主机内网IP。其他如端口、数据目录CasaOS会自动处理或提供默认值。点击安装等待拉取镜像和启动完成。CasaOS会在后台为你生成并管理对应的docker-compose.yml文件所有数据会存储在它指定的目录下通常是/var/lib/casaos/apps/UnifiNetworkApplication。这种方式最适合追求极致易用性的家庭用户。6. 安装后关键配置让设备找到“家”容器成功运行用浏览器打开https://主机IP:8443你会看到Unifi控制器的初始化设置界面。完成基础设置创建管理员账户、命名站点等后最关键的一步来了如何让网络中的AP、交换机等设备被这个Docker中的控制器发现并管理6.1 修改控制器Inform主机地址这是解决“设备无法被控制器发现”问题的核心步骤。因为控制器运行在Docker容器内它默认告知设备的联系地址是容器内部的IP如172.20.0.3这个地址在你的物理网络中是访问不到的。在Unifi控制器Web界面进入设置Settings-系统System。在搜索框输入“Inform Host”。你会找到“Override Inform Host”选项。启用它。在输入框中填入你的宿主机在局域网中的IP地址也就是你用来访问8443端口的那个IP端口保持为8080。例如http://192.168.1.100:8080。点击保存更改。控制器会重启部分服务以应用新配置。6.2 手动Adopt采用设备即使修改了Inform Host有时新设备或重置后的设备仍然无法在控制器界面中自动出现。这时需要手动干预获取设备IP确保你的设备如AP已经通电并连接到网络。在路由器后台或通过扫描工具找到它的IP地址。SSH到设备Unifi设备的默认SSH用户名和密码通常是ubnt/ubnt。ssh ubnt设备IP执行set-inform命令登录后输入以下命令set-inform http://你的宿主机IP:8080/inform例如set-inform http://192.168.1.100:8080/inform回到控制器界面执行命令后稍等几秒钟刷新控制器Web界面。你应该能在“设备Devices”列表中看到该设备状态为“等待中控批准Pending Adoption”。点击采用Adopt在设备列表中找到它点击“采用Adopt”。设备会下载配置并重启完成后状态变为“已连接Connected”。实操心得对于已经由旧控制器管理的设备迁移到新Docker控制器时最稳妥的方法就是先在旧控制器上“忘记Forget”该设备然后设备会重置并等待被新控制器发现。如果发现不了再用上面的SSHset-inform命令手动指向新控制器地址。7. 日常维护、备份与故障排查实录将服务容器化后日常运维变得模式化。这里记录几个高频操作和踩过的坑。7.1 数据备份策略你的所有配置、数据库、日志都在宿主机挂载的卷里。对于/opt/unifi或CasaOS对应的目录下的整个文件夹进行定期备份就是最完整的备份。# 假设你的数据在 /opt/unifi # 创建一个简单的备份脚本比如 /opt/backup_unifi.sh #!/bin/bash BACKUP_DIR/path/to/your/backup/drive SOURCE_DIR/opt/unifi TIMESTAMP$(date %Y%m%d_%H%M%S) # 停止服务以确保数据一致性可选但推荐 cd $SOURCE_DIR docker compose down # 使用tar打包 tar -czf ${BACKUP_DIR}/unifi_backup_${TIMESTAMP}.tar.gz -C $(dirname $SOURCE_DIR) $(basename $SOURCE_DIR) # 重新启动服务 cd $SOURCE_DIR docker compose up -d # 清理30天前的旧备份 find $BACKUP_DIR -name unifi_backup_*.tar.gz -mtime 30 -delete给脚本执行权限并添加到cron定时任务每周自动运行一次。7.2 容器日志与问题诊断大多数启动或运行时问题通过查看容器日志都能找到线索。# 查看unifi-controller容器的最后50行日志 docker compose logs --tail 50 unifi-controller # 实时跟踪日志输出类似 tail -f docker compose logs -f unifi-controller # 查看MongoDB容器的日志 docker compose logs unifi-mongodb7.3 常见问题速查表下表是我在部署和维护过程中遇到的一些典型问题及解决方法问题现象可能原因排查步骤与解决方案访问https://IP:8443连接被拒绝或超时1. 容器未成功启动。2. 宿主机防火墙UFW或云主机安全组未放行8443端口。3. 端口被其他进程占用。1.docker compose ps检查状态docker compose logs查看错误。2.sudo ufw status检查规则或sudo netstat -tlnp | grep :8443查看端口占用。控制器启动后Web界面一直卡在“正在加载”或显示“数据库连接错误”1. MongoDB容器启动慢或启动失败。2.MONGO_HOST环境变量指向错误。3. MongoDB数据卷权限问题。1.这是最常见问题先docker compose logs unifi-mongodb看数据库是否就绪。通常等待1-2分钟再刷新页面即可。2. 检查docker-compose.yml中MONGO_HOST是否为服务名unifi-mongodb。3. 如果日志显示权限错误尝试sudo chown -R 999:999 /opt/unifi/data/db(MongoDB容器内用户ID常为999)。AP/设备无法被控制器发现1.INFORM_HOST设置错误这是最主要原因。2. 宿主机8080端口未开放。3. 设备和控制器不在同一VLAN或子网且没有正确配置L3管理。1. 确认控制器设置中“Override Inform Host”已启用并指向宿主机的正确内网IP:8080。2. 在设备所在网络用telnet 控制器宿主机IP 8080测试连通性。3. 对于跨网段需在控制器“设置-系统-高级”中启用“L3管理”并在设备网关做好相关路由/防火墙规则。采用Adopt设备失败一直“Pending”1. 设备无法从INFORM_HOST地址下载固件或配置。2. 控制器版本与设备固件版本不兼容。1. 在设备上再次SSH执行set-inform并观察控制器日志看是否有来自该设备的inform请求。2. 尝试在控制器设置中启用“自动升级Auto-Upgrade”或手动为设备指定一个稍旧的稳定版固件。控制器运行一段时间后变卡或内存占用高Java堆内存设置不足或内存泄漏旧版本常见。1. 对于Docker部署可以修改docker-compose.yml在unifi-controller服务的environment部分添加- JVM_OPTIONS-Xmx1024M -Xms512M来调整JVM内存。2. 考虑定期重启容器通过cron job每周重启一次。3. 关注LinuxServer.io的镜像更新日志及时升级到新版本。7.4 升级控制器版本使用LinuxServer.io的镜像升级通常很简单# 进入项目目录 cd /opt/unifi # 拉取最新的镜像 docker compose pull # 重新创建并启动容器配置和数据卷会保留 docker compose up -d --force-recreate # 查看新镜像版本 docker compose images重要提醒在升级前务必做好完整备份。虽然Unifi控制器升级通常很平滑但以防万一有一个可回滚的备份是运维的好习惯。8. 从Cloud Key迁移至Docker控制器如果你已经有一个在运行的Cloud Key或旧控制器迁移到新的Docker控制器可以做到几乎无缝。核心思路是备份旧- 恢复新。在旧控制器上创建备份登录旧控制器进入设置Settings-系统System-备份。点击“立即备份Backup Now”。选择“所有设置All”或按需选择。下载生成的.unf备份文件到本地电脑。在新Docker控制器上恢复完成新Docker控制器的基本初始化设置管理员账号、站点名等。进入新控制器的设置Settings-系统System-备份。点击“恢复Restore”上传刚才下载的.unf备份文件。系统会提示重启确认即可。迁移后设备重指向恢复备份后所有设备配置SSID、网络规划、防火墙规则等都会过来但设备本身仍然指向旧控制器的IP。你需要逐一将设备重新指向新的Docker控制器。最快的方法是将旧控制器关机或断开网络。等待设备因联系不上旧控制器而进入“孤立”状态LED灯常亮白光或黄光。此时在新Docker控制器上你应该能看到这些设备状态变为“离线”或“断开连接”。对于每个设备使用前面提到的SSHset-inform http://新控制器IP:8080/inform命令或者更简单直接在新控制器界面上对离线设备点击“采用Adopt”控制器会自动尝试用新的Inform Host去联系设备。