Docker 中 Nextcloud 的文件存储位置怎么查
了解 Nextcloud 数据目录在容器内的位置、Docker volume 对应的主机路径,以及备份所需的 5 项内容,而不只是用户文件。
Docker 中 Nextcloud 的文件存储位置
Docker 中的 Nextcloud 会将文件存储在容器内的数据目录中。服务器上的实际位置取决于您为该目录配置的 volume 或 bind mount。对于 linuxserver.io 镜像,lscr.io/linuxserver/nextcloud,用户文件位于 /data,Nextcloud 安装及其 config.php 位于 /config。这两个都是容器路径。一条命令可以显示它们对应的主机路径。本指南的其余部分将说明问题中更复杂的部分:数据目录不包含的所有内容。
固定镜像标签。路径属于镜像,而不是 Nextcloud;浮动标签可能会在您不知情的情况下指向新版本。截至 2026 年 8 月,该镜像当前的稳定标签是 34.0.3。
services:
nextcloud:
image: lscr.io/linuxserver/nextcloud:34.0.3
container_name: nextcloud
environment:
- PUID=1000
- PGID=1000
- TZ=Etc/UTC
volumes:
- nextcloud_config:/config
- nextcloud_data:/data
ports:
- 443:443
restart: unless-stopped
nextcloud-db:
image: mariadb:11.8
container_name: nextcloud-db
environment:
- MARIADB_ROOT_PASSWORD=${MARIADB_ROOT_PASSWORD}
- MARIADB_DATABASE=nextcloud
- MARIADB_USER=nextcloud
- MARIADB_PASSWORD=${NEXTCLOUD_DB_PASSWORD}
volumes:
- nextcloud_db:/var/lib/mysql
restart: unless-stopped
volumes:
nextcloud_config:
nextcloud_data:
nextcloud_db:这两个密码来自 compose 文件旁边的 .env 文件,因此不会直接写入 compose 文件。答案中共有 3 个 volume,其中只有 1 个存储用户文件。
这些容器路径来自该镜像的文档。其他 Nextcloud 镜像的文件系统布局可能不同,并会将安装文件放在自己的 Web 根目录下。因此,直接复制论坛帖子中的路径并不可靠。请从正在运行的容器中读取实际路径。
docker inspect nextcloud该输出的 Mounts 部分会列出所有挂载点,其中 Source 是主机端路径,Destination 是容器端路径。无论您选择了哪个镜像,这份列表都能给出当前配置中的实际路径。
如何查找卷背后的实际主机路径?
命名卷由 Docker 管理,因此您无需选择其路径。您只需查询即可。
docker volume ls
docker volume inspect nextcloud_nextcloud_data名称很重要。Docker Compose 会在卷名称前添加项目名称。默认情况下,项目名称是存放 compose 文件的目录名称。因此,文件中写为 nextcloud_data 的卷通常在磁盘上对应 nextcloud_nextcloud_data。docker volume ls 会显示实际名称。inspect 输出如下,内容已截短:
[
{
"CreatedAt": "2026-08-18T09:12:44Z",
"Driver": "local",
"Mountpoint": "/var/lib/docker/volumes/nextcloud_nextcloud_data/_data",
"Name": "nextcloud_nextcloud_data",
"Scope": "local"
}
]Mountpoint 就是所需路径。请从命令输出中读取该路径,不要假定它固定不变,因为路径可能会变化。对于 rootless Docker,整个 Docker 数据根目录位于运行 daemon 的用户主目录中,因此路径的起点会有所不同。
使用绑定挂载即可避免这个问题。在 compose 文件中写入 - /srv/nextcloud/data:/data,主机路径就是您填写的路径,docker inspect 会将其报告为 Source。这不仅会改变路径,因为命名卷和绑定挂载在所有权和备份方面的行为不同。
为什么数据目录不是备份
Nextcloud 手册列出了备份必须保留的 5 项内容:config 文件夹、custom apps 文件夹、data 文件夹、theme 文件夹和数据库。在此映像中,config、apps 和 theme 文件夹都位于 /config 下,而数据库运行在拥有独立卷的容器中。只复制 /data,实际上只保存了问题中最不重要的部分。
数据库很重要,因为 Web 界面从不直接列出目录,而是列出文件缓存中的记录。因此,手册要求在手动将文件复制到 data 目录后运行扫描。将 /data 恢复到空数据库旁边,得到的只是没有索引的字节:没有用户、没有共享,也没有文件列表中的任何内容。将数据库恢复到空的 /data 旁边,则每条记录都指向已经不存在的文件。
config.php 保存数据库凭据和受信任域名,也保存实例 ID。实例 ID 是 data 目录中应用数据文件夹的名称。应从正在运行的实例中查询这些值,不要依赖记忆中的值。
docker exec -it nextcloud occ config:system:get datadirectory
docker exec -it nextcloud occ config:system:get instanceid第一条命令会输出此实例实际使用的数据目录,这里是 /data。此映像在 PATH 中提供了一个 occ 包装器,因此应直接通过 docker exec 运行它。不要照搬 Nextcloud 手册中的较长 sudo 和 php occ 形式,因为该形式适用于容器外部的安装。
什么在悄悄占满数据卷?
预览文件和每个用户的历史版本与文件存放在同一个卷中,但用户在 Web 界面中看到的存储用量不会包含这两类数据。
- 预览文件是生成的缩略图。它们位于数据目录中的应用数据文件夹内,名称以
appdata_开头,后面接实例 ID。 - 删除的文件会保留在回收站中。
trashbin_retention_obligation默认设置为auto,文件会保留 30 天,只有在需要释放空间时才会被删除。删除的文件仍会计入用户配额。超过配额后,系统会忽略保留设置,持续清理回收站,直到用量重新符合配额。 - 旧版本也会保留。
versions_retention_obligation默认设置为auto。Versions 应用最多使用用户当前可用空间的 50%。清理时会先删除最旧的版本,同时保留最近的两个版本。用户手动命名的版本不会被删除。
删除任何内容前,先进行测量。
docker exec -it nextcloud sh -c 'du -sh /data/*'
docker exec -it nextcloud sh -c 'du -sh /data/appdata_*'第一行会分别显示每个用户文件夹和应用数据文件夹的一个数值。如果应用数据的数值很大,原因就是预览文件。下面的清理命令已有文档说明,并且每条命令都会有意删除数据。
docker exec -it nextcloud occ trashbin:cleanup --all-users
docker exec -it nextcloud occ versions:cleanup alice
docker exec -it nextcloud occ preview:cleanuppreview:cleanup 会删除所有已生成的预览文件。用户打开这些文件时,Nextcloud 会重新生成预览,因此空间占用会逐步恢复,同时增加 CPU 负载。如果该卷只是更大范围磁盘问题的一部分,旧镜像和过期的构建缓存 通常是另一个原因。
为什么我复制到主机上的文件没有出现在 Nextcloud 中?
因为 Nextcloud 从数据库读取文件缓存,而不是直接读取目录。复制操作只在磁盘上创建了文件,但没有创建对应的数据库记录,因此 Web 界面没有可列出的内容。手册明确说明了这一情况:直接将文件复制到数据目录后,必须执行扫描。
docker exec -it nextcloud occ files:scan --path="/alice/files/Photos"
docker exec -it nextcloud occ files:scan --unscanned -v
docker exec -it nextcloud occ files:scan --all--path 参数还展示了数据目录的布局:每个用户都有一个以用户名命名的目录,其中的 files 保存该用户在 Web 界面中看到的内容。知道文件所在位置时,可以只扫描一个路径。--all 会遍历所有用户,在大型实例上可能需要很长时间。--unscanned 只处理标记为尚未完全扫描的文件。-v 会在处理文件时逐个输出文件名,因此可以区分命令确实卡住和命令正在运行但没有输出。
文件所有权决定扫描是否足够。容器用户无法写入的文件可以被编入索引,但之后无法移动,因此列表看起来正确,而从 Web 界面重命名或删除文件时会失败。
设置 PUID 和 PGID 后,为什么写入仍会失败?
因为内核比较的是数字,而不是名称。PUID 和 PGID 设置容器进程运行时使用的数字用户 ID(uid)和组 ID(gid)。主机上的每个文件也都有数字所有者。两个数字不一致时,写入会被拒绝,无论两端显示的名称是什么。
docker exec -it nextcloud id abc
sudo ls -ln /var/lib/docker/volumes/nextcloud_nextcloud_data/_dataid abc会输出容器实际使用的 uid 和 gid,也就是你设置的 PUID 和 PGID。ls -ln会输出数字所有者,而 -n 很重要:普通的 ls -l 会通过主机自己的用户列表将这些数字转换为名称,但该名称在容器内没有意义。请比较这两个数字。
然后直接测试写入,不要靠猜测。
docker exec -u abc -it nextcloud touch /data/writetest名为 /data 的 Permission denied 是确认结果。先在容器内修复所有权,再运行同样的测试。
docker exec -u 0 -it nextcloud chown -R abc:abc /data
docker exec -u abc -it nextcloud touch /data/writetest
docker exec -u abc -it nextcloud rm /data/writetest之所以要在容器内执行,是因为 rootless Docker 会通过 /etc/subuid 中的 subordinate 范围映射容器的用户 ID。因此,容器内的 uid 1000 会对应主机上高得多的 uid。在主机上执行 chown 1000:1000 会设置一个容器无法使用的所有者,写入仍会失败。在容器内运行 chown 时,会使用与 Nextcloud 进程相同的映射,因此这些数字会自然对应。这也是为什么在排查其他问题前,必须先确保 PUID 和 PGID 与磁盘上的所有者一致。
如何备份,才能确保恢复成功?
在同一时间点获取数据库和目录。维护模式会阻止登录,因此从导出数据库到复制文件期间不会有上传写入。
docker exec -it nextcloud occ maintenance:mode --on
docker exec nextcloud-db mariadb-dump --single-transaction -u nextcloud -p"$NEXTCLOUD_DB_PASSWORD" nextcloud > nextcloud-sqlbkp.sql
docker run --rm -v nextcloud_nextcloud_data:/data:ro -v "$PWD":/backup alpine:3.22 tar czf /backup/nextcloud-data.tgz -C /data .
docker run --rm -v nextcloud_nextcloud_config:/config:ro -v "$PWD":/backup alpine:3.22 tar czf /backup/nextcloud-config.tgz -C /config .
docker exec -it nextcloud occ maintenance:mode --off注意导出命令中没有什么:没有 -t 标志。TTY 会改写行尾,SQL 导出文件一旦经过 TTY,就会损坏,而且只有在恢复时才会发现。还要注意,命令运行期间,命令行中的密码会显示在 ps 输出中。因此,应从 .env 文件读取密码并传递给 shell,而不是直接输入。较旧的数据库镜像使用 mysqldump,而不是 mariadb-dump;手册对两者都有说明。
恢复时,将导出文件加载到空数据库中,将两个归档解压到新的卷中,启动容器,然后关闭维护模式。如果目录和导出文件来自不同时间点,文件缓存与磁盘状态就会不一致,而 occ files:scan --all 只能单向修复。它可以找到存在但没有对应数据库行的文件,但无法恢复数据库行所指向的文件。
将恢复结果存放在服务器之外。位于同一 VPS 内的副本会随 VPS 一起丢失。因此,使用 restic 备份到服务器外的存储库应纳入此流程;提供商快照与备份是不同的工具也是如此。如果仍在搭建此环境,在 VPS 上完整安装 Nextcloud会介绍反向代理和 TLS(传输层安全)证书配置,本指南不涵盖这些内容。
FAQ
Nextcloud 数据目录在 Docker 容器中的什么位置?
使用 linuxserver.io 镜像时,数据目录在容器内的 /data,使用 config.php 安装时则位于 /config。这些都是容器路径。要获取主机路径,请运行 docker inspect nextcloud,然后读取 Mounts 部分中的 Source 值;或者对该卷运行 docker volume inspect,然后读取 Mountpoint。其他 Nextcloud 镜像使用不同的容器路径,因此请查看所固定 tag 的文档,并使用 docker exec -it nextcloud occ config:system:get datadirectory 进行确认。
为什么复制到卷中的文件不会显示在 Nextcloud 中?
Nextcloud 从数据库中的文件缓存读取文件列表,而不是直接读取目录。因此,未经过 Nextcloud 写入的文件没有对应记录,会保持不可见。对单个目录运行 docker exec -it nextcloud occ files:scan --path="/alice/files/Photos",或对所有用户运行 occ files:scan --all。如果文件能够显示,但随后无法移动或删除,原因是所有权不正确:容器用户必须拥有写入这些文件的权限。
只复制数据卷是否足以恢复 Nextcloud?
不够。数据卷保存文件内容。数据库保存文件索引、用户和共享信息,config.php 保存数据库凭据和实例 ID。要成功恢复,需要数据目录、配置目录、数据库,以及自定义应用和主题目录(如果使用)。必须从同一时刻获取这些内容,因为数据库比文件更新时,可能会指向不存在的文件。
为什么我的数据卷比用户看到的文件大很多?
预览、已删除文件和旧版本都保存在同一个卷中,但用户看到的容量统计不会包含这些内容。使用 docker exec -it nextcloud sh -c 'du -sh /data/*' 进行测量。回收站默认保留已删除文件 30 days,只有在需要空间时才会提前清理;Versions 应用最多可使用用户当前可用空间的一半。使用 occ trashbin:cleanup --all-users、occ versions:cleanup alice 和 occ preview:cleanup 清理这些内容,并预期预览会随着用户打开文件而重新增长。
可以将 Nextcloud 数据目录移动到另一块磁盘吗?
将新位置挂载到相同的容器路径,不要修改 Nextcloud 已知的路径。停止容器,在保留所有权的情况下使用 cp -a 或 rsync -aAX 将旧内容复制到新磁盘,然后在 compose 文件中将卷或 bind mount 指向新位置,最后重新启动容器。Nextcloud 仍会看到 /data,因此无需修改数据库中的记录。使用 docker exec -it nextcloud occ config:system:get datadirectory 和一次测试上传进行验证。