手机要给电脑传一个大文件,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 防火墙文档。