Copyparty 轻量文件共享:Docker Compose 部署、权限与多协议使用全指南

手机要给电脑传一个大文件,Linux 服务器要临时分发维护包,NAS 想让家人用浏览器下载资料------这些场景常常只需要一个文件入口。Copyparty 把 Web 文件管理、HTTP 传输和 WebDAV 放在同一套目录权限下,也能按需启用 FTP、TFTP 等服务。

它不要求客户端安装专用软件:浏览器打开就能列目录、拖拽上传、点击下载;需要挂载或脚本同步时,再走 WebDAV 或 rclone。所有文件最终落在宿主机映射目录,容器可以随时重建,数据仍然保留。

本文以官方 copyparty/min:1.20.25 为主线,只启用经过身份认证的 HTTP/WebDAV,单独介绍 FTP 和设备固件分发所需的 TFTP。

适用场景与选型

Copyparty 是 Python 实现的文件服务器,主体使用 MIT 授权。它提供浏览器文件列表、上传下载及按目录授权;部署容器时,普通文件直接保存在映射的宿主机目录。启用文件索引后会使用 SQLite 元数据,但不要求额外启动数据库容器。

它的核心思路是"一个进程、一套配置、多个协议入口":HTTP/WebDAV 共用同一个监听端口和同一份账号权限,FTP、TFTP 等协议在需要时再单独开启,并复用相同的目录授权规则。因此不必为每种协议维护独立的用户体系,也不会出现"浏览器能看、FTP 看不到"的权限割裂。

对使用者而言,最直观的收益是零客户端门槛:手机、平板、办公电脑只要打开浏览器就能传文件;对运维而言,收益是部署简单------一个容器、两个目录(配置与数据)即可起步,后续扩展协议也只是在配置文件里增加几行参数。 相比传统 FTP 服务,它增加了无需专用客户端的 Web 入口;相比 Samba 或 NFS,它首先是文件传输与 Web 访问服务,并非系统网络文件系统的通用替代品。它可以补充 NAS 的外部文件入口,但不能代替磁盘管理、RAID、快照和备份。

换句话说,Copyparty 解决的是"如何把某个目录安全、方便地暴露给人和脚本",而不是"如何把远程存储挂载成本地磁盘"。如果需求是让应用程序像访问本地路径一样读写远端文件,或者依赖文件锁、字节范围锁等语义,仍应选择 SMB/NFS 这类网络文件系统;如果只是临时传文件、给家人下载资料、给脚本提供上传接口,Copyparty 的轻量形态更合适。

图 0:浏览器和 WebDAV 共用主方案端口与权限;FTP 是单独启用的访问路径,所有文件落在宿主机共享目录。

方案 更适合的工作 选型时重点考虑
Copyparty 浏览器传文件、临时共享、轻量目录授权、WebDAV 镜像可选依赖与协议的端口边界
SFTPGo 以 SFTP 为核心的文件传输和账户管理 后端存储、认证、配额等需求与维护成本
Samba Windows 网络共享与 SMB 客户端生态 系统用户、ACL、SMB 安全配置
NFS Unix/Linux 的网络文件系统挂载 导出范围、客户端身份和网络边界
File Browser 类工具 主要通过浏览器管理文件 具体项目的权限与认证设计

适用情形包括局域网临时传输、Windows/Linux 文件交换、电脑与手机共享、维护包分发和多用户共享目录。需要真正的 SMB/NFS 挂载、文件锁语义、企业级身份流程或硬件存储管理时,应先评估对应的专用系统。不能仅凭镜像大小判断空闲内存或传输速度。

选型时可以按三个问题快速判断:第一,客户端是否愿意安装专用软件?如果希望"打开浏览器就能用",Copyparty 更省事。第二,是否需要系统级挂载?如果需要把远端目录当作本地盘符或挂载点使用,应选 SMB/NFS。第三,权限模型是否足够简单?如果只是"谁能读、谁能写、谁能删"的目录级授权,Copyparty 的配置足够直观;若需要对接 LDAP、细粒度 ACL 或审计合规,则要评估更完整的方案。

镜像与协议支持边界

官方镜像怎么选

镜像 主要组件与用途 与本文有关的限制
copyparty/min Copyparty、基础模板依赖;内含 FTP/TFTP 模块 无 Pillow、FFmpeg、Paramiko、PyOpenSSL、Argon2、Impacket;入口显式禁用缩略图
copyparty/im Pillow、Mutagen,另含 Paramiko、PyOpenSSL、Argon2 可用于需要 SFTP/FTPS 的扩展;不包含完整 FFmpeg 媒体处理能力
copyparty/ac 图像与音视频处理,含 FFmpeg 官方通用推荐,但本文不需要这些媒体组件
copyparty/iv 在媒体能力上增加 libvips 等图像组件 更复杂的图像处理需求才值得考虑
copyparty/dj 增加音乐节拍/调性分析组件 普通文件传输无需引入

