首页 / 资讯中心 / 文章详情

Docker+Nextcloud自建网盘与公网HTTPS访问实战

Docker+Nextcloud自建网盘与公网HTTPS访问实战 ★ FEATURED ARTICLE
自己攒设备当网盘最怕两件事一是数据放在别人家服务器上心里不踏实二是折腾半天最后只能在局域网里自娱自乐。我在 Linux 上用 Docker 跑 Nextcloud 这套组合已经换过三台机器从家里的小主机到租来的云服务器中间踩的坑基本集中在两处——容器化之后目录和权限怎么摆以及怎么让它在公网上被安全地访问到。这篇就把我这几轮折腾下来的完整路径摊开讲从系统准备、compose 配置、数据库和缓存的取舍到域名解析、证书签发、请求转发再到最后那些只有真跑起来才会遇到的排查细节。适合手里有一台闲置机器或者一台基础配置云服务器、想把文件同步和相册备份抓回自己手里的朋友也适合已经跑起来但卡在远程访问这一步、被访问不被信任的域名或者大文件上传超时折磨过的人。全程照着抄能跑通但每一步背后的原因我也会说清楚省得你换个环境就抓瞎。1. 先把需求和技术选型捋清楚1.1 自建网盘到底要解决什么问题动手之前得先明确自己图什么不然很容易变成为了折腾而折腾。我当初的诉求很具体手机相册要能自动备份到自己的盘上、几台设备之间要能双向同步工作文件、偶尔要给外部的人发一个带密码和有效期的分享链接、顺手把日历和通讯录也统一管起来。再往后还希望能在线预览 Office 文档和 PDF、能挂 WebDAV 给一些老工具用。这几条列出来候选方案其实就很少了——Nextcloud 在这几个维度上是覆盖得最全的开源实现桌面端、移动端、Web 端都有官方客户端WebDAV 和 CalDAV/CardDAV 都是原生支持插件生态也够厚。真正需要自己想清楚的是另一件事这台机器放在哪、数据存在哪、谁有权限碰它。放在家里意味着你要处理公网地址的问题放在云服务器上意味着你要为磁盘和流量付费但省掉了网络那一堆麻烦。我个人是两条腿走路——主力数据在家里的机器上云端只放一些需要随时调取的资料。这个决定会直接影响后面的方案选型所以建议你在动手之前就把这件事定下来。1.2 为什么用容器而不是直接装源码包源码方式部署 Nextcloud 的老玩家应该都有印象那是一条相当长的依赖链PHP 及十几个扩展gd、zip、intl、bcmath、imagick、apcu、redis 等、Web 服务器、数据库、缓存装完之后还要处理文件属主、目录权限、.htaccess生效、OPcache 参数。升级更麻烦要进维护模式、替换目录、跑occ upgrade、再对一堆目录重新 chown。这套流程熟悉了不算难但每次大版本升级都得提心吊胆。容器化把依赖全部固化进镜像升级的本质变成了改一个版本号然后重启出问题就把版本号改回去重新起来回滚成本极低。这是我选 Docker 最核心的理由——不是说容器性能更好而是它把环境一致性这件事解决了。但容器化也带来了三个必须提前知道的代价。第一是文件属主Nextcloud 镜像里的 Apache 以www-datauid 33、gid 33运行而宿主机上你登录的用户往往是 uid 1000挂载进去的目录如果属主不对表现为安装向导走完直接白屏或者报 500日志里全是权限拒绝。第二是配置里的地址不能写死容器每次重建 IP 都可能变所以配置里只能用服务名compose 里的服务名会被自动解析而不能写容器 IP。第三是数据目录的边界/var/www/html里既有程序文件也有用户数据全塞在一个挂载点里将来备份、迁移、升级都会很别扭得提前拆开。提示容器化不等于不用管系统宿主机的时间同步、磁盘空间、内核参数该配还是要配出问题时排查顺序永远是先宿主机再容器。1.3 部署前的硬件与系统环境清单我给自己定的最低线是 2 核 CPU、2GB 内存、20GB 系统盘数据盘另算。2GB 内存跑 MariaDB PHP Redis 是偏紧的能上 4GB 会舒服很多如果只有 2GB务必加一个 2GB 的 swap 文件兜底否则在同步大量小文件的时候极容易被 OOM 杀掉进程。文件系统用 ext4 或 xfs 都行别用网络上挂载的目录做数据盘——尤其是把数据库目录放在共享存储上锁机制会出各种诡异问题。系统我一般用 Debian 12 或者同系的版本软件包版本新、Docker 官方源支持好。如果你的系统默认开了 SELinux挂载目录时要加:z或:Z后缀不然容器里的进程会被拒绝访问用 AppArmor 的系统则要留意默认策略有没有拦网络绑定。这一步很多人会忽略结果就是容器起来了但页面永远转圈日志里一行 SELinux denied 藏得很深。还有一个容易被跳过的动作先确认磁盘空间和 inode。df -h看容量df -i看 inode 数量。Nextcloud 会给每个文件写元数据同步几十万个小文件的时候 inode 消耗得比想象中快之前有个朋友的盘 40GB 没用完就写不进去了一查 inode 满了。2. 部署前的关键决策目录、数据库、缓存怎么选2.1 目录规划把家底和程序分开我现在的目录结构是这样的你可以直接照搬/opt/nextcloud/ ├── app/ # 程序文件挂到 /var/www/html ├── data/ # 用户数据挂到 /var/www/html/data ├── db/ # 数据库数据目录 ├── redis/ # 缓存持久化 ├── php/ # 自定义 php.ini ├── nginx/ # 转发层配置与站点 └── certs/ # 证书为什么要把app和data分开挂载因为data目录里装的是用户上传的所有文件体积会一直涨备份策略和app完全不同。app只需要在升级前做一次快照data则是天天要增量备份的对象。两者混在一个挂载点里将来想把数据迁到一块更大的盘上就得全量搬一遍几十上百 GB 搬起来很痛苦。拆开之后加盘、扩容、单独挂载都变得很轻松。有个细节首次启动前必须手动创建这些目录并改属主data目录要chown -R 33:33。如果你忘了这一步安装向导会在写配置文件那一步失败报错信息还很不直观。我习惯在写 compose 之前就把这行命令执行掉宁可多敲一次。mkdir -p /opt/nextcloud/{app,data,db,redis,php,nginx,certs} chown -R 33:33 /opt/nextcloud/app /opt/nextcloud/data chmod 750 /opt/nextcloud/datadata目录给 750 是有意为之——里面是明文文件同机器上的其他普通用户不该能直接读。2.2 数据库选型SQLite、MariaDB、PostgreSQL 的取舍Nextcloud 默认允许 SQLite装起来确实快单人用、文件量几千个以内完全没问题。但它的问题是写并发SQLite 用的是库级锁多个客户端同时同步、同时又有人在网页上操作的时候很容易出现 database is locked表现为客户端一直重试、同步卡在某个百分比。多人共用的场景我强烈建议直接上 MariaDB。PostgreSQL 也能用功能上没短板但社区里现成的排错经验相对少一些遇到问题搜到的答案经常是 MySQL 系的。我选 MariaDB 纯粹是因为踩坑时更容易找到同路人。参数上2GB 内存的机器我会在 compose 里给 MariaDB 加一段启动参数主要是把 InnoDB 的缓冲池控制在合理范围别让它把内存吃干command: - --transaction-isolationREAD-COMMITTED - --binlog-formatROW - --innodb-buffer-pool-size256M - --innodb-flush-log-at-trx-commit2READ-COMMITTED和ROW是 Nextcloud 官方文档里明确建议的组合主要是为了避免同步过程中出现意料之外的间隙锁。innodb-flush-log-at-trx-commit2是拿一点点断电风险换写入性能家用场景可以接受如果你放的是重要资料改回默认的 1 更保险。2.3 缓存与性能组件Redis 该不该上Redis 在 Nextcloud 里承担两件事一是文件锁file locking二是分布式缓存。文件锁这件事在多人或多端同时写同一个文件时非常关键没有它就容易出现两个客户端互相覆盖、文件版本混乱。APCu 单机也能顶一部分但它只在 PHP 进程内共享多进程下效果有限Redis 是独立进程所有 worker 共享同一份锁表行为更可预期。我的建议是只要你打算长期用、且不止一台设备在同步就把 Redis 加上。它占的内存很小我这边常驻 30MB 左右收益却很明显——网页端的页面加载、缩略图生成、文件列表刷新都会快一截。配的时候记得给它设密码别裸奔。虽然它只监听容器内部网络但多一层防护不亏command: redis-server --requirepass 换成你的口令 --maxmemory 128mb --maxmemory-policy allkeys-lruallkeys-lru这个策略是有意的缓存嘛内存满了就淘汰最久没用的不需要持久保证。但注意别把 Redis 当成唯一存储来放重要数据它只是缓存。2.4 一张表看清各组件的取舍组件选轻量方案选完整方案我的建议数据库SQLiteMariaDB超过 1000 个文件或 2 台以上设备就上 MariaDB缓存APCuRedis长期使用直接上 Redis省得后面迁移Web 服务容器内置 Apache独立 Nginx 转发要上 HTTPS 和域名就用独立 Nginx存储单盘独立数据盘数据量超过 50GB 就单独挂盘访问方式局域网 IP域名 HTTPS只要有外部访问需求就必须上域名证书3. 动手部署一份可直接抄的 compose 配置3.1 安装 Docker 与 compose 插件系统自带的软件源里 Docker 版本往往偏旧我一般走官方仓库。这里不写具体源地址你搜docker 官方安装文档按发行版照做即可步骤就是加源、更新索引、装docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin这几个包。装完验证一下版本docker compose version能输出版本号说明插件已经就位注意是docker compose中间带空格不是老版本的docker-compose。接着把当前用户加进 docker 组usermod -aG docker $USER重新登录一次生效。如果拉镜像速度慢配置一个镜像加速地址会有明显改善这部分按你所在环境的实际情况处理就行。注意给普通用户加 docker 组等价于给了它 root 级别的权限这是 Docker 的固有设计。机器只有你自己用无所谓多人共用的服务器上要谨慎。3.2 编写 docker-compose.yml在/opt/nextcloud下建一个docker-compose.yml内容如下。我把所有需要你改的地方都用中文标注了替换掉再执行。services: db: image: mariadb:10.11 container_name: nc-db restart: always command: - --transaction-isolationREAD-COMMITTED - --binlog-formatROW - --innodb-buffer-pool-size256M volumes: - ./db:/var/lib/mysql environment: - MYSQL_ROOT_PASSWORD换成根口令 - MYSQL_PASSWORD换成应用口令 - MYSQL_DATABASEnextcloud - MYSQL_USERnextcloud networks: - backend redis: image: redis:7-alpine container_name: nc-redis restart: always command: redis-server --requirepass 换成缓存口令 --maxmemory 128mb --maxmemory-policy allkeys-lru volumes: - ./redis:/data networks: - backend app: image: nextcloud:28-apache container_name: nc-app restart: always ports: - 127.0.0.1:8080:80 volumes: - ./app:/var/www/html - ./data:/var/www/html/data - ./php/custom.ini:/usr/local/etc/php/conf.d/zz-custom.ini:ro environment: - MYSQL_HOSTdb - MYSQL_DATABASEnextcloud - MYSQL_USERnextcloud - MYSQL_PASSWORD换成应用口令 - REDIS_HOSTredis - REDIS_HOST_PASSWORD换成缓存口令 - NEXTCLOUD_TRUSTED_DOMAINScloud.example.com 192.168.1.10 - OVERWRITEPROTOCOLhttps - OVERWRITECLIURLhttps://cloud.example.com - PHP_MEMORY_LIMIT512M depends_on: - db - redis networks: - backend networks: backend: driver: bridge几个关键点说明一下。ports我写的是127.0.0.1:8080:80只绑本机回环外部访问一律走后面的转发层。这样即使防火墙配错Nextcloud 也不会直接暴露在公网上等于多了一道保险。如果你暂时只想在局域网里用把它改成8080:80就能用http://内网IP:8080打开了。NEXTCLOUD_TRUSTED_DOMAINS里预置了域名和内网地址中间用空格分隔。这个参数的作用是白名单——不在名单里的 Host 头会被拒绝提示访问不被信任的域名。后面加域名、换 IP 都要回来改这里或者用occ命令动态加。php/custom.ini这个文件要提前建好memory_limit 512M upload_max_filesize 16G post_max_size 16G max_execution_time 3600 max_input_time 3600 output_buffering 0 opcache.enable 1 opcache.memory_consumption 128 opcache.interned_strings_buffer 16 opcache.max_accelerated_files 10000这几个数字不是拍脑袋来的。upload_max_filesize和post_max_size必须一致或者后者略大否则大文件会被 PHP 直接拒掉而且报错信息很含糊。max_execution_time给到 3600 是为了让大文件上传不被中途掐断——一个 10GB 的文件在慢速网络下传一两个小时很正常。output_buffering 0是 Nextcloud 官方推荐的设置避免输出缓冲影响进度提示。3.3 首次启动与初始化向导目录和配置都就位之后一条命令起来cd /opt/nextcloud docker compose up -d docker compose ps docker compose logs -f applogs里看到 Apache/2.4.x ... configured -- resuming normal operations 就说明 Web 服务起来了。第一次启动会比较慢因为镜像要初始化app目录把所有程序文件铺进去一分钟左右很正常。浏览器打开http://服务器地址:8080会进安装向导。这里有三个地方要注意第一管理员账号名别用admin。这是被自动化工具扫得最多的用户名换成你自己的。密码用长一点的反正只在登录时输一次。第二数据目录保持默认。因为我们已经把/var/www/html/data单独挂载出来了这里写的路径实际上就落在宿主机的/opt/nextcloud/data不用改。第三数据库类型选 MySQL/MariaDB主机填db就是 compose 里的服务名库名、用户名、密码跟环境变量里的一致。如果你在这一步填错向导会报错并让你重填不会写坏数据。向导跑完会跳转到登录页。进去之后第一件事是到设置 → 概览看一眼有没有黄色警告通常会有两条一条是 PHP 内存建议值、一条是数据库的innodb参数建议按提示微调就行。3.4 用 occ 命令收尾occ是 Nextcloud 的命令行工具容器里跑的时候一定要带-u www-data否则生成的文件属主会变成 root后面 Apache 读写不了症状是某些页面莫名其妙报 500。docker compose exec -u www-data app php occ status docker compose exec -u www-data app php occ config:system:set trusted_domains 2 --valuecloud.example.com docker compose exec -u www-data app php occ config:system:set overwriteprotocol --valuehttps docker compose exec -u www-data app php occ config:system:set overwrite.cli.url --valuehttps://cloud.example.com docker compose exec -u www-data app php occ db:add-missing-indices docker compose exec -u www-data app php occ maintenance:repairdb:add-missing-indices是个很实用的命令能补上数据库缺失的索引对文件列表加载速度有肉眼可见的提升而且它经常在新版本升级后被官方提示要执行。maintenance:repair会修复一些内部的元数据不一致装完之后跑一次没坏处。4. 让服务能被公网访问的几条路径4.1 先判断自己手里到底有没有公网地址这一步非常关键很多人卡住就是因为默认自己有公网 IP其实没有。最简单的判断方法在服务器上执行curl -s https://ipv4.icanhazip.com拿到的是出口地址再去路由器管理页面看 WAN 口地址。两个地址如果一致说明你是直接拨号、拿到了公网地址如果不一致说明中间还有一层运营商的地址转换端口映射是无效的。还有一种情况两个地址一致但地址落在100.64.0.0/10这个段里。这不是公网地址是运营商内部共享用的地址段同样映射不通。这种时候正确的做法是打客服电话申请公网地址说明用途是家里装监控或者自建服务通常都能办下来有些地区免费有些需要办个基础套餐。IPv6 是另一条路。现在多数地区的家宽都已经下发了 IPv6 地址在服务器上ip -6 addr如果能看到2408、240e之类开头的公网地址并且能 ping 通外部的 IPv6 地址那你其实已经拥有公网可达的地址了完全不需要折腾端口映射。缺点是 IPv6 的可达性取决于访问方是否支持手机流量一般没问题某些公司网络和老旧设备就不行。4.2 方案 A直接部署在云服务器上这是最省心的一条路。云服务器天生带公网地址只要在控制台的安全组里放行 80 和 443 端口再把域名解析过去就完事了。你不需要处理任何网络地址转换的问题也不用担心运营商那边的限制。代价是磁盘和流量要花钱。我的做法是把不常用的大文件留在家里的机器上云上只放工作文档和照片的近期备份用 Nextcloud 的外部存储功能把两边挂到一起用起来跟一个盘差不多。注意用外部存储的时候挂载的是远程的 WebDAV 或者另一台机器的共享目录配置在设置 → 外部存储里需要装对应的插件。安全组配置有个原则只开放必要的端口。80 和 443 之外SSH 端口要么限制来源 IP要么换成非默认端口别把 22 大方地开着。4.3 方案 B家里机器 路由器端口映射 动态域名有公网地址的情况下在家里的路由器上把外部的 443 转发到内网服务器的 443 就行。这里有个细节既然要转发到 443那宿主机的 HTTPS 就得由转发层来处理Nextcloud 容器本身还是跑在 8080 上外面用 Nginx 收 HTTPS 再转进去链路是公网 → 路由器 → 宿主机 Nginx:443 → 容器:8080。家用宽带拿到的公网地址一般会变重启光猫就换一个所以需要动态域名解析DDNS。两条路一是路由器自带 DDNS 功能在管理页面里找找很多型号都有二是自己在服务器上写个小脚本定时拿当前地址去调域名服务商的接口更新 A 记录。后者的原理很简单一个curl请求加一个 cron 就够关键是记得把接口密钥放在只有自己能读的文件里别硬编码在脚本里。注意家用宽带的 80 和 443 端口在部分地区是被封的用来做网站访问会失败。遇到这种情况可以把外部端口换成 8443 之类的访问时带上端口号。证书签发也会受影响需要用 DNS 验证方式而不是 HTTP 验证。4.4 方案 CIPv6 直连 AAAA 记录我目前主力用的就是这个。服务器拿到 IPv6 公网地址之后在域名服务商那里加一条 AAAA 记录指向它客户端解析到 AAAA 就直接连过来了中间不经过任何转换环节。速度上比端口映射的方案还快一点因为没有额外的转发。要处理的问题有三个。一是防火墙宿主机的防火墙和路由器的 IPv6 防火墙都要放行对应端口很多人只改了前者结果一直连不上。二是地址会变IPv6 的地址前缀在运营商侧调整时会变所以同样需要 DDNS 机制只是把 A 记录换成 AAAA 记录。三是隐私扩展有些系统开启了临时地址ip -6 addr会看到一堆地址得用ip -6 addr show scope global找出那个持久的。还有个坑部分客户端在双栈环境下会优先尝试 IPv4如果你的域名同时有 A 和 AAAA 记录但 IPv4 那条是不通的浏览器会先卡几秒再回退到 IPv6体验很差。所以要么只留 AAAA要么确保两条路都通。4.5 HTTPS证书签发与自动续期不管走哪条方案HTTPS 都必须上。一方面是明文传输密码和文件不可接受另一方面 Nextcloud 的很多功能比如客户端同步、WebDAV 挂载在非 HTTPS 下会被客户端拒绝。用 ACME 协议的免费证书就够。以 HTTP 验证方式为例先确保你的域名已经解析到这台机器、且外部能访问到 80 端口然后apt install certbot mkdir -p /var/www/letsencrypt certbot certonly --webroot -w /var/www/letsencrypt -d cloud.example.com证书会落在/etc/letsencrypt/live/cloud.example.com/下面fullchain.pem是证书链、privkey.pem是私钥。续期是自动的certbot 装的时候会注册一个定时任务但续期之后必须重新加载 Nginx否则它还在用内存里的旧证书。加一个钩子文件就解决了在续期配置目录里放一个脚本内容是systemctl reload nginx之后每次续期成功都会自动重载。这个细节很多人漏掉结果三个月后证书过期客户端全部报错。验证续期是否正常用certbot renew --dry-run跑一次演练看到 Congratulations, all simulated renewals succeeded 就放心了。4.6 Nginx 转发层的完整配置前面说的转发层就是 Nginx它负责收 HTTPS、把请求转给容器。配置文件放在/etc/nginx/conf.d/nextcloud.confserver { listen 80; server_name cloud.example.com; location /.well-known/acme-challenge/ { root /var/www/letsencrypt; } location / { return 301 https://$host$request_uri; } } server { listen 443 ssl; http2 on; server_name cloud.example.com; ssl_certificate /etc/letsencrypt/live/cloud.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/cloud.example.com/privkey.pem; ssl_protocols TLSv1.2 TLSv1.3; ssl_session_cache shared:SSL:10m; client_max_body_size 16G; client_body_timeout 3600s; location / { proxy_pass http://127.0.0.1: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_request_buffering off; proxy_read_timeout 3600s; proxy_send_timeout 3600s; } location /.well-known/carddav { return 301 https://$host/remote.php/dav; } location /.well-known/caldav { return 301 https://$host/remote.php/dav; } }几个参数值得单独解释。client_max_body_size 16G必须跟 PHP 那边的upload_max_filesize对上这是最常见的大文件传一半就失败的根因。proxy_request_buffering off是让请求体直接流进去而不是先缓存在 Nginx 的临时目录里——对于大文件上传开启缓冲会先把整个文件写到磁盘再转发既慢又占空间。proxy_read_timeout 3600s是给长时间的上传下载留出余量。/.well-known/carddav和/.well-known/caldav这两条重定向是给日历和通讯录同步用的手机客户端配置账号时会自动去探测这两个路径没有它们就得手动填完整地址用户体验差很多。配完nginx -t检查语法然后systemctl reload nginx。此时访问https://cloud.example.com应该能正常打开登录页了。5. 常见问题与排查实录5.1 页面提示访问不被信任的域名这是最高频的问题几乎每个人都会遇到一次。原因是请求头里的 Host 不在trusted_domains白名单里。解决办法有两个临时用occ加一条docker compose exec -u www-data app php occ config:system:set trusted_domains 3 --value新域名或者直接改app/config/config.php里的trusted_domains数组改完重启容器。我习惯用occ因为数组索引写错不会把整个配置文件搞坏。还有个子情况如果你在转发层之外又套了一层比如云厂商的负载均衡那 Nextcloud 看到的 Host 可能是内网地址这时候除了加白名单还要确认转发层有没有把Host头透传过来。5.2 大文件上传失败或者卡在某个百分比排查顺序按这个来先看 Nginx 的client_max_body_size再看 PHP 的upload_max_filesize和post_max_size这两个必须同时改最后看容器的磁盘空间和 inode。日志位置分别是/var/log/nginx/error.log和容器里/var/www/html/data/nextcloud.log。还有个隐蔽的原因反向转发如果开了请求缓冲会在/var/lib/nginx/body下面生成临时文件那个分区如果只有几 GB传大文件必然失败。proxy_request_buffering off就是解决这个的同时检查nginx.conf里client_body_temp_path指向的目录所在分区有多大。5.3 安装向导走完白屏或者报 500九成是目录属主问题。执行ls -ln /opt/nextcloud/app | head看一眼如果是 root 或者 1000改成 33chown -R 33:33 /opt/nextcloud/app /opt/nextcloud/data改完重启容器。如果还不行去看容器的 Apache 错误日志docker compose logs app | tail -50日志里出现 Permission denied 后面跟着具体路径就针对那个路径单独处理。有时候是app/config目录被写坏了可以把它清空让容器重新生成记得先备份config.php。5.4 手机客户端同步卡住或者反复重连先确认域名在手机上能打开网页版。如果网页能开、客户端连不上通常是证书问题——客户端对证书链的校验比浏览器严格浏览器会自动补全中间证书客户端不会。用openssl s_client -connect cloud.example.com:443 -showcerts看一下能不能拉出完整的链缺中间证书就把fullchain.pem换成完整的而不是只用cert.pem。如果客户端连上了但同步慢看看是不是在传大量小文件。这个问题跟文件数量强相关几十万个小文件挨个建索引性能会明显下降。可以考虑把一些老资料打包成压缩包存放或者开启服务端的批量处理参数。5.5 速度慢传不满带宽三个排查方向。一是转发层的缓冲区配置proxy_buffering off配合proxy_request_buffering off在处理大文件时更直接。二是磁盘 IO机械盘写大文件时会成为瓶颈iostat -x 1看一下%util是不是长期接近 100。三是 MTU 问题IPv6 隧道或者某些网络环境下 MTU 不是 1500会导致大包分片表现为小文件很快、大文件很慢ping -M do -s 1472 目标地址试探一下能找到合适的值。5.6 问题速查表现象大概率原因处理动作白屏 / 500挂载目录属主不是 33chown -R 33:33后重启访问不被信任的域名Host 不在白名单occ config:system:set trusted_domains大文件传一半失败三处体积限制没对齐改 Nginx 与 PHP 的 body/upload 上限证书过期告警续期后没重载 Nginx加续期钩子脚本重载服务数据库锁表用了 SQLite 或多端并发换 MariaDB 并检查READ-COMMITTED客户端连不上但浏览器正常证书链不完整用 fullchain 而非单证书同步慢小文件过多或磁盘 IO 打满合并小文件、换 SSD、看 iostat容器起不来端口被占用或目录权限docker compose logs定位具体报错6. 长期运行需要补的几件事6.1 备份别把鸡蛋放在一个挂载点上我见过太多人把容器跑起来就觉得万事大吉结果一次误删或者一次磁盘故障几年的照片全没了。备份这件事必须单独做而且要遵守三份数据、两种介质、一份异地的老规矩。数据库的备份要用mysqldump导出不能直接复制数据目录——InnoDB 里有未刷盘的脏页冷拷贝出来的文件可能不一致docker compose exec -T db mysqldump --single-transaction \ -unextcloud -p你的口令 nextcloud | gzip /backup/nc-db-$(date %F).sql.gz--single-transaction是必须的参数它保证导出的是一致的快照不会因为导出过程中有人写数据而出现半截状态。文件部分用rsync做增量比tar全量打包快得多也不占额外的临时空间rsync -a --delete /opt/nextcloud/data/ /backup/data/--delete要谨慎使用它会把目标端多余的文件删掉保持完全一致。如果目标端是你手动整理过的目录别加这个参数。异地那份我用的是另一块盘加一台老机器每周同步一次。容器里还有个occ命令可以辅助occ files:scan --all会在文件被外部改动后重建索引从备份恢复之后一定要跑一次否则文件在网页上看不见。6.2 升级节奏与回滚Nextcloud 的大版本升级有严格的路径要求不能跨大版本跳比如从 25 直接到 28 是不行的得 25→26→27→28 一步步来。所以我的策略是只锁大版本跟着官方镜像的小版本更新走一年做一次大版本跨越。升级前必做三件事备份数据库、备份app目录、记下当前镜像的完整 tag。升级过程就是改 compose 里的版本号然后docker compose up -d容器起来后会自动进入升级流程。如果卡住用occ upgrade手动触发。出问题要回滚把版本号改回去重启就行前提是app目录你备份了——因为升级过程会改config.php和数据库结构光改镜像版本号是不够的。这就是为什么app和data要分开data目录在升级中完全不受影响回滚的时候不用动它省了大量时间。6.3 安全加固清单跑在公网上的东西该做的基本功要做。我列一下自己在用的几条强制 HTTPS并且在 Nginx 里加上 HSTS 响应头让浏览器以后只用 HTTPS 访问关掉目录列表Nginx 里autoindex off定期清理data/nextcloud.log别让它无限增长同时留意里面的异常登录记录开启两步验证Nextcloud 内置了 TOTP 支持在设置里打开就行用occ security:routes可以查看所有暴露的路由定期看一眼有没有意外开放的接口容器不要用latest标签锁定具体版本号否则某天自动拉取新版本可能带来不兼容还有一个容易忽略的点限制容器能用的资源。在 compose 里给 app 服务加一段deploy.resources.limits限制 CPU 和内存上限防止某个异常请求把整台机器拖垮。这不是性能优化是防止雪崩的保险丝。6.4 参数配置对照表参数位置建议值说明memory_limitphp/custom.ini512M4GB 内存机器可给 1Gupload_max_filesizephp/custom.ini16G按实际需要调整post_max_sizephp/custom.ini16G必须大于等于上一条max_execution_timephp/custom.ini3600大文件上传需要client_max_body_sizeNginx16G与 PHP 侧保持一致proxy_read_timeoutNginx3600s长连接传输需要innodb-buffer-pool-sizeMariaDB 启动参数内存 1/42GB 机器给 256MmaxmemoryRedis 启动参数128mb缓存而已别给太多这套配置在我两台机器上分别跑了一年多和半年多期间遇到过证书续期失败、大文件超时、容器 OOM 三类问题都在上面的排查表里覆盖到了。真正需要长期盯的其实只有两件事磁盘空间和证书有效期把这两个做成定时提醒剩下的基本可以放着不管。如果后面想把分享链接做得好看一点可以在 Nextcloud 里配置自定义域名前缀想给家里人分账号就建几个普通用户并配置配额想在电视或者旧设备上访问WebDAV 那条路永远不会过时。这套东西的扩展方向很多但地基就是上面这些——目录分清楚、限制对齐、证书自动续其他的都是在这个基础上加东西。
阅读完成 · 觉得有帮助?
咨询建站