去年有位朋友找我救急:公司二十几号人的文件散落在各自电脑里,互相传文件靠微信和U盘,一次误删事故后,老板终于松口说搞个私有云盘。我落地的那套方案,和这篇标题一模一样——用 Docker 部署 Nextcloud 作为核心文件服务,数据库交给 MariaDB,在线文档编辑接 OnlyOffice,最外层统一套 HTTPS。整套跑下来成本就是一台云主机,数据全在自己手里,不用每年交公共网盘会员费。
这篇文章我会把整体思路、选型原因、完整配置文件和一路踩过的坑全部摊开讲。不管你是想给团队搭内部文件服务,还是只想给自己和家人搞个独立云盘,照着做都能少走弯路。如果你后面打算把在线编辑能力集成进自己的业务系统,这套部署也能直接当底座使用。
1. 整套方案的设计思路与技术选型
做私有云盘很容易冲动,一上来就想把全家桶装齐,结果越搞越乱。选型阶段的克制,比后期堆功能重要得多。这个项目里我坚持的核心原则是:能用容器解决的绝不裸装,能少暴露端口就少暴露,所有数据必须落在宿主机目录里。
1.1 为什么用 Docker 而不是裸装环境
很多人一听“私有云”就以为要独立服务器加整套 LAMP 环境,其实没必要。裸装 Nextcloud 本身的安装不算难,难在依赖管理:PHP 版本、PHP-FPM 配置、Nginx、Redis、数据库客户端,随便某个系统库升级就能让服务瘫痪。Docker 把这些依赖全部打进镜像,宿主机只要有一个稳定的容器运行时就行。
Docker 还带来两个实际好处。一是可复现性:同一份 docker-compose.yml 换任何一台机器都能拉起来,不会因为“当时少装了一个包”而跑不起来。二是回滚方便:Nextcloud 大版本升级翻车是常态,裸装回滚基本等于重装,容器方案只要把镜像 tag 改回去再恢复数据目录就完事了。我自己的教训是:不要为了省那 200MB 内存放弃容器化,后续维护省下的时间远超这点内存开销。
1.2 为什么选 MariaDB、OnlyOffice、Caddy
数据库层面我在 MariaDB 和 MySQL 之间犹豫过。两者对 Nextcloud 的兼容性都很好,但 MariaDB 社区维护更活跃,同配置下内存占用略低,在小内存 VPS 上更友好。如果你已经有很重的 MySQL 运维经验,用 MySQL 也没问题;从零开始的话我更推荐 MariaDB。这套方案里 MariaDB 只服务 Nextcloud 一个业务,不需要分库分表,核心诉求就是稳。
在线文档编辑选了 OnlyOffice 而不是 Collabora Online。个人实测下来,OnlyOffice 对 Office 文档的排版还原度更高,界面也更接近传统 Office,团队里非技术成员的接受度明显更好。更关键的是,Nextcloud 官方提供了 ONLYOFFICE 集成应用,装好之后在文件列表里单击就能新建和编辑 docx,体验和公共网盘几乎没差别。
最外层反向代理选了 Caddy,没选 Nginx。原因很简单:省事。Caddy 天然支持自动申请和续期 Let's Encrypt 证书,写一个 Caddyfile 就能搞定 HTTPS,不用像 Nginx 那样写一长串 location 和证书路径。它是 Go 写的静态二进制,丢到服务器就能跑,特别适合个人和小团队。
1.3 请求是怎么流动的
动手写配置前,先在心里过一遍完整的请求链路,后面排查问题会轻松很多。
用户访问https://cloud.example.com时,请求先到宿主机 80/443 端口,Caddy 容器接住后做两件事:终止 TLS 解密,然后把请求转发给内部 Docker 网络里的 Nextcloud 容器。Nextcloud 收到请求后,如果需要在线编辑文档,它会在服务端调用 OnlyOffice 的 API,把文档内容同步给https://doc.example.com对应的 OnlyOffice 容器,浏览器里的编辑器实际是从 OnlyOffice 容器拉取页面和资源。
MariaDB 在整个链路里是最底层,只有 Nextcloud 会连接它,不直接对宿主机暴露任何端口。也就是说,外部能碰到的只有 Caddy 的 80/443,Nextcloud 和 OnlyOffice 都只在 Docker 内部网络里通过服务名互访。这种网络隔离是私有云安全的底线,也决定了我们后面配置时端口绑定方式。
2. 环境准备与目录规划
方案定型后,先把环境和目录铺好。很多人喜欢一上来就拉镜像,结果运行到一半发现目录权限不对、域名没解析,又回头折腾,浪费时间。我习惯按“硬件 → Docker → 目录”三步走。
2.1 服务器与域名
硬件方面,Nextcloud 本身不挑配置,但 OnlyOffice 是内存大户。我实测下来,2 核 4G 是最低比较舒服的配置,如果经常有多人同时编辑文档,建议直接上 4 核 8G。只有 2G 内存的机器跑 Nextcloud 没问题,但一旦打开 OnlyOffice 编辑器,Swap 会吃满,体验会很卡。
域名方面,最好准备一个主域名和两个子域名:
cloud.example.com:给 Nextcloud 文件服务用doc.example.com:给 OnlyOffice 文档服务用
两个服务尽量不要塞在同一个路径下。OnlyOffice 对部署路径有要求,拆成独立子域是最省心的方案。把这两个域名做 A 记录解析到服务器公网 IP,同时确认服务器的 80 和 443 端口在防火墙和安全组里放通,后面配置完才能直接访问验证。
2.2 安装 Docker 与 Compose
宿主机是 Ubuntu/Debian 的话,官方安装脚本一把梭就行。装完记得把当前用户加入 docker 组,省得每次敲命令都要 sudo。然后确认 Docker 和 Compose 都能用,Compose v2 直接用docker compose命令,不是docker-compose。
如果你在 Windows 或 macOS 上用 Docker Desktop 做实验,要注意提前在 BIOS 里开启 CPU 虚拟化,并在 Windows 功能里启用“虚拟机平台”和“适用于 Linux 的 Windows 子系统”,否则 Docker Desktop 启动时会直接报virtualization support not detected。这个问题我在帮朋友远程看环境时遇到过太多次,十有八九是虚拟化没开或者 WSL2 没启用。
网络条件不太理想的话,装完 Docker 后建议顺手给 Docker 配置一个可用的镜像加速地址,避免拉大镜像时卡到怀疑人生。这一步属于环境优化,不影响方案结构。
2.3 目录规划与权限设计
容器虽然自带环境,但数据一定要放在宿主机目录里,否则容器一删全没了。这是我反复强调、也付出过代价的一条原则。我在/opt/nextcloud下规划了以下目录:
/opt/nextcloud/ ├── db/ # MariaDB 数据文件 ├── app/ # Nextcloud 应用代码 ├── data/ # Nextcloud 用户文件 ├── config/ # Nextcloud 配置目录 ├── onlyoffice/ # OnlyOffice 数据 └── caddy/ # Caddy 配置与证书创建目录后,稍微关注一下 UID/GID。Nextcloud 官方镜像默认以 www-data 用户运行,UID 通常是 33;MariaDB 镜像默认用户是 mysql,UID 通常是 999;OnlyOffice 容器内部普遍以 root 运行。如果你把宿主机目录权限只给 root 或者其他用户,容器内可能写不进去,造成上传失败或内部服务器错误。我一般是这样处理的:
mkdir -p /opt/nextcloud/{db,app,data,config,onlyoffice,caddy} chown -R 33:33 /opt/nextcloud/data /opt/nextcloud/config /opt/nextcloud/app chown -R 999:999 /opt/nextcloud/db注意不要一刀切 chmod 777,麻烦不说,还有安全隐患。正确做法是让每个容器的数据目录归属对应容器的运行用户。
3. 用 Compose 把四件套一次拉起来
环境准备好后进入核心环节。我会用 Docker Compose 把 MariaDB、Nextcloud、OnlyOffice、Caddy 四个容器编排起来,并用 .env 文件统一管理密码类敏感信息,避免把密码直接写进 compose 文件。
3.1 一份可以直接抄的 compose 文件
下面的内容保存为/opt/nextcloud/docker-compose.yml,同级目录下建一个.env文件存放密码:
services: db: image: mariadb:11.4 container_name: nextcloud-db restart: always command: [ '--character-set-server=utf8mb4', '--collation-server=utf8mb4_general_ci', '--max-allowed-packet=64M', '--innodb-buffer-pool-size=256M' ] volumes: - ./db:/var/lib/mysql environment: MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD} MYSQL_DATABASE: ${DB_NAME} MYSQL_USER: ${DB_USER} MYSQL_PASSWORD: ${DB_PASSWORD} networks: - nextcloud-net app: image: nextcloud:30 container_name: nextcloud-app restart: always depends_on: - db ports: - "127.0.0.1:8080:80" volumes: - ./app:/var/www/html - ./data:/var/www/html/data - ./config:/var/www/html/config environment: MYSQL_HOST: db MYSQL_DATABASE: ${DB_NAME} MYSQL_USER: ${DB_USER} MYSQL_PASSWORD: ${DB_PASSWORD} NEXTCLOUD_ADMIN_USER: ${ADMIN_USER} NEXTCLOUD_ADMIN_PASSWORD: ${ADMIN_PASSWORD} NEXTCLOUD_TRUSTED_DOMAINS: ${TRUSTED_DOMAINS} NEXTCLOUD_UPLOAD_LIMIT: 10G networks: - nextcloud-net onlyoffice: image: onlyoffice/documentserver:latest container_name: onlyoffice-doc restart: always ports: - "127.0.0.1:8081:80" environment: JWT_ENABLED: "true" JWT_SECRET: ${JWT_SECRET} JWT_HEADER: "Authorization" JWT_INBODY: "true" volumes: - ./onlyoffice:/var/www/onlyoffice/Data networks: - nextcloud-net caddy: image: caddy:2 container_name: nextcloud-caddy restart: always ports: - "80:80" - "443:443" volumes: - ./caddy/Caddyfile:/etc/caddy/Caddyfile:ro - ./caddy/data:/data - ./caddy/config:/config networks: - nextcloud-net networks: nextcloud-net: driver: bridge.env文件示例:
DB_ROOT_PASSWORD=ChangeMeRoot DB_NAME=nextcloud DB_USER=nextcloud DB_PASSWORD=ChangeMeDb ADMIN_USER=admin ADMIN_PASSWORD=ChangeMeAdmin TRUSTED_DOMAINS=cloud.example.com JWT_SECRET=ChangeMeOnlyOfficeJwt这里有几个要点值得单独拎出来说。
第一,app 和 onlyoffice 的端口没有直接暴露到公网,而是绑到了127.0.0.1,真正对外的只有 Caddy 的 80/443,宿主机之外的机器连不上内部服务。自建私有云,最小暴露面的思路一定要有。
第二,Nextcloud 镜像的NEXTCLOUD_TRUSTED_DOMAINS支持逗号分隔多个域名。如果后面想加内网 IP 访问或临时域名,直接在这里追加再重启容器即可,不用手动进 config.php 改。
第三,NEXTCLOUD_UPLOAD_LIMIT=10G是较新版本 Nextcloud 镜像支持的变量,能直接控制 PHP 上传限制。如果你用的是老版本镜像,还是要去容器里改upload_max_filesize和post_max_size。这点不同版本之间差异较大,建议先确认自己用的镜像版本。
3.2 MariaDB 初始化与调优要点
MariaDB 容器第一次启动时,会读取MYSQL_DATABASE、MYSQL_USER、MYSQL_PASSWORD这些环境变量自动建库建用户。注意,这个初始化动作只在数据目录为空时发生一次。一旦数据目录初始化完成,以后再改 compose 里的环境变量是不生效的——很多人想改数据库密码,改了 compose 重启后发现连接报错,就是因为数据库文件已经生成过了。
所以,数据库密码这类敏感信息从一开始就写进.env,不要提交 Git。如果真需要改密码,直接进容器执行 SQL 或使用 mysqladmin,别指望环境变量帮你自动改。
启动命令里那几个参数也解释一下。utf8mb4 是 Nextcloud 强制要求的字符集,不用它建表会出兼容性问题;max-allowed-packet=64M是为了应对大文件或大批量写入时的数据包上限;innodb-buffer-pool-size=256M是 InnoDB 缓冲池,4G 内存机器上 256M 是起步值,内存充裕的话可以提到 512M 甚至 1G。这些参数可以直接写在容器启动 command 里,不用单独改 my.cnf。
如果你在 ARM 设备上跑,mariadb 官方镜像本身就提供 arm64 版本,mariadb:11.4这种多架构镜像直接拉就能用,不用专门找所谓的“arm 客户端”。真正要担心的是 OnlyOffice 在 ARM 平台上的内存压力,后面单独说。
3.3 OnlyOffice 配置:JWT 密钥是灵魂
OnlyOffice 容器的核心配置是 JWT。Nextcloud 和 OnlyOffice 之间互相调用接口时,会带上由 JWT 签名的令牌,两边密钥必须完全一致。不一致的话,编辑界面勉强能打开,但只要加载或保存文档,就会报“文档安全令牌的格式不正确”。这是我遇到过的最高频问题,没有之一。
不同版本的 OnlyOffice 镜像,密钥环境变量名有变化。老版本用JWT_SECRET,较新版本官方推荐用SECRET。如果你拉的是 latest,先按我上面的 compose 写法来;如果仍然报令牌错误,进容器看环境变量是否生效,或者去查官方文档确认你那个镜像 tag 对应的变量名。我见过不少人卡在这里,其实不是服务没启动,而是版本差异造成的变量名不匹配。
内存方面,OnlyOffice 容器启动后很容易吃掉 1.5G 以上内存,在 4G 内存机器上已经占很大一块。建议给 OnlyOffice 设置内存上限,避免它把整台机器拖垮。如果你的机器只有 2G 内存,OnlyOffice 的体验会非常痛苦,可以先临时用 Nextcloud 自带的文本编辑,等硬件升级再启用在线 Office 编辑。
3.4 Nextcloud 容器的启动与初始化
Nextcloud 容器首次启动时会根据环境变量完成安装,这个过程大约几分钟。启动完成后,浏览器通过 Caddy 域名应该能访问到登录页,用NEXTCLOUD_ADMIN_USER和NEXTCLOUD_ADMIN_PASSWORD登录。如果你在安装阶段就发现“访问被拒绝”,多半是TRUSTED_DOMAINS没有把当前访问域名加进去。
登录后的第一件事,我习惯先做三件事:
- 到“管理设置 → 基本设置”,把后台任务从默认的 AJAX 改成 Cron。Nextcloud 的定时任务不改的话,后台同步、清理临时文件都会滞后。
- 到“应用”里安装 ONLYOFFICE 官方集成插件,在设置里填写 OnlyOffice 文档服务地址,比如
https://doc.example.com,并在高级设置里填入相同的 JWT 密钥。 - 开启两步验证,或者至少设置好通知方式,减少管理员账号被爆破的风险。
数据目录方面,我把./data单独挂出来,是为了备份时只备份用户文件,不用背整个代码目录。注意,初次安装后不要再随意改 data 目录路径,否则 Nextcloud 会认为原来的文件丢失了。
4. HTTPS 落地:Caddy 自动证书与反向代理
到这里,私有云已经能跑起来了,但千万别直接关掉内网用 IP 裸奔上公网。没有 HTTPS 的云盘在公网上等于透明文件柜。这一章说清楚为什么必须上 HTTPS,以及怎样做最省事。
4.1 为什么 HTTPS 在这套方案里是刚需
很多人觉得“服务器 IP 别人不知道,不加密也没事”,这个想法非常危险。HTTP 是明文协议,登录时输入的管理员密码、用户密码,编辑文档时传输的文件内容,以及 Nextcloud 调用 OnlyOffice 时携带的 JWT 令牌,全部以明文在网络链路上传输。只要经过任何一个不信任的网络设备,抓包工具就能把内容看得一清二楚,这就是通常说的“明文捕获”问题。
举一个很直观的例子:你在咖啡馆用公共 Wi-Fi 访问自己的云盘,请求先经过路由器再出公网。如果这个 Wi-Fi 被人做了中间人劫持,HTTP 场景下它可以直接拿到你的登录凭证,甚至篡改返回给你的页面脚本。而 HTTPS 相当于给整个会话加了密封,协议层面的校验让中间人拿不到任何有效内容。我们部署 OnlyOffice 时费那么大劲配置 JWT,如果链路本身不加密,这把密钥等于放在透明信封里寄出去的,意义大打折扣。
实际调试接口时你也会发现,很多工具默认拦截 HTTPS 流量,比如录制脚本时要先导入证书并关闭 SSL 校验才能抓到 HTTPS 请求。这反过来印证了,HTTPS 就是为了让不持有证书的人看不到内容而生的。
4.2 Caddy 配置与证书自动续期
Caddy 最吸引人的地方就是自动 HTTPS。只要在 Caddyfile 里写域名,它自动向 Let's Encrypt 申请证书、自动续期,并把 80 端口流量跳转到 443。配置文件如下:
cloud.example.com { reverse_proxy app:80 } doc.example.com { reverse_proxy onlyoffice:80 }保存后重启 Caddy 容器,观察日志,正常情况下几秒钟内就能看到证书申请成功的记录。Caddy 会把证书存在./caddy/data目录,到期前自动续期,不用写 cron 脚本,也不用关心证书路径。
这里提醒两点。第一,Caddy 容器必须能访问外网,且 80 端口要能被 Let's Encrypt 的验证服务器访问到,否则证书申请失败。第二,app:80和onlyoffice:80这种写法依赖 Docker 内部 DNS,因为三个服务都在同一个nextcloud-net网络里,能直接通过服务名解析。如果你把容器单独拆到其他网络,这里要换成宿主机 IP。
4.3 没有域名时的替代方案
没有正规域名的情况我也遇到过不少。一种做法是在本地 DNS 或路由器里设置内部域名解析,比如让cloud.home.local指向服务器内网 IP,然后在 Caddyfile 里指定tls internal,让 Caddy 使用自己管理的内部 CA 签发证书。局域网设备访问时会提示证书不受信任,在浏览器里信任一次即可。
另一种做法更省事:纯内网环境直接 HTTP。反正链路不出局域网,威胁小很多。但必须明确,这种部署方式只能留在内网,不要直接映射到公网,除非你愿意之后把 HTTPS 补上。
5. 实操中的高频异常与排障
这一部分是我最想写的。配置本身不难,真正让人头疼的是各种“表面正常但实际不对”的问题。我把实战中高频出现的问题按模块拆开,给你一份能直接对照排查的清单。
5.1 OnlyOffice 连不上的各种症状
第一个高发症状是浏览器控制台报api.js无法访问,或者在线编辑打开后一直转圈、白屏。我的排查顺序:先确认 OnlyOffice 容器健康,然后从宿主机 curl 一下http://127.0.0.1:8081/api.js,能返回 JS 内容说明服务本身没问题;接下来检查 Nextcloud 里填写的 OnlyOffice 地址是不是https://doc.example.com,域名能解析到本机,以及防火墙、云安全组放通了 443。很多时候仅凭“打不开”判断不出问题,都是这样一层层排除。
第二个高发症状就是“文档安全令牌的格式不正确”。这个问题 80% 是 JWT 密钥不一致。发生错误时,先检查 compose 里 OnlyOffice 的密钥和 Nextcloud 应用设置里的密钥是否完全一样,确认 Nextcloud 设置里打开了“使用 JWT”开关,而不仅仅是填了地址没填密钥。另外,OnlyOffice 版本不同导致的环境变量名差异也可能让密钥没真正生效,建议用docker exec查看容器内环境变量,确认 JWT_SECRET 是否正确。
第三个高发症状是“文件版本已更改,该页面将被重新加载”。这个提示的意思是,编辑器检测到当前打开的文件在服务端版本号或哈希已经变了。常见原因有三类:一是同一份文档被多人同时编辑打开,后者保存时覆盖了前者的状态,触发了版本同步机制;二是文件在 Nextcloud 侧被外部程序修改过,比如通过 occ 命令或同步客户端改了文件;三是 OnlyOffice 和 Nextcloud 之间网络不稳定,WebSocket 断过,重新连接时发现版本不一致。遇到这个提示最直接的处置是保存后关闭当前标签重新打开;如果频繁出现,就要检查网络稳定性,尽量协调团队成员避免多人同时编辑同一份文件。
5.2 Nextcloud 自身的常见问题
Nextcloud 这边最常见的是“访问被拒绝,您不是被允许的”。原因基本都是TRUSTED_DOMAINS没包含当前域名或 IP。处理办法是修改NEXTCLOUD_TRUSTED_DOMAINS环境变量后重启,或者手动编辑 config/config.php 里的trusted_domains数组。
另一个常见问题是页面加载出来却是“内部服务器错误”。这时候千万别急着删除容器,先进 Nextcloud 日志看具体错误。通常要么是数据库连接失败,检查 db 容器是否起来、用户名密码是否正确;要么是 data/config 目录权限不对;要么是 PHP 内存不够。用docker logs nextcloud-app看启动日志,再打开 data/nextcloud.log 看应用日志,基本能定位。
上传文件失败也是高频问题。前端提示“文件超过上传限制”的话,除了改NEXTCLOUD_UPLOAD_LIMIT,还要检查反向代理是否限制请求体大小。Caddy 默认对请求体没有严格限制,一般不用额外设置;但如果用 Nginx 做反代,千万别忘了改client_max_body_size。
5.3 MariaDB 备份与 ARM 平台注意事项
关于备份,很多人搭建完当天很开心,忘记备份,等到硬盘损坏才追悔莫及。MariaDB 的备份建议用脚本加 crontab 来做,数据库和文件目录分开备份。
数据库备份脚本的核心就是用 mysqldump,然后按日期保留最近 N 份:
#!/bin/bash DATE=$(date +%F) mysqldump -h 127.0.0.1 -u nextcloud -p'密码' nextcloud \ | gzip > /backup/nextcloud-db-$DATE.sql.gz find /backup -name "nextcloud-db-*.sql.gz" -mtime +14 -delete脚本丢到宿主机,配合 cron 每天凌晨执行。需要注意,mysqldump 备份前最好确保数据库没有正在进行的写操作,或者用--single-transaction参数做一致性备份。Nextcloud 用户文件目录./data的备份更简单,rsync 到另一块磁盘或对象存储即可,但备份前最好让服务进入维护模式(occ maintenance:mode --on),避免备份过程中文件变化导致备份不一致。
关于 ARM 平台,现在树莓派、飞腾、鲲鹏这类设备跑 Docker 已经很常见。MariaDB 和 Nextcloud 官方镜像都提供 arm64 版本,拉取时 Docker 会自动选择对应架构。OnlyOffice 也有 arm64 镜像,但 ARM 设备上性能下降明显,2G 内存的小主机跑 OnlyOffice 会非常吃力。如果目标设备是 ARM 小主机,建议先进纯 Nextcloud 跑文件同步,OnlyOffice 等换了硬件再考虑。
6. 常见问题速查表与我的个人体会
把前面散落在各处的排查要点整理成速查表,方便收藏备用。
| 症状 | 可能原因 | 解决思路 |
|---|---|---|
| 在线编辑保存报“文档安全令牌的格式不正确” | JWT 密钥不一致或环境变量名不匹配 | 检查 compose、容器环境变量、Nextcloud 设置三处一致 |
| 打开在线编辑白屏,控制台报 api.js 无法访问 | OnlyOffice 服务端口不通或地址错误 | 从宿主机 curl 测试,检查 DNS、防火墙 |
| 编辑后提示“文件版本已更改,该页面将被重新加载” | 多人并发编辑或文件被外部修改 | 重新打开文档,避免多人同时编辑同一文件 |
| Nextcloud 访问被拒绝 | trusted_domains 未包含当前域名 | 更新环境变量重启,或直接改 config.php |
| 页面提示“内部服务器错误” | 数据库不通 / 目录权限错误 / PHP 内存不足 | 看 docker logs 和 nextcloud.log 定位 |
| 上传文件提示超限 | PHP 限制或反代限制请求体 | 设置 NEXTCLOUD_UPLOAD_LIMIT,Nginx 改 client_max_body_size |
| MariaDB 容器反复重启 | 数据目录权限或端口占用 | 查看 docker logs db,确认 UID/GID 和数据目录状态 |
| 证书申请失败 | 80 端口不可达或域名未解析 | 检查 DNS、防火墙、云安全组 |
6.1 第一次搭建时的实操建议
如果你之前没有搭过 Nextcloud,我建议第一次动手时不要在正式数据上折腾。先按这套方案跑通,导入一部分测试文件,用几天看看备份和恢复流程是否顺畅,确认没问题后再同步正式数据。不要一上来就把全家照片、工作文件全部塞进去,否则出问题的时候连退路都没有。
6.2 最后分享一点我自己的体会
这套方案我前后在好几台机器上部署过,从 2 核 4G 的云主机到家里的旧笔记本都有。最大的体会是,只要容器编排逻辑理顺了,换机器部署就是拷贝目录加调整环境变量的事,没什么玄学。真正值得花时间的不是“把容器拉起来”,而是“怎么让服务在跑崩之后能快速恢复”。备份、日志、版本回滚这三件事,建议从第一天就养成习惯。
最后再分享一个小技巧:给服务器配个定时任务,让 Nextcloud 定期通过 occ 命令清理临时文件和回收站,避免数据目录无限膨胀。类似docker exec -u www-data nextcloud-app php occ trashbin:cleanup这样的命令,配合 cron 每周跑一次。这个小习惯能让你的私有云长期保持清爽,不至于用了几个月后磁盘被塞满才发现。