协议支持矩

FTP 是 File Transfer Protocol,FTPS 是 FTP 加 TLS,SFTP 是 SSH File Transfer Protocol;三个名称相近,但连接机制不同。WebDAV 是基于 HTTP 的文件管理扩展,不能当作 SMB。TFTP 是 Trivial File Transfer Protocol,使用 UDP,没有 FTP 的账号机制。

协议 项目实现/依赖 min:1.20.25 能否直接启用 端口与启用条件 安全与用途 难度/注意事项
HTTP 内置 是;主方案已启用 默认 TCP 3923 明文;受控内网或代理后端 简单;认证不能弥补传输明文
HTTPS Python TLS 能接受 TLS;需合格证书;本文由代理实现 可共用 3923;不是另开默认 443 TLS;浏览器与 WebDAV 外部入口 中等;不能依赖打包的示例证书
WebDAV HTTP 内置实现 是;主方案已启用 与 HTTP/HTTPS 共用 安全取决于 HTTP 是否加 TLS 简单;覆盖修改有额外权限条件
FTP 内含 pyftpdlib 是;默认关闭 ftp: 3921,另设被动数据端口 明文;受控 LAN 或 VPN 内 中等;控制端口与数据端口都要处理
FTPS pyftpdlib + PyOpenSSL 否;缺 PyOpenSSL ftps: 3990 示例,显式 TLS,另有数据端口 TLS;兼容客户端 较复杂;可改用 im,证书独立部署
SFTP Paramiko 否;缺 Paramiko sftp: 3922 示例;默认关闭 SSH;优先公钥认证 中等;可改用 im,保持主机密钥
TFTP 内含 partftpy 是;默认关闭 tftp: 3969 + UDP 数据端口范围;客户端常用 69 无认证无加密;隔离固件分发 中等;只给专用目录匿名读权限
SMB/CIFS Impacket 否;官方镜像未预装该依赖 项目参数默认 TCP 445;不是自动启用 官方警告严重安全问题 高;1.20.25 还需危险功能开关;本文不推荐
NFS 没有 NFS 服务端实现 否 无服务端监听参数 使用独立 NFS 服务 独立部署;挂载 NFS 存储不等于提供 NFS

集中完成主方案部署

环境与目录

准备支持所选架构的 Linux 系统、Docker Engine、Compose Plugin 和一个有足够空间的存储目录。以下是 Bash 命令

bash 复制代码
docker version
docker compose version
id
df -h

mkdir -p "$HOME/copyparty/config" "$HOME/copyparty/data"
cd "$HOME/copyparty"

最终布局:

text 复制代码
copyparty/
├── compose.yaml
├── .env
├── config/
│   ├── copyparty.conf
│   └── hists/           # 服务启动后生成的索引元数据
└── data/                # 共享文件

图 1:共享文件与配置、索引分别持久化;容器可以重建,宿主机目录必须保留。

Compose 与环境变量

创建 compose.yaml,内容与交付文件一致:

yaml 复制代码
services:
  copyparty:
    image: copyparty/min:1.20.25
    container_name: copyparty-files
    user: "${CP_UID:-1000}:${CP_GID:-1000}"
    restart: "no"
    ports:
      - "${CP_BIND_IP:-127.0.0.1}:3923:3923"
    volumes:
      - ./config:/cfg
      - ./data:/w
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"

创建 .env。下面的 1000 必须与准备好的目录属主对应;没有使用所谓 PUID/PGID 镜像环境变量,而是由 Compose 的 user: 设置实际进程身份。

dotenv 复制代码
CP_BIND_IP=127.0.0.1
CP_UID=1000
CP_GID=1000

默认回环绑定适合宿主机上的反向代理,或本机测试。需要局域网直接访问时,把 CP_BIND_IP 改成宿主机真实的 LAN 接口地址,再重建容器。 不要照抄不存在的 IP,也不必为了 LAN 访问开放到所有接口。若代理本身在另一个容器里,应使用两者共享的 Docker 网络,并让代理访问 copyparty:3923;代理容器里的 127.0.0.1 指向代理自身。

账号与共享目录配置

创建 config/copyparty.conf,并把所有示例密码替换为彼此不同的长随机密码。配置文件中的密码不会被 Compose 的 .env 自动替换。

ini 复制代码
[global]
  p: 3923
  i: 0.0.0.0
  http-only
  usernames
  dav-auth
  e2dsa
  hist: /cfg/hists/
  unpost: 0
  ftp-no-ow

[accounts]
  owner: CHANGE_ME_OWNER_USE_A_LONG_RANDOM_PASSWORD
  uploader: CHANGE_ME_UPLOADER_USE_A_DIFFERENT_PASSWORD
  reader: CHANGE_ME_READER_USE_A_DIFFERENT_PASSWORD

