如何用 Ubuntu 服务器和 Docker Compose 部署家用 Nextcloud
-
如何用 Ubuntu 服务器和 Docker Compose 部署家用 Nextcloud
目录作为一名喜欢折腾的技术爱好者,我一直想在家里搭一套自己的私有云,既能替代各种商业网盘做文件同步,又能顺便练练手。这次我选择了 Nextcloud,部署方式是 Docker Compose,运行环境是 Ubuntu + Docker,通过 mDNS 在局域网内用
*.local域名访问。本文记录整个部署过程,以及中途遇到的几个典型问题和解决思路,希望能给有类似需求的朋友一些参考。
一、环境与最终配置
运行环境
- OS:Ubuntu(家庭服务器)
- 容器运行时:Docker + Docker Compose v2
- 局域网访问方式:mDNS(Avahi)
最终的
docker-compose.ymlservices: db: image: mariadb:10.11 container_name: nextcloud-db restart: unless-stopped command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW volumes: - db_data:/var/lib/mysql environment: MYSQL_ROOT_PASSWORD: RootPass_ChangeMe_123 MYSQL_DATABASE: nextcloud MYSQL_USER: nextcloud MYSQL_PASSWORD: NcPass_ChangeMe_456 MARIADB_AUTO_UPGRADE: "1" app: image: nextcloud:latest container_name: nextcloud restart: unless-stopped ports: - "5050:80" depends_on: - db volumes: - nextcloud_data:/var/www/html environment: MYSQL_HOST: db MYSQL_DATABASE: nextcloud MYSQL_USER: nextcloud MYSQL_PASSWORD: NcPass_ChangeMe_456 NEXTCLOUD_TRUSTED_DOMAINS: myhost.local localhost 192.168.1.* 192.168.0.* 10.0.0.* *.local # 首次安装向导走完后,取消下面两行注释再 docker compose up -d # OVERWRITEPROTOCOL: http # OVERWRITEHOST: "myhost.local:5050" volumes: db_data: nextcloud_data:说明:配置中的密码、主机名均为示例,请按自己实际情况修改。本文后续统一用
myhost.local代表家庭服务器的主机名。二、配置设计思路
1. 数据库用 MariaDB 10.11
Nextcloud 官方文档推荐 MariaDB / MySQL。这里选
10.11(LTS)而不是latest,主要是为了避免未来某天docker compose pull把大版本顶上去导致崩溃。两个关键启动参数:
--transaction-isolation=READ-COMMITTED:Nextcloud 官方推荐的隔离级别,能减少死锁--binlog-format=ROW:配合上面的隔离级别,保证事务一致性
MARIADB_AUTO_UPGRADE=1让容器启动时自动跑mysql_upgrade,跨版本升级时省心。2. 应用容器只暴露 5050 端口
ports: - "5050:80"Ubuntu 上 80 端口经常被其他服务占用(例如以后可能会装的 Nginx),这里映射成 5050 干净利落。访问地址就是
http://myhost.local:5050。3. 数据全部走命名卷
db_data和nextcloud_data都用 Docker 命名卷,而不是绑定宿主机目录。好处是不用操心宿主机权限,容器内的www-data用户能正常读写。缺点是备份时要用docker run --rm -v ... tar的方式导出,绑定目录则可以直接 rsync,各有取舍。4.
NEXTCLOUD_TRUSTED_DOMAINS用通配符myhost.local localhost 192.168.1.* 192.168.0.* 10.0.0.* *.localNextcloud 的
trusted_domains支持*通配符(一个*只能匹配一段),多个值用空格分隔。这样局域网里任何设备用 IP 或.local名字访问都能放行。⚠️ 安全提示:通配符仅适用于纯内网部署。一旦暴露到公网,应当写死具体域名。
三、一个关键决定:局域网里用什么名字访问?
家里的设备(手机、Mac、iPad)都在同一个 Wi-Fi 下。我不想每次都记 IP,于是打算用 mDNS(也叫 Bonjour / Avahi),通过
xxx.local的方式访问。最初的想法:让容器自己广播 mDNS
第一版方案里我加了一个
mdns容器,专门跑avahi-daemon,用network_mode: host去广播一个自定义名字。结果容器日志里全是:Detected another IPv4 mDNS stack running on this host, effectively disabling Avahi's mDNS stack. Host name conflict, retrying with next-2.local Host name conflict, retrying with next-3.local ...排查端口占用:
sudo ss -ulpn | grep 5353发现宿主机(Ubuntu)本身就跑着一个
avahi-daemon,正在广播myhost.local。容器里那个 avahi 被挤得节节败退——两者都在争 UDP 5353。换思路:直接用宿主机已有的 mDNS 名
既然宿主机已经在广播
myhost.local,为什么还要自己再造一个?直接用现成的就好:NEXTCLOUD_TRUSTED_DOMAINS: myhost.local ...浏览器访问
http://myhost.local:5050完事,compose 里那个多余的mdns服务直接删掉。最好的方案往往是不做。如果你的 Ubuntu 还没装 avahi,启用很简单:
sudo apt install -y avahi-daemon avahi-utils libnss-mdns sudo systemctl enable --now avahi-daemonavahi-daemon:mDNS 守护进程avahi-utils:提供avahi-resolve、avahi-browse等调试工具libnss-mdns:让 Ubuntu 自己也能解析*.local(Mac 自带 Bonjour,不需要)
验证:
avahi-resolve -n myhost.local # 应返回宿主机 IP avahi-browse -a -t # 列出局域网所有 mDNS 服务四、部署过程中踩到的几个坑
坑 1:
NEXTCLOUD_TRUSTED_DOMAINS改了不生效现象:改了 compose 里的环境变量,
docker compose up -d重启后,浏览器依然报Access through untrusted domain。原因:
NEXTCLOUD_TRUSTED_DOMAINS这类环境变量只在数据卷为空(首次初始化)时写入config/config.php。如果之前装过,config 已经存在,后续修改环境变量完全不会被读入。解决:进容器用
occ命令改:docker compose exec --user www-data app \ php occ config:system:set trusted_domains 0 --value="myhost.local" docker compose exec --user www-data app \ php occ config:system:set trusted_domains 1 --value="192.168.1.*" docker compose exec --user www-data app \ php occ config:system:set trusted_domains 2 --value="*.local"查看当前值:
docker compose exec --user www-data app php occ config:system:get trusted_domains经验:所有
NEXTCLOUD_*开头的"首次初始化"环境变量都有这个特性,包括NEXTCLOUD_ADMIN_USER、NEXTCLOUD_ADMIN_PASSWORD等。第一次启动之后,改配置一律走occ或者直接编辑config.php。坑 2:升级提示 "Update needed"
现象:
Update needed Please use the command line updater because updating via browser is disabled in your config.php.原因:镜像用了
nextcloud:latest,docker compose pull可能拉到更新的大版本,而数据卷里的 Nextcloud 实例版本比较老。解决:命令行升级
docker compose exec --user www-data app php occ upgrade docker compose exec --user www-data app php occ maintenance:mode --off⚠️ Nextcloud 不允许跨大版本升级(比如 27 → 29 会拒绝)。如果版本差距大,要先把镜像暂时改成中间版本(如
nextcloud:28)过一次occ upgrade,再切到目标版本。教训:生产环境应该把镜像版本锁死,而不是用
latest:image: nextcloud:30-apache这样
pull只会在 30 的小版本内更新,大版本升级由自己掌控节奏。坑 3:分享链接生成的 URL 不带端口
Nextcloud 生成的分享链接和客户端回调地址,默认根据请求头推断协议和域名。家里用
http://myhost.local:5050访问没问题,但分享链接可能生成成http://myhost.local/s/xxx(丢了 5050),点开打不开。解决:在
config.php里固定外部访问的协议和主机:docker compose exec --user www-data app \ php occ config:system:set overwriteprotocol --value="http" docker compose exec --user www-data app \ php occ config:system:set overwritehost --value="myhost.local:5050"或者在初次安装完成后,编辑 compose 把注释去掉再
up -d(仅对重新初始化的实例生效):OVERWRITEPROTOCOL: http OVERWRITEHOST: "myhost.local:5050"五、完整部署步骤汇总(Ubuntu)
# 0. 如果还没装 Docker sudo apt update sudo apt install -y docker.io docker-compose-v2 sudo usermod -aG docker $USER # 重新登录一次让 docker 组生效 # 1. 准备目录 mkdir -p ~/nextcloud && cd ~/nextcloud # 把前面的 compose 文件保存为 docker-compose.yml,记得改密码 # 2. 启动 docker compose up -d # 3. 查看日志,确认没有错误 docker compose logs -f app # 4. 浏览器打开 http://myhost.local:5050,走首次安装向导 # 设置管理员账号密码即可 # 5. 安装完成后,固定外部访问 URL docker compose exec --user www-data app \ php occ config:system:set overwriteprotocol --value="http" docker compose exec --user www-data app \ php occ config:system:set overwritehost --value="myhost.local:5050" # 6. Mac 端清下 mDNS 缓存(Linux / Windows 通常不需要) sudo dscacheutil -flushcache sudo killall -HUP mDNSResponder六、几点实用经验总结
- 尽量用宿主机已有的基础设施。mDNS、反向代理这些系统级服务,没必要每个项目都在容器里再跑一份,否则就是在和宿主机抢端口。
latest是工具,不是信仰。一旦要长期运行,把镜像 tag 锁到大版本号,免得某天凌晨自动更新后服务起不来。- "首次初始化"环境变量要当心。Nextcloud、Postgres、MariaDB 这类官方镜像里的
*_PASSWORD、*_DATABASE等环境变量,几乎都是"仅在空卷时生效",之后改都得进容器手动操作。 - 部署前先通读日志。很多问题(mDNS 冲突、trusted_domains 报错、升级提示)其实日志里写得明明白白。
docker compose logs -f应该是部署时另开一个窗口常驻的命令。 trusted_domains支持通配符,但每个*只能匹配一段。想覆盖两个八位组,要写两条:192.168.0.*和192.168.1.*,而不是192.168.*.*。
结语
一套可用的私有云就这么搭起来了。下一步打算给它加上自动备份脚本(
occ maintenance:mode --on→ 打包数据卷 → 关掉维护模式),以及定期做大版本升级演练。如果你也在用 Ubuntu + Docker 折腾家庭服务器,希望这篇记录能帮你少走几步弯路。Have fun self-hosting ☁️
歡迎留言回复交流。
Log in to reply.