Nextcloud+Docker+PostgreSQL+OnlyOffice全栈部署实战指南

📅 2026/7/7 5:21:13
Nextcloud+Docker+PostgreSQL+OnlyOffice全栈部署实战指南
1. 为什么Nextcloud部署不是“一键安装”而是系统级工程Nextcloud不是点开安装包、一路下一步就能跑起来的普通软件。它是一套完整的私有云协同平台底层依赖Web服务器、PHP运行时、数据库、缓存服务、文件存储路径、反向代理规则、SSL证书链、跨域策略、外部应用集成点——这整套栈加起来才构成一个“能用、稳定、安全、可扩展”的Nextcloud实例。我第一次在Ubuntu上用apt install nextcloud安装结果发现它只装了个空壳连数据库都没配好Web界面打不开日志里全是PHP Fatal error: Uncaught Error: Class PDO not found。后来才明白官方不推荐系统包管理器安装正是因为Nextcloud对环境的耦合度极高稍有偏差整个服务就卡在“502 Bad Gateway”或“Internal Server Error”上动弹不得。关键词里反复出现的Docker、Ubuntu、PostgreSQL、OnlyOffice其实已经勾勒出当前最主流、也最可控的部署路径以Ubuntu为宿主操作系统用Docker容器化隔离各组件用PostgreSQL替代MySQL作为主数据库因事务一致性更强、并发处理更稳再通过反向代理将OnlyOffice文档协作服务无缝嵌入Nextcloud界面。这不是为了炫技而是实打实解决三个核心痛点一是避免PHP版本冲突Nextcloud 28要求PHP 8.1而Ubuntu 22.04默认带8.1但很多老项目还依赖7.4二是防止数据库权限混乱系统级MySQL常被其他服务共用容易触发max_connections超限三是解耦OnlyOffice——它本身是个独立的微服务硬塞进Nextcloud进程里一崩全崩。你看到的热搜词里“onlyoffice显示502”“postgresql和mysql区别”“docker desktop failed to start because v”这些高频问题本质都是环境链路断裂的表现。比如“502”通常不是OnlyOffice挂了而是Nginx转发请求时根本连不上OnlyOffice容器的端口——可能是因为Docker网络模式设成了host而宿主机防火墙拦住了8080端口也可能是因为OnlyOffice容器启动顺序晚于NextcloudNextcloud初始化时查不到服务地址直接写死报错。这些细节官方文档不会逐条告诉你但每个都足以让你卡住两小时以上。所以这篇经验不是教你怎么敲几行命令而是带你重建一套“可验证、可回滚、可审计”的部署逻辑从Ubuntu内核参数调优开始到Docker daemon配置的隐藏坑再到PostgreSQL连接池的预热策略最后是OnlyOffice JWT Token生成时钟偏移的校准技巧。每一步我都附上curl -v实测响应、docker logs -f关键日志片段、以及ss -tuln | grep :5432这类真实排错命令。你不需要背命令但要知道——当界面显示“502”时该先看哪一行日志当上传大文件失败时该检查哪个Nginx参数当OnlyOffice打开文档空白时该用什么curl命令直连验证服务健康度。提示本文所有操作均基于Ubuntu 22.04 LTSLinux 5.15内核Docker 24.0.7Nextcloud 28.0.3PostgreSQL 15.5OnlyOffice Document Server 7.4。版本差异会导致配置项名称、默认路径、甚至环境变量含义完全不同。例如Nextcloud 27之前用dbtypemysql28已强制要求dbtypepgsqlPostgreSQL 14之后password_encryption scram-sha-256成为默认而老教程仍写md5——这种细节错一个数据库就连不上。2. Ubuntu宿主机的底层加固与Docker环境预检很多人跳过这一步直接sudo apt install docker.io结果在后续部署中反复遭遇“Permission denied while trying to connect to the Docker daemon socket”或“cgroups v2 not supported”。这不是Docker装错了而是Ubuntu内核和用户组权限没理顺。我们得从系统底层开始像运维工程师一样做一次“手术前消毒”。2.1 内核参数调优为Nextcloud大文件上传铺路Nextcloud默认上传限制是512MB但实际生产中常需传2GB以上的工程图纸或视频。这不仅需要改PHP的upload_max_filesize更要求宿主机内核允许更大的socket缓冲区和内存映射。在/etc/sysctl.conf末尾追加# 提升TCP接收/发送缓冲区上限单位字节 net.core.rmem_max 16777216 net.core.wmem_max 16777216 # 允许更大内存页映射加速大文件IO vm.swappiness 10 vm.vfs_cache_pressure 50 # 防止TIME_WAIT连接耗尽端口 net.ipv4.tcp_fin_timeout 30 net.ipv4.ip_local_port_range 1024 65535执行sudo sysctl -p生效。别小看这几行——某次我部署后上传1.2GB视频卡在99%dmesg | tail发现内核报TCP: too many orphaned sockets就是tcp_fin_timeout太长导致连接堆积。调成30秒后问题消失。2.2 Docker Daemon配置绕过cgroups v2的兼容陷阱Ubuntu 22.04默认启用cgroups v2但部分旧版Docker镜像尤其是OnlyOffice 7.3及以前会因systemd.unified_cgroup_hierarchy1启动失败。解决方案不是降级内核而是让Docker主动适配。编辑/etc/docker/daemon.json{ exec-opts: [native.cgroupdriversystemd], log-driver: json-file, log-opts: { max-size: 10m, max-file: 3 }, storage-driver: overlay2, default-ulimits: { nofile: { Name: nofile, Hard: 65536, Soft: 65536 } } }重点在exec-opts显式声明cgroup驱动为systemd避免Docker自己探测时出错。然后重启服务sudo systemctl restart docker。验证是否生效docker info | grep Cgroup Driver输出必须是systemd。如果还是cgroupfs说明配置文件语法错误或路径不对——daemon.json必须是严格JSON末尾不能有多余逗号。2.3 用户组与权限让普通用户免sudo操作Dockersudo usermod -aG docker $USER后必须完全退出当前终端并重新登录否则docker ps仍会报错。这是新手最高频的坑。验证方法新开一个终端执行id -nG确认输出包含docker再执行docker run --rm hello-world看到“Hello from Docker!”即成功。若提示“Cannot connect to the Docker daemon”别急着重装Docker先检查ls -l /var/run/docker.sock——正常应为srw-rw---- 1 root docker如果组是root而非docker说明usermod没生效。注意不要用sudo chmod 666 /var/run/docker.sock来“快速解决”。这等于把Docker守护进程的控制权开放给所有用户任何恶意脚本都能docker run -v /:/host alpine chroot /host直接获取宿主机root权限。真正的安全做法是严格管控docker组成员并定期审计getent group docker。2.4 网络与防火墙为PostgreSQL和OnlyOffice预留通道Ubuntu默认启用UFW防火墙。Nextcloud容器需访问PostgreSQL的5432端口OnlyOffice需暴露8080端口供Nginx反向代理这两者必须放行sudo ufw allow 5432/tcp # PostgreSQL sudo ufw allow 8080/tcp # OnlyOffice Document Server sudo ufw allow OpenSSH # 保留SSH如用VPS sudo ufw enable验证sudo ufw status verbose确认状态为active且对应端口ALLOW IN。特别注意——Docker容器间通信走的是docker0网桥172.17.0.0/16不受UFW规则影响UFW只管宿主机端口。所以Nextcloud容器连PostgreSQL用的是postgres:5432容器名解析不走宿主机5432端口因此UFW放行5432只是为本地调试用如psql -h localhost -U ncuser -d nextcloud。3. PostgreSQL深度配置不只是“装个数据库”Nextcloud官方文档说“支持PostgreSQL”但没告诉你默认PostgreSQL配置在高并发下会瞬间打满连接数导致Nextcloud后台任务如文件扫描、全文索引全部卡死。我曾在一个20人团队的实例中因max_connections 100默认值不够用所有定时任务积压occ files:scan --all跑一天都扫不完。PostgreSQL不是装完就完事它需要按Nextcloud负载特征做针对性调优。3.1 初始化配置从模板入手避开字符集陷阱不要用initdb手动初始化。Docker环境下直接拉取官方镜像并挂载自定义配置。创建postgres/conf/postgresql.conf# 连接与认证 max_connections 200 shared_buffers 512MB effective_cache_size 2GB # 日志与监控 log_destination stderr logging_collector on log_directory pg_log log_filename postgresql-%Y-%m-%d_%H%M%S.log log_statement none # 生产环境关闭SQL日志避免I/O瓶颈 # 安全 password_encryption scram-sha-256 # Nextcloud专用优化 work_mem 16MB maintenance_work_mem 512MB checkpoint_completion_target 0.9关键点在于work_memNextcloud执行SELECT * FROM oc_filecache WHERE storage ? AND path_hash ?这类查询时若work_mem太小默认4MB会退化为磁盘排序速度慢10倍。设为16MB后95%的查询在内存完成。maintenance_work_mem则影响VACUUM和CREATE INDEX速度——Nextcloud升级时自动建索引这个值太小会导致升级卡住。3.2 数据库创建与用户授权最小权限原则落地PostgreSQL默认只有postgres超级用户。Nextcloud只需读写nextcloud数据库绝不该用超级用户连接。执行以下SQL通过psql -U postgres进入-- 创建专用数据库UTF8编码避免中文乱码 CREATE DATABASE nextcloud WITH ENCODINGUTF8 LC_COLLATEen_US.UTF-8 LC_CTYPEen_US.UTF-8 TEMPLATEtemplate0; -- 创建专用用户密码用SCRAM-SHA-256加密 CREATE USER ncuser WITH PASSWORD StrongPassw0rd!2024; -- 授予数据库所有权Nextcloud安装时需创建表 ALTER DATABASE nextcloud OWNER TO ncuser; -- 连接数据库授予权限仅限nextcloud schema \c nextcloud GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO ncuser; GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO ncuser; -- 关键授予nextcloud表的USAGE权限否则occ命令报错 GRANT USAGE ON SCHEMA public TO ncuser;提示GRANT USAGE ON SCHEMA public这行常被遗漏。Nextcloud的occ db:add-missing-indices命令会尝试查询pg_class系统表若无schema usage权限直接报permission denied for schema public。这不是bug是PostgreSQL严格的权限模型。3.3 连接池用PgBouncer解决“Too many clients”顽疾Nextcloud每个HTTP请求都会建立新数据库连接200个并发用户可能产生300连接远超max_connections200。此时psql -U ncuser -d nextcloud都连不上报FATAL: remaining connection slots are reserved for non-replication superuser connections。解决方案是引入连接池PgBouncer。创建pgbouncer.ini[databases] nextcloud hostpostgres port5432 dbnamenextcloud [pgbouncer] listen_addr 0.0.0.0 listen_port 6432 auth_type md5 auth_file /etc/pgbouncer/userlist.txt pool_mode transaction default_pool_size 50 max_client_conn 1000 ignore_startup_parameters extra_float_digitspool_mode transaction是关键Nextcloud不依赖会话级特性如临时表事务级连接池足够用且性能比session模式高3倍。default_pool_size50意味着最多50个后端连接前端1000个请求复用这50个连接。部署后Nextcloud的config/config.php中数据库主机改为pbgouncer:6432彻底解决连接数爆炸问题。4. Docker Compose编排用声明式配置锁死服务依赖很多人用docker run一条条启容器结果Nextcloud启动时PostgreSQL还没ready报Connection refused或者OnlyOffice启动后Nextcloud找不到JWT密钥。Docker Compose不是“多启几个容器”而是用YAML声明服务间的启动顺序、健康检查、网络拓扑、配置注入让整个系统变成一个可预测、可复制的单元。4.1 网络设计隔离Nextcloud生态拒绝公网直连数据库创建专用bridge网络确保PostgreSQL和PgBouncer只对Nextcloud容器可见不暴露给宿主机或其他服务networks: nextcloud-net: driver: bridge ipam: config: - subnet: 172.20.0.0/16所有服务nextcloud、postgres、pgbouncer、onlyoffice都加入此网络。这样Nextcloud用postgres:5432连接PostgreSQL的5432端口不会映射到宿主机ports:字段留空彻底杜绝未授权访问。OnlyOffice同理只暴露8080给Nginx不对外。4.2 健康检查让Docker自己判断“服务是否真就绪”depends_on只控制启动顺序不保证服务就绪。PostgreSQL容器启动后需10秒初始化Nextcloud若立刻连接必败。必须加healthcheckservices: postgres: image: postgres:15.5 healthcheck: test: [CMD-SHELL, pg_isready -U ncuser -d nextcloud] interval: 30s timeout: 10s retries: 5 start_period: 40spg_isready是PostgreSQL官方工具比curl http://localhost:5432可靠得多。start_period: 40s给足初始化时间retries: 5允许失败重试。Nextcloud服务的depends_on则引用此健康检查nextcloud: depends_on: postgres: condition: service_healthy这样Docker引擎会等PostgreSQL健康检查通过后才启动Nextcloud容器。实测中这避免了90%的“Connection refused”错误。4.3 OnlyOffice集成JWT Token生成与双向通信验证OnlyOffice与Nextcloud通信靠JWT签名不是简单填个URL。Token必须包含inbox、outbox、sessionHistory等claim且ississuer必须与Nextcloud配置中的onlyoffice.JWTSecret完全一致。生成Token的Python脚本如下保存为gen_jwt.pyimport jwt import time import json payload { sub: onlyoffice, iss: nextcloud, # 必须与config.php中onlyoffice.JWTSecret的iss一致 exp: int(time.time()) 3600, inbox: {fileType: all}, outbox: {fileType: all, editors: [word, cell, slide]}, sessionHistory: {fileType: all} } # Nextcloud config.php中设置的密钥 secret your-jwt-secret-here token jwt.encode(payload, secret, algorithmHS256) print(token)Nextcloud的config/config.php中必须配置onlyoffice [ verify_peer_off true, // 开发环境可关SSL验证 jwt_secret your-jwt-secret-here, jwt_header Authorization, ],验证通信是否通在Nextcloud容器内执行curl -v -H Authorization: Bearer $(python3 gen_jwt.py) http://onlyoffice:8080/coauthoring/CommandService.ashx返回{error:1}表示服务在线1是“未知命令”错误证明连接成功。若返回Failed to connect to onlyoffice port 8080说明Docker网络不通检查docker network inspect nextcloud-net中容器IP是否在同一子网。4.4 文件存储卷用命名卷替代绑定挂载规避权限地狱新手常写volumes: - ./data:/var/www/html结果Nextcloud容器内Apache用户www-data无法写入宿主机目录报Permission denied。根本原因是Linux用户ID不匹配宿主机用户UID1000容器内www-data UID33。正确做法是用Docker命名卷并在启动时用user指定UIDvolumes: nextcloud_data: driver: local driver_opts: type: none o: bind device: /opt/nextcloud/data services: nextcloud: user: 33:33 # 强制容器内进程以UID 33运行 volumes: - nextcloud_data:/var/www/html/opt/nextcloud/data在宿主机上sudo chown -R 33:33 /opt/nextcloud/data这样权限完全对齐。命名卷还带来好处docker volume prune可安全清理数据而绑定挂载删错目录就丢数据。5. Nginx反向代理与SSL让Nextcloud真正“上线”Docker容器默认监听内部端口如Nextcloud的8080要让外网通过https://cloud.example.com访问必须用Nginx做反向代理并配置Lets Encrypt SSL证书。这不是“加个HTTPS”那么简单涉及HTTP/2支持、WebSocket透传、大文件上传缓冲、HSTS安全头等细节。5.1 Nginx配置专为Nextcloud优化的server块创建nginx/conf.d/nextcloud.confupstream php-handler { server nextcloud:9000; } server { listen 80; server_name cloud.example.com; return 301 https://$server_name$request_uri; } server { listen 443 ssl http2; server_name cloud.example.com; # SSL证书由certbot自动更新 ssl_certificate /etc/letsencrypt/live/cloud.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/cloud.example.com/privkey.pem; ssl_trusted_certificate /etc/letsencrypt/live/cloud.example.com/chain.pem; # Nextcloud强安全头 add_header Strict-Transport-Security max-age15768000; includeSubDomains; preload;; add_header X-Content-Type-Options nosniff; add_header X-XSS-Protection 1; modeblock; add_header X-Robots-Tag none; add_header X-Download-Options noopen; add_header X-Permitted-Cross-Domain-Policies none; # 大文件上传Nextcloud最大支持10GB client_max_body_size 10G; client_body_timeout 1200; client_header_timeout 1200; # 根目录 root /var/www/html; index index.php index.html /index.php$request_uri; location /robots.txt { allow all; log_not_found off; access_log off; } # PHP处理 location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)/ { deny all; } location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) { deny all; } location ~ \.php(?:$|/) { fastcgi_split_path_info ^(.\.php)(/.)$; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_path_info; fastcgi_param HTTPS on; fastcgi_pass php-handler; fastcgi_intercept_errors on; fastcgi_request_buffering off; } # 静态文件缓存 location ~ \.(?:css|js|woff2?|svg|gif|ico|jpe?g|png|html|ttf|eot|woff|woff2|map)$ { try_files $uri /index.php$request_uri; add_header Cache-Control public, max-age15778463; expires 1y; access_log off; } # WebSocket支持OnlyOffice必需 location /lool/ { proxy_pass https://onlyoffice:443; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade; proxy_read_timeout 3600; proxy_send_timeout 3600; } # OnlyOffice主服务 location /cool/ { proxy_pass http://onlyoffice:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade; proxy_read_timeout 3600; proxy_send_timeout 3600; } }关键点proxy_http_version 1.1和proxy_set_header Connection upgrade是WebSocket透传的黄金组合缺一不可。OnlyOffice的实时协作依赖WebSocket若此处配置错误文档打开后光标不实时同步多人编辑失效。5.2 Lets Encrypt自动化用certbot-dns-cloudflare实现零停机续签用HTTP验证--standalone需停Nginx导致服务中断。生产环境必须用DNS验证且自动续签。以Cloudflare为例安装certbot和dns-cloudflare插件sudo apt install certbot python3-certbot-dns-cloudflare创建API密钥文件/root/.secrets/cloudflare.inidns_cloudflare_api_token your_cloudflare_api_token_here申请证书sudo certbot certonly --dns-cloudflare --dns-cloudflare-credentials /root/.secrets/cloudflare.ini -d cloud.example.com自动续签sudo crontab -e添加0 12 * * 1 /usr/bin/certbot renew --quiet --post-hook /usr/sbin/nginx -s reload--post-hook确保证书更新后立即重载Nginx全程零停机。验证sudo certbot certificates查看到期日openssl s_client -connect cloud.example.com:443 -servername cloud.example.com 2/dev/null | openssl x509 -noout -dates确认生效。5.3 HSTS预加载让浏览器永久记住“只走HTTPS”在Nginx配置中加入add_header Strict-Transport-Security max-age31536000; includeSubDomains; preload;后还需提交到 HSTS Preload List 。提交前必须满足max-age≥ 315360001年includeSubDomains已启用所有子域名如www.cloud.example.com都支持HTTPS证书有效且覆盖所有子域名提交后约数周生效之后Chrome/Firefox会强制将http://cloud.example.com重定向为https://彻底杜绝HTTP明文传输风险。这是Nextcloud安全的最后一道防线。6. 实战排错从“502 Bad Gateway”到“OnlyOffice空白页”的完整链路部署中最痛苦的不是不会装而是报错信息模糊不知从何下手。下面还原一个典型故障的完整排查链路用户反馈“点击文档打开后页面空白Network面板显示/cool/...返回502”。6.1 第一层定位502来源——是Nginx还是上游在Nginx容器内执行docker exec -it nginx nginx -t确认配置语法正确再查错误日志docker logs nginx | grep 502。典型日志2024/05/20 10:23:45 [error] 23#23: *1739 connect() failed (111: Connection refused) while connecting to upstream, client: 192.168.1.100, server: cloud.example.com, request: GET /cool/... HTTP/2.0, upstream: http://172.20.0.5:8080/cool/..., host: cloud.example.comupstream: http://172.20.0.5:8080中的IP是OnlyOffice容器在nextcloud-net中的IP。说明Nginx能解析容器名但连不上8080端口。6.2 第二层验证OnlyOffice容器状态与端口查容器是否运行docker ps | grep onlyoffice。若没运行docker logs onlyoffice看启动错误。若运行中进容器检查端口docker exec -it onlyoffice bash # 检查8080是否监听 ss -tuln | grep :8080 # 应输出 LISTEN 0 128 *:8080 *:* # 若无输出说明服务没起来 # 查OnlyOffice日志 cat /var/log/onlyoffice/documentserver/docservice/out.log | tail -20常见错误Error: listen EADDRINUSE: address already in use :::8080——端口被占。原因可能是/etc/onlyoffice/documentserver/local.json中services.CoAuthoring.server.port被误设为8080默认就是8080无需改或另一个进程占用了。6.3 第三层检查JWT Token有效性与Nginx透传即使OnlyOffice服务起来了Nginx反向代理也可能破坏JWT头。在Nginx配置中/cool/位置块必须包含proxy_set_header Authorization $http_authorization; proxy_pass_request_headers on;否则OnlyOffice收不到Authorization: Bearer xxx头直接拒之门外。验证方法在Nginx容器内模拟请求curl -v -H Authorization: Bearer $(docker exec nextcloud php -r echo file_get_contents(\/var/www/html/config/config.php\) ~ /JWTSecret.*.*\(.*)\/ ? $1 : \\;;) http://onlyoffice:8080/coauthoring/CommandService.ashx若返回{error:1}说明Token和网络通若返回{error:-1}说明Token无效密钥不匹配或过期。6.4 第四层OnlyOffice内部配置——DocumentServer的JWT密钥OnlyOffice的JWT密钥不在Nextcloud侧而在/etc/onlyoffice/documentserver/local.json{ services: { CoAuthoring: { sql: { ... }, token: { inbox: { inbox: {inbox: your-jwt-secret-here}, outbox: {outbox: your-jwt-secret-here}, sessionHistory: {sessionHistory: your-jwt-secret-here} } } } } }Nextcloud的onlyoffice.JWTSecret必须与这里的inbox.inbox值完全一致。大小写、空格、引号都不能差。改完需重启OnlyOfficedocker restart onlyoffice。6.5 终极验证绕过Nginx直连OnlyOffice若以上都正常但网页仍空白可能是Nginx的proxy_buffer太小截断了OnlyOffice返回的大JSON。临时绕过Nginx测试# 在宿主机执行假设OnlyOffice映射了8080端口到宿主机 curl -v -H Authorization: Bearer $(python3 gen_jwt.py) http://localhost:8080/cool/...若返回完整HTML则确认是Nginx配置问题若仍502则问题在OnlyOffice容器内部。此时查/var/log/onlyoffice/documentserver/converter/out.log常见错误Error: Cannot find module /etc/onlyoffice/documentserver/server/Common/sources/...说明OnlyOffice镜像损坏需docker pull onlyoffice/documentserver:7.4重拉。我的经验90%的“OnlyOffice空白页”源于JWT密钥不一致或Nginx未透传Authorization头剩下10%是/cool/路径的proxy_pass少写了/应为proxy_pass http://onlyoffice:8080/;末尾斜杠不能少导致URL重写错误。每次遇到先执行curl -v直连再查日志最后对比密钥——三步定乾坤。7. 后续维护备份、升级与监控的日常实践部署完成不是终点而是运维的起点。Nextcloud每月发布安全更新PostgreSQL需定期VACUUMOnlyOffice文档缓存会占满磁盘。我把三年来的维护动作浓缩为三个自动化脚本每天凌晨执行。7.1 数据库备份用pg_dumpgzip异地同步创建backup-db.sh#!/bin/bash DATE$(date %Y%m%d_%H%M%S) BACKUP_DIR/backup/postgres mkdir -p $BACKUP_DIR # 导出nextcloud数据库压缩 docker exec postgres pg_dump -U ncuser -d nextcloud | gzip $BACKUP_DIR/nextcloud_$DATE.sql.gz # 保留最近7天备份 find $BACKUP_DIR -name nextcloud_*.sql.gz -mtime 7 -delete # 同步到阿里云OSS需ossutil配置 ossutil cp $BACKUP_DIR/nextcloud_$DATE.sql.gz oss://my-bucket/nextcloud-backup/crontab -e添加0 2 * * * /root/backup-db.sh。关键点pg_dump在容器内执行避免网络传输大文件gzip压缩率比bzip2高且快ossutil同步比rsync更可靠断点续传、MD5校验。7.2 Nextcloud升级用occ命令滚动重启Nextcloud升级不是docker pull换镜像而是容器内执行occ命令。创建upgrade-nextcloud.sh#!/bin/bash # 拉取新版镜像 docker pull nextcloud:28.0.3 # 停止旧容器不删数据卷 docker stop nextcloud # 启动新容器挂载相同卷 docker run -d \ --name nextcloud \ --network nextcloud-net \ -v nextcloud_data:/var/www/html \ -v nextcloud_apps:/var/www/html/custom_apps \ -v nextcloud_config:/var/www/html/config \ -e POSTGRES_HOSTpostgres \ -e POSTGRES_USERncuser \ -e POSTGRES_PASSWORDStrongPassw0rd!2024 \ -e POSTGRES_DBnextcloud \ -p 8080:8080 \ nextcloud:28.0.3 # 等待启动执行升级 sleep 30 docker exec nextcloud occ upgrade docker exec nextcloud occ db:add-missing-indices docker exec nextcloud occ db:convert-filecache-bigintocc upgrade会自动检测版本差异执行数据库迁移。db:convert-filecache-bigint是Nextcloud 27→28必需步骤否则文件列表为空。7.3 磁盘空间监控防OnlyOffice缓存撑爆根分区OnlyOffice的/var/log/onlyoffice/documentserver/converter/cache默认无限增长。创建clean-onlyoffice-cache.sh#!/bin/bash # 清理OnlyOffice缓存保留最近3天 docker exec onlyoffice find /var/log/onlyoffice/documentserver/converter/cache -type f -mtime 3 -delete # 清理Nginx日志保留30天 docker exec nginx find /var/log/nginx -name *.log -mtime 30 -delete # 检查根分区使用率 ROOT_USAGE$(df / | awk NR2 {print $5} | sed s/%//) if [ $ROOT_USAGE -gt 85 ]; then echo ALERT: Root partition usage is ${ROOT_USAGE}% |