[/files]
  /w
  accs:
    rwmda: owner
    rw: uploader
    r: reader

这不是 YAML;使用 Copyparty 自己的区段和缩进语法,不要加 YAML 文档头。[global] 对应服务参数,[accounts] 定义账号,[/files] 把容器内 /w 发布为 URL /files/。官方配置示例。

http-only 明确让后端走 HTTP。usernames 要求用户名与密码一起认证;浏览器登录也输入完整的 用户名:密码。dav-auth 强制 WebDAV 认证。e2dsa 开启文件索引与启动扫描,但没有启用音视频标签扫描。hist 把索引状态放入持久化的 /cfg/hists/。unpost: 0 关闭上传后撤回窗口;否则仅去掉删除权限,并不能直接断言上传者无法撤回近期上传。ftp-no-ow 预先约束将来启用 FTP 时的同名覆盖,当前并不会启动 FTP。

权限字符 含义 本文分配
r 列目录、下载 三类账号都有
w 上传;不自动包含管理操作 owner、uploader
m 移动/重命名;目标还需写权限 owner
d 删除文件/目录;永久操作 owner
a 查看上传者 IP、配置重载等管理能力 owner

a 不会自动赋予其他权限,也不等于宿主机 root。匿名账号通常以 * 表示,这里没有给它任何卷权限。A 则是包含隐藏文件权限的综合权限,本文没有使用它。授权实现。

图 2:同一个目录按账号分别授权;应用权限还要受到 Linux 文件系统权限约束。

设置宿主机权限并启动

以下只对本次新建目录设置属主,不要随手对已有 NAS 资料做递归 chown:

bash 复制代码
sudo chown 1000:1000 config data
chmod 750 config data
sudo chown 1000:1000 config/copyparty.conf
chmod 600 config/copyparty.conf
chmod 600 .env
ls -ldn config data
ls -ln config/copyparty.conf

docker compose config --quiet
docker compose pull
docker compose up -d
docker compose ps
docker compose logs --tail=100 copyparty

如果实际 UID/GID 不是 1000:1000,同时修改上面的命令与 .env。父目录也必须允许路径遍历。SELinux 主机还要使用合适的标签,如官方示例的 :z,并评估共享标签范围;不要用 chmod -R 777 代替定位问题。

先检查日志确认 /files 的来源是 /w,权限与配置一致,再允许客户端接入。 docker compose config 只验证 Compose 展开与结构,不验证 Copyparty 配置语义;后者需要启动日志和功能测试。主方案没有盲目添加健康检查,ps 显示运行也不代表每个账号或协议可用。Docker 启动就绪说明。

上传、下载与持久化验收

回环模式在宿主机访问 http://127.0.0.1:3923/files/;LAN 模式用 http://服务器LAN地址:3923/files/。这条 HTTP 地址适合受控测试,长期使用参见 HTTPS 章节。

Linux 上准备测试文件,用 uploader 上传、reader 下载,curl 会提示输入密码,不把密码放在命令行:

bash 复制代码
printf 'copyparty test\n' > /tmp/cp-probe.txt
curl --fail --user uploader -T /tmp/cp-probe.txt \
  http://127.0.0.1:3923/files/cp-probe.txt
curl --fail --user reader \
  http://127.0.0.1:3923/files/cp-probe.txt -o /tmp/cp-downloaded.txt
sha256sum /tmp/cp-probe.txt /tmp/cp-downloaded.txt
ls -l data/cp-probe.txt
docker compose up -d --force-recreate
curl --fail --user reader \
  http://127.0.0.1:3923/files/cp-probe.txt -o /tmp/cp-after-recreate.txt
sha256sum /tmp/cp-probe.txt /tmp/cp-after-recreate.txt

三份文件哈希应一致,宿主机文件应存在。再用 reader 尝试上传、用 uploader 尝试删除;预期拒绝。匿名下载或 WebDAV 请求也应拒绝。不要用 curl --fail 对"预期拒绝"下结论为服务故障,应查看 HTTP 状态和实际权限。完成测试后由 owner 清理测试文件。

浏览器与 WebDAV 使用

Web 文件管理

打开 /files/ 后,在控制面板的登录入口输入 owner:你的密码、uploader:你的密码 或 reader:你的密码;主方案开启了 usernames。登录后浏览目录,拖入文件或使用上传入口,等待队列显示完成,再刷新或点击文件下载。用手机浏览器也走同一 HTTP/HTTPS 入口。

owner 可以在选中文件后移动、重命名和删除;uploader 用来新增文件,reader 用来浏览和下载。界面选项随权限和版本变化,应以实际登录身份确认。?hc 连接说明页可以查看客户端连接提示。这里不承诺 min 能生成图片缩略图或转码播放;浏览器直接打开某种媒体格式属于客户端自身能力。

Windows 客户端

在 WinSCP 新建站点,文件协议选择 WebDAV:局域网测试填服务器 IP、端口 3923;通过代理时填 files.example.com、端口 443 并选择 TLS/SSL,用户名与密码分别填写。登录后进入 /files/;若客户端支持目录字段,可填 /files/。实际上传能力取决于账号权限。WinSCP WebDAV 说明。

Windows 文件资源管理器也能尝试"映射网络驱动器"或"添加网络位置",地址使用 https://files.example.com/files/。内置 WebClient 的服务状态、系统认证策略、文件名限制和传输限制都可能影响结果,不建议为了明文 HTTP 挂载去降低系统认证策略。出现兼容性问题时先使用 WinSCP 或 rclone 验证服务端,再定位 Windows 客户端。

通用 rclone 客户端

执行 rclone config 创建名为 cp 的 remote,类型选 webdav,URL 填 https://files.example.com/files/,vendor 选 other,账号和密码按提示填写。然后:

bash 复制代码
rclone lsf cp:
rclone copy /tmp/cp-probe.txt cp: --progress
rclone copyto cp:cp-probe.txt /tmp/cp-rclone.txt --progress

rclone copy 用 uploader,下载或列表可用 reader。不要把 rclone obscure 等同于密码加密保管;保护本地配置。rclone 官方 WebDAV 文档。

用 curl 独立检查目录枚举:

bash 复制代码
curl --user reader -X PROPFIND -H 'Depth: 1' \
  https://files.example.com/files/

预期返回 207 Multi-Status。普通 HTTPS URL 并不代表任何客户端必然支持全部 WebDAV 操作。编辑已有文件通常还需要 d 删除权限;部分客户端需要卷级 daw 才会按预期覆盖。不要为了编辑兼容性给 uploader 全局删除权限 ,可另设专用编辑卷、授权合适账号,并明确 daw 会改变 PUT 同名覆盖行为。WebDAV 请求实现。

FTP 独立扩展

FTP 的控制连接负责登录与命令,数据连接负责目录列表和文件内容。主动模式中服务端连接客户端指定的数据端口,容易受客户端 NAT/防火墙影响;被动模式由客户端连接服务端给出的数据端口,更适合本文的 Docker bridge 方案。

图 3:两种模式的控制连接方向相同,数据连接发起方不同。只映射控制端口,会出现"能登录却不能列目录"。

在 config/copyparty.conf 原有 [global] 内加入:

ini 复制代码
  ftp: 3921
  ftp-nat: 192.0.2.10
  ftp-pr: 12000-12009

192.0.2.10 是文档地址,必须替换为客户端实际能连接到的宿主机 LAN IP 。FTP 服务监听容器 3921;PASV 回应里的地址由 ftp-nat 指定。被动端口范围两端都要用相同端口号,不能任意改号后仍回报容器端口。

在 Compose 的 ports: 下保留 Web 端口,并添加:

yaml 复制代码
      - "${CP_BIND_IP:-127.0.0.1}:3921:3921"
      - "${CP_BIND_IP:-127.0.0.1}:12000-12009:12000-12009"

LAN 模式将 .env 的绑定地址改为真实 LAN IP。测试本机回环时把 ftp-nat 也改成 127.0.0.1。修改端口后执行:

bash 复制代码
docker compose config --quiet
docker compose up -d
docker compose logs --tail=100 copyparty

只改配置文件参数时需要 docker compose restart copyparty;只运行 up -d 未必重启未发生 Compose 变化的容器。首次新增 FTP 端口会触发重建。官方 Docker FTP 指南。

FileZilla/WinSCP 选择 FTP、服务器 LAN IP、3921、uploader 和对应密码,使用被动模式,进入 /files/ 上传新文件,再下载比对。命令验证:

bash 复制代码
curl --fail --user uploader --ftp-pasv -T /tmp/cp-probe.txt \
  ftp://服务器LAN地址:3921/files/ftp-probe.txt
curl --fail --user reader --ftp-pasv \
  ftp://服务器LAN地址:3921/files/ftp-probe.txt -o /tmp/ftp-downloaded.txt
sha256sum /tmp/cp-probe.txt /tmp/ftp-downloaded.txt

主方案的 ftp-no-ow 拒绝 FTP 同名覆盖;重新测试用新文件名。不要把 FTP 的上传恢复行为当成浏览器 up2k 的断点续传保证。目录列表失败时检查实际 PASV/EPSV 回复、地址、范围、Docker 映射和两侧防火墙。

公网 NAT 还需要路由器转发控制端口与同号被动范围,并使 ftp-nat 回报公网可达地址;多网卡、内外网同时访问及回流 NAT 需要另外验证。本文推荐在 LAN/VPN 内使用 FTP;明文 FTP 会暴露账号和文件内容。 HTTP 反向代理不能保护独立 FTP 连接,不要把 3921 放到 HTTPS 代理里就当作 FTPS。

TFTP、FTPS、SFTP 与 SMB

TFTP:只给隔离设备分发文件

TFTP 不登录账号,只读取匿名可读目录;匿名写、删除权限会分别影响写入和覆盖。当前主方案没有匿名卷,因此仅开启端口也无法读取受保护的 /files/。若设备必须使用 TFTP,可创建 data/firmware/,只放允许公开给该隔离网络的文件。

在原有 [global] 加入:

ini 复制代码
  tftp: 3969
  tftp-pr: 13000-13009
  tftp-nols

再新增一个独立卷:

ini 复制代码
[/firmware]
  /w/firmware
  accs:
    r: *

在原 Compose 的 ports: 加入下面两行;CP_BIND_IP 必须是设备能访问的 LAN 接口地址:

yaml 复制代码
      - "${CP_BIND_IP:-127.0.0.1}:69:3969/udp"
      - "${CP_BIND_IP:-127.0.0.1}:13000-13009:13000-13009/udp"

创建目录、放入文件、保证 UID 1000 可读,然后 docker compose config --quiet 和 docker compose up -d。请求从 UDP 69 进入容器 3969;传输来自独立 UDP 数据端口,所以还需要第二条范围映射。这里映射宿主机低端口,应用仍以非 root 用户监听高端口,不需要特权模式或 host 网络。

bash 复制代码
curl --fail tftp://服务器LAN地址/firmware/firmware.bin \
  -o /tmp/firmware-downloaded.bin
sha256sum data/firmware/firmware.bin /tmp/firmware-downloaded.bin

tftp-nols 限制目录枚举,但没有增加账号认证;这个匿名卷还会通过 HTTP 可读,WebDAV 因 dav-auth 仍要求登录。用 VLAN、防火墙和服务启停控制访问范围。只支持 binary/octet/image 模式,不支持 netascii,不能假定 RFC 7440 窗口扩展可用。TFTP 模块、partftpy 项目。

FTPS:换依赖镜像并管理独立证书

min 缺少 PyOpenSSL,实际模块检查和 FTPS 实现均确认不能直接启用。确需 FTPS 可独立评估 copyparty/im:1.20.25,在全局指定 ftps: 3990、ftp-pr、ftp-nat,并配置 cert 和 certkey,映射 3990/TCP 与被动范围。证书文件需正确挂载并可被容器用户读取;已有 HTTPS 代理的证书不会自动进入该容器。

客户端应选择 显式 TLS/FTPES ,不是 implicit FTPS,不是 SFTP。服务端要求控制与数据连接均使用 TLS。若同时启用 FTP/FTPS,项目会分割被动端口范围,需扩大范围后检查两边。此扩展未在本次环境端到端测试,因此不作为可以直接投产的完整配置交付。FTPS 实现与依赖条件。

SFTP:与 FTP 无关的 SSH 文件入口

SFTP 需要 Paramiko,官方 im/ac/iv/dj 有对应依赖,min 没有。需要它时可独立切换到 im,使用 sftp: 3922,设置 sftp-key: 用户名 ssh-ed25519 公钥内容 并映射 3922/TCP;默认以公钥认证,只有显式设置 sftp-pw 才开启密码认证。设置 sftp-hostk: /cfg/ssh-hostkeys 持久化主机密钥,并在客户端核对指纹。

它不占用 SSH 系统服务 22 端口,也不表示获得远程 shell。切换镜像会增加依赖,需重新核验当前版本;本文没有为"不需要 SFTP"的主方案添加这些组件。SFTP 模块。

SMB/CIFS 与 NFS:交给专用服务

SMB 后端依赖 Impacket;官方明确警告 VFS 集成与安全问题。1.20.25 除依赖外,还阻止在未设置 hack-me-bro 时启动 SMB。本文不提供把这个危险开关用于公网共享的配置,确需 Windows 系统共享时优先评估独立 Samba。1.20.25 发布说明。

Copyparty 没有 NFS 服务端协议实现。将宿主机的 NFS 挂载目录映射给 /w,只是把 NFS 作为后端存储,客户端访问 Copyparty 仍走其启用的协议。后端掉线时还要避免扫描把临时不可见的文件误判为删除;可以评估官方 filesystem guards。NAS 存储的故障与权限不能由文件传输容器自动解决。

HTTPS 与安全管理

复用现有反向代理

受控 LAN 临时传文件可以直接访问 IP,但 HTTP 和 FTP 的认证信息仍是明文。长期访问和互联网入口,应为 HTTP/WebDAV 使用 HTTPS,复用已存在的 Nginx/Caddy 即可,不必为本文强制添加代理容器。

图 4:TLS 在反向代理终止;后端 HTTP 必须受网络边界保护。独立 FTP/TFTP 端口不会因为 HTTPS 入口而自动加密。

以下示例适用于 Nginx 在 Docker 宿主机运行,对应主方案回环绑定;域名和证书路径是示例,必须替换为真实部署值:

nginx 复制代码
server {
    listen 443 ssl;
    server_name files.example.com;
    ssl_certificate /etc/nginx/certs/files/fullchain.pem;
    ssl_certificate_key /etc/nginx/certs/files/privkey.pem;

    client_max_body_size 0;
    client_body_timeout 600s;
    send_timeout 600s;

    location / {
        proxy_pass http://127.0.0.1:3923;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_request_buffering off;
        proxy_buffering off;
        proxy_read_timeout 600s;
        proxy_send_timeout 600s;
    }
}

此单层代理覆盖来自客户端的 X-Forwarded-For,不允许随意透传伪造的链。转发 WebDAV 的 PROPFIND/PUT/MOVE/DELETE,不额外启用 Nginx 自己的 DAV 文件服务,也不加入阻止这些方法的 limit_except。这里 proxy_pass 保留原请求路径,采用独立子域名避免子路径重写。

client_max_body_size 0 取消 Nginx 请求体大小限制,应结合存储剩余空间、访问控制与业务要求评估;也可以设置明确的上限。600 秒是读写空闲超时,不是允许整个文件最多传输十分钟。浏览器分块上传与普通 WebDAV PUT 的请求大小不同,应分别测试,不能以单个小文件成功证明大文件链路可靠。Nginx proxy 模块、请求体与超时参数。

应用前运行 nginx -t,通过后按现有服务机制重载。不要使用 curl -k 来验证正式证书;使用 curl -I https://files.example.com/ 和 WebDAV 请求,再做实际的大文件上传下载。

真实 IP 与可信代理

Docker bridge 的源地址可能是网关地址,并非 Copyparty 看到的 127.0.0.1。先查看请求日志及:

bash 复制代码
docker inspect copyparty-files --format '{{json .NetworkSettings.Networks}}'

然后在 [global] 设置实际观察到的代理来源,例如:

ini 复制代码
  xff-src: 172.20.0.1/32
  xff-hdr: x-forwarded-for
  rproxy: -1

这个地址只是格式示例,必须换成容器日志确认的实际代理地址,不能盲信任整个 LAN,更不能设置 any。单层代理覆盖成一个客户端地址时,-1 选最近一项;若已有 CDN/多层代理,先在入口校验上游来源并重新设计可信链。对可信代理来源的检查和对客户端的授权是不同事情。保持后端只对代理开放,避免直接绕过 HTTPS。官方真实 IP 文档。

账号与文件安全

不要共享 owner 密码;日常传输使用 uploader 或 reader。敏感目录不要映射进容器,尤其不要挂宿主机根目录、Docker Socket 或私钥目录。匿名临时只读可以在明确受控的 LAN 卷 添加 r: *,但它意味着所有能连到该卷入口的人都能下载;用完移除并重启。若把 data 挂成 :ro,应用层的 w 权限也无法突破文件系统只读。

例如,只在受控 LAN 临时分享 data/public/:先创建目录、放入准备分享的文件,并保证容器 UID 可读,在原配置末尾增加以下卷,然后重启服务。主共享 /files/ 的账号授权仍按原配置执行。

ini 复制代码
[/public]
  /w/public
  accs:
    r: *

将 .env 绑定地址设置为真实 LAN IP,首次改变绑定后执行 docker compose up -d;以后只改卷配置时执行 docker compose restart copyparty。匿名浏览器访问 http://服务器LAN地址:3923/public/,只有列目录和下载权限。主方案 dav-auth 仍要求 WebDAV 登录;如果先前启用了 TFTP,它也可能读取这个匿名卷,所以需要同步评估所有已启用协议。分享结束后删除这段配置并重启,或直接 docker compose stop。只放允许该网络访问的内容,不给匿名用户 w、m、d、a。

上传文件是不可信内容,不应自动执行,也不应把共享目录当作服务器代码目录。主方案禁用媒体缩略图,降低了不需要的处理组件,但并不保证任何上传都安全。配置中的明文密码需通过文件权限和备份权限保护。

min 没有 Argon2 依赖,不能直接照搬 ah-alg: argon2。本次确认标准库存在 hashlib.scrypt,但主方案没有启用密码哈希;如使用 scrypt,要按 --help-pwhash 指南生成,并保持 ah-salt 和 usernames 输入规则一致,测试登录后再替换现有配置。不要把其他镜像的哈希能力默认赋给 min。

持续关注官方安全公告与发布记录。固定旧版本是复现手段,不是长期安全策略;本文选定版本已经包含官方近期的安全修复,今后仍要维护。共享目录应真正隔离,不能把大小写不敏感文件系统上的"隐藏子目录"当成可靠敏感数据边界。

按需启动、备份与升级

常用操作

在 Compose 目录执行:

bash 复制代码
docker compose start                  # 已创建的停止容器
docker compose up -d                  # 首次创建或同步 Compose 变化
docker compose stop                  # 用完停止,保留容器
docker compose restart copyparty      # 重启现有容器,不拉取新镜像
docker compose ps -a
docker compose logs --tail=100 copyparty
docker compose logs -f copyparty
docker compose up -d --force-recreate # 按当前配置重建
docker compose down                  # 删除本项目容器与默认网络

主方案 restart: "no" 适合"平时关闭,需要时再启动",不会因 Docker daemon 重启自动拉起,也不会自动处理崩溃。常驻服务可改为 unless-stopped,但要理解运行中的容器会在 daemon 恢复时重启;手动停止的容器保持停止。Docker 重启策略。

stop 保留容器,可以 start;down 删除容器,要重新 up -d。本方案使用 bind mount,删除容器或其网络不会删除宿主机 data/ 和 config/。错误删除目录、磁盘故障及恶意删除仍会造成数据丢失,持久化不等于备份。bind mount 文档。

备份与恢复

停止服务,避免索引数据库和文件处于写入过程;备份放在共享目录以外:

bash 复制代码
docker compose stop
mkdir -p ../copyparty-backups
backup_path="../copyparty-backups/copyparty-$(date +%Y%m%d-%H%M%S).tar.gz"
tar -czf "$backup_path" compose.yaml .env config data
chmod 600 "$backup_path"
# 需要继续共享时再执行 docker compose start

已有大量文件时,评估增量备份或存储快照,不要把这条压缩命令当成唯一方案。备份包含密码和索引,需限制访问并定期做恢复演练。

恢复到新的空目录,不覆盖正在使用的数据:

bash 复制代码
mkdir -p "$HOME/copyparty-restore"
cd "$HOME/copyparty-restore"
tar -tzf /path/to/copyparty-backup.tar.gz
tar -xzf /path/to/copyparty-backup.tar.gz
ls -ldn config data
docker compose config --quiet
docker compose up -d

恢复前检查备份来源、路径及空间;恢复后核对 .env 地址、UID/GID、目录属主,确认不存在同名容器冲突,并重新验证认证和文件哈希。索引状态与配置也随 config/ 恢复。

升级与回滚

查看运行版本、所用镜像 ID,记录升级前状态:

bash 复制代码
docker compose exec copyparty python3 -m copyparty --version
docker inspect copyparty-files --format '{{.Image}}'
docker image inspect copyparty/min:1.20.25 --format '{{json .RepoDigests}}'

先阅读新版本的 release notes 和安全公告,备份后把 Compose 标签改为已核验的新版本;若使用摘要,也必须更新它。执行:

bash 复制代码
docker compose config --quiet
docker compose pull
docker compose up -d
docker compose ps
docker compose logs --tail=100 copyparty

pull 只是下载;up -d 才根据新镜像/配置重新创建容器。restart 不会切到刚拉取的新镜像。重做 reader 下载、uploader 上传、匿名拒绝和已启用协议检查后,才能判断升级成功。

回滚时把 image: 改回记录的旧标签或摘要,再 docker compose up -d。如果新版本改变配置语法或元数据格式,仅换旧镜像可能不足,应停止服务并恢复兼容的配置/索引备份,同时保护升级后新增的共享文件。不要对包含这些新增数据的目录直接执行破坏性恢复。

资源占用怎么测

本文不提供未经实测的 CPU/内存排行榜。可用 docker stats --no-stream copyparty-files 观察容器指标,配合 df -h、iostat -xz 1 和客户端哈希验证。比较时固定硬件、架构、镜像摘要、磁盘、网络、文件集、客户端、协议、TLS 与并发数,分别测空闲状态、单大文件和大量小文件;注明冷缓存/热缓存及后台扫描条件。镜像下载大小、磁盘占用、RSS 和容器内存指标不是同一概念。

外部改动文件需要等待或触发索引重新扫描;主方案 e2dsa 启动扫描,可在维护窗口重启确认。元数据更新策略与直接目录列表显示是不同问题。大量文件扫描会增加磁盘 I/O,不必为了"功能完整"开启媒体分析。

故障排查

先看 docker compose ps -a、启动日志和展开后的配置,再按症状定位。docker compose config 与配置文件可能含敏感信息,不要原样公开。

故障现象 可能原因 检查方法 处理方向
容器启动后退出 配置语法/不支持参数、端口冲突 docker compose ps -a;docker compose logs --tail=100 修正具体报错;不要靠重启循环掩盖
配置未生效 .conf 放错目录、挂载错误、未重启 docker inspect copyparty-files --format '{{json .Mounts}}';检查日志卷列表 确认宿主机 config 内文件被挂到 /cfg;重启
出现匿名写权限 没有有效卷配置,回落默认共享 启动日志的 volumes/permissions 先停止服务,修复 /files 配置后再开放入口
本机能访问,LAN 不通 仍绑定 127.0.0.1、接口地址错误 docker compose port copyparty 3923;宿主机 ss -lnt 修改 .env、up -d 重建;检查 Docker 实际转发策略
全部入口无法访问 容器退出、端口被占用、客户端路由 curl -v http://127.0.0.1:3923/files/;ss -lnt 先通本机再测试远端;分辨监听与转发
登录失败 未按 usernames 模式登录、配置密码错误、封禁 curl --user reader -v URL;日志 Web 用 用户名:密码;客户端分开填;修复失败原因
上传 403 或拒绝 账号只有 r、宿主机权限不足、只读挂载 docker compose exec copyparty id;ls -ldn config data;Mounts 同时核对应用权限和系统权限
上传磁盘错误 空间/inode 不足 df -h;df -i;日志 清理确定可删的文件或扩容,不盲删索引
下载 404/403 URL 编码、文件名、卷路径或权限 登录后查看列表;curl --user reader -I URL 区分文件不存在与权限拒绝;核对 /files/
WebDAV 挂载失败 WebClient 策略、认证、客户端行为 curl PROPFIND;WinSCP 或 rclone 对照 服务端 207 正常后检查客户端;优先 HTTPS
WebDAV 修改生成新名字 客户端覆盖条件不满足 权限与请求日志;是否带 x-oc-mtime 只对专用编辑卷评估 d 和 daw,不扩大普通上传权限
FTP 登录后不能列目录 PASV 地址或数据范围不通 FileZilla 详细日志;curl -v --ftp-pasv 同步 ftp-nat、ftp-pr、端口映射和网络转发
FTP 内网正常公网异常 公网地址/NAT 回流/防火墙 比较内外网 PASV/EPSV 与实际目的地址 验证路由器同号转发;优先 VPN 内访问
TFTP 请求超时 只映射 69,数据端口未放行 检查 tftp-pr;抓取 UDP;TFTP 日志 映射同号 UDP 数据范围,检查只读匿名卷
代理 502 后端关闭、proxy_pass 地址错误 宿主机 curl 后端;nginx -t;代理错误日志 明确代理在宿主机还是容器;按需启动后端
HTTPS 上传 413 代理/CDN 请求体上限 Nginx 配置与错误日志;比较直连 设置合理大小限制;检查链路每一层
大文件中断 空闲超时、磁盘慢、网络/CDN 限制 传输时间、服务/代理日志、磁盘指标 找到发生中断的层;验证实际文件集与客户端
所有用户被同时封禁 容器只看见代理 IP 请求日志、真实代理来源 正确设置 xff-src 和可信链,再处理封禁
宿主机改文件后结果异常 索引未扫描、缓存、后端挂载掉线 ls data、启动扫描日志、实际存储挂载 检查后端状态;在维护窗口重新扫描
更新后启动不兼容 参数或索引格式变化 新版发布说明、启动报错 恢复兼容配置/索引和旧摘要,再验证

Docker 发布端口可能与宿主机常见防火墙规则的直觉不同,要按实际 Docker 网络规则验证来源限制;不能因为 UFW 显示拒绝就认定容器端口已被隔离。Docker 防火墙文档。

相关推荐
切糕师学AI3 小时前
Kubernetes 探针全解析:启动探针、存活探针与就绪探针(Startup/Liveness/Readiness Probe)
容器·kubernetes·探针·probe
岁寒良木4 小时前
麒麟 V10 (x86_64) 离线/联网部署 Docker 26.1.4 与 MaxKB v2.10 LTS 实战指南
python·docker·kylin
fb_123456 小时前
K8s调度实战全景-Pod调度与资源管控
云原生·容器·kubernetes
吴声子夜歌7 小时前
Kubernetes权威指南——Kubernetes安装配置指南(二进制文件安装)
容器·kubernetes
江华森7 小时前
Kubernetes集群部署实战:使用kubeadm在4台ECS服务器上搭建K8s v1.31集群
云原生·容器·kubernetes
正经教主8 小时前
【FDE系列】阶段2:Day 43(UP详细版):Docker Compose — 多容器一键编排
运维·docker·容器
csdn_aspnet8 小时前
构建、运行与管理容器的 18 个常用 Docker 命令
docker·容器·eureka·command
木雷坞8 小时前
AnythingLLM Docker部署:中文资料上传后无引用的检查路径
运维·docker·容器
暖核8 小时前
K8s 深度拆解:健康检查、认证授权与可视化面板全梳理
云原生·容器·kubernetes