transfer.sh 1.6.1 Docker Compose 部署指南
使用官方 noroot 镜像以 Docker Compose 部署 transfer.sh 1.6.1,覆盖镜像选型与本地构建、首次部署全流程、数据持久化与目录结构、环境变量表、配置文件挂载、等价 docker run、常用运维命令与常见问题排障,全部步骤已在 Ubuntu 24.04 服务器实测通过。
transfer.sh 1.6.1 Docker Compose 部署指南
> 目标:在一台 Linux 服务器上用 Docker Compose 把 transfer.sh v1.6.1 跑起来并完成上传/下载验证——覆盖镜像选型(官方 noroot 镜像与本地构建两条路径)、首次部署全流程、数据持久化目录结构、环境变量表、配置文件挂载、等价 docker run 与常用运维命令。全部命令与回显已在下述环境实测通过。
一、环境信息
本文所有步骤在以下环境实测完成:
- 操作系统:Ubuntu 24.04.5 LTS(x86_64)
- Docker:Docker version 29.9.2, build a82e528
- Docker Compose:Docker Compose version v5.6.1
- 组件版本:transfer.sh v1.6.1(
transfersh --version回显transfer.sh version v1.6.1) - 镜像:
transfer.sh:v1.6.1-noroot(内容与官方dutchcoders/transfer.sh:v1.6.1-noroot一致,选型说明见第二章) - 服务端口:宿主机
8130→ 容器内8080(容器内端口由镜像 ENTRYPOINT 固定为 8080) - 数据目录:项目目录下
compose-data/(bind mount 到容器内/data) - Compose 项目名:
transfer-sh-1.6.1-stack(compose 文件中显式name:指定)
验证环境版本的命令与实测回显:
docker --version
Docker version 29.9.2, build a82e528
docker compose version
Docker Compose version v5.6.1
grep PRETTY_NAME /etc/os-release; uname -m
PRETTY_NAME="Ubuntu 24.04.5 LTS"
x86_64
transfer.sh 本身是单个静态编译的 Go 二进制(--help 全量参数见《transfer.sh 1.6.1 配置参数详解》第二章),镜像内除二进制外只有 mime.types 与 CA 证书,资源占用极小(实测运行中 RSS 约 25 MB)。
二、镜像选型说明
2.1 官方镜像与标签
transfer.sh 官方在 Docker Hub 发布 dutchcoders/transfer.sh 镜像,同一版本提供两种标签形态(来源:官方仓库 README「Docker」章节,查询日期 2026-11-01):
| 标签形态 | 示例 | 运行用户 | 说明 |
|---|---|---|---|
latest / latest-noroot | dutchcoders/transfer.sh:latest | root / 5000 | 指向最新构建,README 明确不建议生产使用(可能包含未发布改动) |
vx.y.z | dutchcoders/transfer.sh:v1.6.1 | root | 正式版本,root 运行 |
vx.y.z-noroot | dutchcoders/transfer.sh:v1.6.1-noroot | 5000(非特权) | 正式版本 + 非 root 运行,官方推荐形态 |
关键差异解读:生产部署一律选 v1.6.1-noroot 这类带版本号的 -noroot 标签——版本号保证可复现,-noroot 保证服务进程无 root 权限,即便被攻破也难以直接越权写宿主文件。
官方镜像拉取实测(官方源直连成功,注意回显末尾的 digest):
docker pull dutchcoders/transfer.sh:v1.6.1-noroot
v1.6.1-noroot: Pulling from dutchcoders/transfer.sh
97f5f14b9f64: Pulling fs layer
32b9a28ccef5: Pulling fs layer
df5074319a19: Pulling fs layer
0bd7b686b904: Pulling fs layer
26514c47e9eb: Pulling fs layer
0bd7b686b904: Download complete
32b9a28ccef5: Download complete
df5074319a19: Download complete
26514c47e9eb: Download complete
97f5f14b9f64: Download complete
0bd7b686b904: Pull complete
32b9a28ccef5: Pull complete
df5074319a19: Pull complete
26514c47e9eb: Pull complete
97f5f14b9f64: Pull complete
ec280d9a8bb4: Download complete
Digest: sha256:8db9ade72a0da260f0b6a52897bd1c7c35c3d5f25b3f9f9c7a47c2a354687703
Status: Downloaded newer image for dutchcoders/transfer.sh:v1.6.1-noroot
docker.io/dutchcoders/transfer.sh:v1.6.1-noroot
⚠️ 网络说明:以上为官方 Docker Hub 源直连拉取成功的实测回执(2026-11-01)。另一路经 DaoCloud 公共镜像加速器(docker.m.daocloud.io)的拉取实测失败,报错为「Error response from daemon: error from registry: … 这镜像不在白名单. this image is not in the allowlist.」——该加速器对 transfer.sh 仓库不在白名单内,请直接走官方源。
2.2 镜像内部构成
用 docker inspect 查看官方同名配置(本地构建镜像与官方镜像配置一致):
docker inspect transfer.sh:v1.6.1-noroot \
--format '{{json .Config.Entrypoint}} | {{json .Config.Cmd}} | {{.Config.User}}'
["/go/bin/transfersh","--listener",":8080"] | null | transfersh
三个关键信息:
- ENTRYPOINT 已带
--listener :8080:容器内固定监听 8080,docker run/compose 的command:传的是「追加参数」(如--provider local --basedir /data),不要重复写--listener,也不要指望默认参数——transfersh裸启动默认监听127.0.0.1:8080,在容器内等于没监听; - 运行用户是
transfersh(UID/GID 5000):这就是-noroot标签的含义,直接决定了第五章的数据目录属主要求; - 基底为 scratch:镜像内没有 shell、没有包管理器,无法
docker exec进容器排查,日志一律走docker compose logs或服务端--log参数(见第十章)。
2.3 本地构建镜像(备选路径)
若需要离线环境部署或想固定二进制来源,可复刻官方 Dockerfile 的 final 阶段本地构建。实测使用的 Dockerfile 全文如下(builder 阶段因构建机访问 Docker Hub 拉取 Go 构建镜像不可用,改用「官方 Releases 静态二进制直供」方案,二进制 sha256 已与官方 transfersh-v1.6.1-linux-amd64 校验值核对一致:46fb5ac519769bae8a626cc3f79e2101013ff13beb75d5a613b8df6970d9e27c):
# 复刻官方 Dockerfile(v1.6.1)final 阶段:scratch + mime.types + CA + 非 root 5000
# builder 阶段因 Docker Hub 不可达改用「官方 Releases 静态二进制」直供(sha256 已对官方校验值核验)
FROM alpine:3 AS assets
RUN apk add -q mailcap
RUN mkdir -p /tmp/empty /tmp/useradd
COPY passwd /tmp/useradd/passwd
COPY group /tmp/useradd/group
FROM scratch AS final
LABEL maintainer="Andrea Spacca <andrea.spacca@gmail.com>"
COPY --from=assets /etc/mime.types /etc/mime.types
COPY --from=assets /tmp/empty /tmp
COPY --from=assets /tmp/useradd/passwd /etc/passwd
COPY --from=assets /tmp/useradd/group /etc/group
COPY --from=assets /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
COPY --chown=5000:5000 transfersh-v1.6.1-linux-amd64 /go/bin/transfersh
USER transfersh
ENTRYPOINT ["/go/bin/transfersh", "--listener", ":8080"]
EXPOSE 8080
其中 passwd/group 两个文件内容(非 root 用户定义):
transfersh:x:5000:5000::/nonexistent:/sbin/nologin
transfersh:x:5000:
构建与打标(在与 Dockerfile 同目录、二进制就位后执行):
docker build -t transfer.sh:v1.6.1-noroot .
构建产物大小实测 36 MB(官方镜像同版实测 36.4 MB,差异来自基础资产层打包方式),二进制本体完全一致。本文后续 compose 部署使用该本地镜像标签 transfer.sh:v1.6.1-noroot;使用官方全名标签的读者把 image: 改为 dutchcoders/transfer.sh:v1.6.1-noroot 即可,其余步骤完全相同。
三、前置条件
- Docker Engine 与 Docker Compose v2 已安装(版本要求见第一章,
docker compose version能正常回显即可); - 规划宿主机端口:容器内固定 8080,宿主侧端口自选,本文用
8130(确认未占用:ss -ltn | grep 8130应无输出); - 规划数据目录:本文统一放
/opt/transfer-sh/,上传数据落compose-data/子目录; - 数据目录属主必须是 UID/GID 5000(镜像内服务进程运行用户),否则启动后上传报
Could not save metadata——这是最常见的首跑故障,排障实录见第十一章 11.2; - 防火墙如启用需放行宿主端口(如
ufw allow 8130/tcp)。
准备命令与实测回显:
mkdir -p /opt/transfer-sh/compose-data && cd /opt/transfer-sh
chown -R 5000:5000 compose-data
ls -ln | grep compose-data
drwxr-xr-x 2 5000 5000 4096 Nov 1 14:58 compose-data
⚠️ 注意:
chown 5000:5000不是可有可无。镜像内进程以 UID 5000 运行,若目录属 root(新建目录的默认属主),服务能启动、首页能访问,但任何上传都会失败,错误现象见第十一章 11.2。
四、部署步骤
4.1 编写 compose 文件
在 /opt/transfer-sh/ 下创建 docker-compose.yml,全文如下(与实测运行文件一致):
name: transfer-sh-1.6.1-stack
services:
app:
image: transfer.sh:v1.6.1-noroot
container_name: transfer-sh-1.6.1-web
command: --provider local --basedir /data
ports:
- "8130:8080"
volumes:
- ./compose-data:/data
restart: unless-stopped
networks:
ts-net:
networks:
ts-net:
driver: bridge
ipam:
config:
- subnet: 10.89.58.0/24
逐项说明:
name: transfer-sh-1.6.1-stack:显式指定 Compose 项目名,生成的网络/容器名都带此前缀,避免多套部署互相干扰,也保证compose down只作用于本项目;image:镜像标签说明见第二章;官方镜像用户把值改为dutchcoders/transfer.sh:v1.6.1-noroot;container_name:固定容器名,便于docker logs/docker inspect直达;command: --provider local --basedir /data:追加到 ENTRYPOINT 之后的启动参数,等价于transfersh --listener :8080 --provider local --basedir /data。--provider local使用本地磁盘存储(四种后端对比见《transfer.sh 介绍与选型指南》第三章),--basedir /data指定数据落在挂载目录;ports: "8130:8080":宿主 8130 → 容器 8080;volumes: ./compose-data:/data:数据持久化 bind mount,详见第五章;restart: unless-stopped:宿主机重启后自动拉起(手动 stop 的除外);networks.ts-net:显式创建项目专用 bridge 网络并固定网段10.89.58.0/24(网段可按自己环境调整,避开既有网络即可)。单机部署其实可以省略 networks 段让 Compose 自建默认网络,显式写出的好处是网段可控、便于与同机其他部署避让。
4.2 启动服务
cd /opt/transfer-sh
docker compose up -d
首次创建的实测回显:
Container transfer-sh-1.6.1-web Creating
Container transfer-sh-1.6.1-web Created
Container transfer-sh-1.6.1-web Starting
Container transfer-sh-1.6.1-web Started
4.3 确认运行状态
docker compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
transfer-sh-1.6.1-web transfer.sh:v1.6.1-noroot "/go/bin/transfersh …" app Less than a second ago Up Less than a second 0.0.0.0:8130->8080/tcp, [::]:8130->8080/tcp
再看一眼服务日志确认监听正常:
docker compose logs app
(输出节选,实测前 5 行)
transfer-sh-1.6.1-web | [transfer.sh]2026/11/01 06:58:39 Transfer.sh server started.
transfer-sh-1.6.1-web | using temp folder: /tmp/
transfer-sh-1.6.1-web | using storage provider: local
transfer-sh-1.6.1-web | [transfer.sh]2026/11/01 06:58:39 starting to listen on: :8080
transfer-sh-1.6.1-web | [transfer.sh]2026/11/01 06:58:39 ---------------------------
日志里三行关键信息与预期一致:临时目录 /tmp/、存储后端 local、监听 :8080。
4.4 功能验证(上传/下载闭环)
服务端首页在浏览器打开 http://<服务器IP>:8130/ 即可看到说明页;命令行验证走 curl(curl 用法细节见《transfer.sh 1.6.1 curl 上传下载命令详解》):
curl -s --upload-file hello.txt http://192.168.1.172:8130/hello.txt
http://192.168.1.172:8130/WNwFDdYW95/hello.txt
响应即下载 URL。下载回读并比对内容一致性:
diff hello.txt <(curl -s http://192.168.1.172:8130/WNwFDdYW95/hello.txt) && echo "DIFF: identical"
DIFF: identical
再确认首页文本态(curl 默认请求返回纯文本说明页):
curl -s http://192.168.1.172:8130/ | head -3
192.168.1.172:8130: Easy file sharing from the command line
===
made with <3 by DutchCoders
上传、下载、首页三者都正常,部署完成。
五、数据持久化说明
5.1 挂载关系与目录结构
./compose-data:/data 是整个部署唯一的持久化点:--provider local 后端把所有上传数据写进 --basedir(即容器内 /data),对应宿主机 compose-data/。local 后端的落盘结构为「每个上传一个以随机 token 命名的一级子目录,目录内是文件本体 + 同名 .metadata 元数据文件」:
ls -la /opt/transfer-sh/compose-data | head -8
total 36
drwxr-xr-x 9 5000 5000 4096 Nov 1 14:54 .
drwxr-xr-x 4 5000 5000 4096 Nov 1 14:20 ..
drwx------ 2 5000 5000 4096 Nov 1 14:22 N9jgbP8uCl
drwx------ 2 5000 5000 4096 Nov 1 14:22 Ri4QjkDfVE
drwx------ 2 5000 5000 4096 Nov 1 14:22 fYdpkLW5X8
drwx------ 2 5000 5000 4096 Nov 1 14:22 vKNyDlRSUi
drwx------ 2 5000 5000 4096 Nov 1 14:22 xo9KSLWTnj
每个 token 目录内部:
find /opt/transfer-sh/compose-data/N9jgbP8uCl -maxdepth 1
/opt/transfer-sh/compose-data/N9jgbP8uCl
/opt/transfer-sh/compose-data/N9jgbP8uCl/hello.txt.metadata
/opt/transfer-sh/compose-data/N9jgbP8uCl/hello.txt
.metadata 是 JSON 元数据(下载次数计数、过期时间、删除令牌等),内容实测示例:
{"ContentType":"","ContentLength":50,"Downloads":0,"MaxDownloads":-1,"MaxDate":"2026-11-02T06:49:47.761965554Z","DeletionToken":"eR4MJDEL5aY7ElAoVGz0","Encrypted":false,"DecryptedContentType":""}
字段含义:Downloads/MaxDownloads 对应 Max-Downloads 请求头的计数与上限(-1 为不限);MaxDate 对应 Max-Days 的到期时刻(零值 0001-01-01T00:00:00Z 表示永不过期);DeletionToken 是删除令牌(其 URL 形态即响应头 X-Url-Delete);Encrypted 标记是否服务端加密落盘。⚠️ 修改 .metadata 需谨慎:它同时是下载鉴权依据,误改会导致文件 404(实测验证见《transfer.sh 1.6.1 配置参数详解》5.5 节)。
5.2 属主与权限
服务进程 UID/GID 为 5000,token 子目录由服务创建,权限为 drwx------(仅 5000 可读写),文件为 -rw-------。宿主机侧只需保证 compose-data 本身属主为 5000:5000(第三章已 chown),子目录权限服务自己维护,不需要人工干预。
5.3 备份与迁移
数据自包含于一个目录,备份即打包:
tar -czf transfer-sh-data-$(date +%F).tar.gz -C /opt/transfer-sh compose-data
迁移到新服务器:把 tar 包解到新机相同相对结构、chown -R 5000:5000 compose-data、启动 compose——token/元数据/删除令牌全部保留,旧 URL 继续可下载。
六、环境变量表
transfer.sh 的全部参数均支持「flag 传参」与「环境变量传参」两种方式——--help 输出里每个参数末尾的 [$大写名称] 即对应环境变量名(全量参数表见《transfer.sh 1.6.1 配置参数详解》第四章)。环境变量方式已在二进制形态实测生效(PROVIDER=local LISTENER=:8143 RATE_LIMIT=3 TEMP_PATH=/tmp BASEDIR=/opt/transfer.sh/data 启动后限流 429 行为与 flag 方式一致)。常用项与默认值:
| 参数(flag) | 环境变量 | 默认值 | 说明 |
|---|---|---|---|
--listener | LISTENER | 127.0.0.1:8080 | HTTP 监听地址(镜像 ENTRYPOINT 已固定为 :8080) |
--provider | PROVIDER | 无 | 存储后端:local/s3/gdrive/storj,不设置启动即报错 |
--basedir | BASEDIR | 无 | local 后端数据目录 |
--temp-path | TEMP_PATH | /tmp | 临时文件目录 |
--log | LOG | /var/log/transfersh.log | 服务日志文件路径 |
--max-upload-size | MAX_UPLOAD_SIZE | 0(不限) | 单文件上传上限,单位 KB |
--rate-limit | RATE_LIMIT | 0(不限) | 每分钟请求上限 |
--purge-days | PURGE_DAYS | 0(关闭) | 上传自动清理天数 |
--purge-interval | PURGE_INTERVAL | 0(关闭) | 清理任务执行间隔,单位小时 |
--random-token-length | RANDOM_TOKEN_LENGTH | 10 | 下载 token 长度 |
--http-auth-user / --http-auth-pass | HTTP_AUTH_USER / HTTP_AUTH_PASS | 无 | HTTP Basic 认证账号/密码 |
--http-auth-htpasswd | HTTP_AUTH_HTPASSWD | 无 | htpasswd 文件认证 |
--http-auth-ip-whitelist | HTTP_AUTH_IP_WHITELIST | 无 | 免认证 IP 白名单 |
--ip-whitelist / --ip-blacklist | IP_WHITELIST / IP_BLACKLIST | 无 | 访问控制白/黑名单 |
--cors-domains | CORS_DOMAINS | 无 | 允许跨域的 Origin 列表 |
--tls-cert-file / --tls-private-key | TLS_CERT_FILE / TLS_PRIVATE_KEY | 无 | TLS 证书与私钥 |
--lets-encrypt-hosts | HOSTS | 无 | Let's Encrypt 自动签发域名 |
--clamav-host | CLAMAV_HOST | 无 | ClamAV 扫描服务地址 |
--virustotal-key | VIRUSTOTAL_KEY | 无 | VirusTotal API Key(系统级密钥,用变量注入,勿写进 compose 文件入库) |
在 compose 中用环境变量的写法示例(与 command: 传 flag 二选一即可,同时设置时 flag 优先):
services:
app:
image: transfer.sh:v1.6.1-noroot
command: --provider local --basedir /data
environment:
RATE_LIMIT: "60"
MAX_UPLOAD_SIZE: "102400"
RANDOM_TOKEN_LENGTH: "12"
💡 说明:
VIRUSTOTAL_KEY这类第三方服务密钥属于系统级真实密钥,不要明文写进 compose 文件提交到版本库,用environment: VIRUSTOTAL_KEY: "${VIRUSTOTAL_KEY}"形态引用,运行前export VIRUSTOTAL_KEY=<真实值>注入。
七、配置参数说明
compose 部署里调参数有两条路:
- 改
command:(推荐):追加 flag,例如加上传上限、限流与自动清理:
command: >-
--provider local
--basedir /data
--max-upload-size 102400
--rate-limit 60
--purge-days 30
--purge-interval 6
--random-token-length 10
- 改
environment::见第六章表。
每个参数的实测行为(413 超限、429 限流、403 黑名单、401 认证、purge 过期 404 等)不在本章展开,统一见《transfer.sh 1.6.1 配置参数详解》。改完参数应用的标准动作:
cd /opt/transfer-sh
docker compose up -d
实测回显(配置变更会触发重建;本例为临时加入 RANDOM_TOKEN_LENGTH 环境变量后执行 docker compose up -d):
Container transfer-sh-1.6.1-web Recreate
Container transfer-sh-1.6.1-web Recreated
Container transfer-sh-1.6.1-web Starting
Container transfer-sh-1.6.1-web Started
⚠️ 注意:
--purge-days启用后清理任务用定时器驱动,首次执行发生在启动后--purge-interval小时(最小粒度小时),不会启动即清理;只对 local 后端生效。
八、配置文件挂载
transfer.sh 没有主配置文件——所有配置经 flag/环境变量传入,不存在「挂载一个 transfer.sh.conf」的操作。实际需要挂载文件的是三类辅助资源:
- htpasswd 认证文件(
--http-auth-htpasswd用)。生成 apr1 哈希文件:
printf "admin:%s\n" "$(openssl passwd -apr1 -salt ts161salt q1w2e3r4)" > /opt/transfer-sh/htpasswd
cat /opt/transfer-sh/htpasswd
admin:$apr1$ts161sal$6CNCex5SESDLSuqclsqZ50
compose 中追加挂载与参数:
volumes:
- ./compose-data:/data
- ./htpasswd:/etc/transfer.htpasswd:ro
command: >-
--provider local
--basedir /data
--http-auth-htpasswd /etc/transfer.htpasswd
启用后未带凭据的上传返回 401 Not authorized,curl -u admin:q1w2e3r4 正常上传,实测回显见《transfer.sh 1.6.1 配置参数详解》5.4 节。
-
TLS 证书与私钥(
--tls-cert-file/--tls-private-key用):同样 bind mount 进容器后以 flag 引用路径,并按需加--force-https(HTTP 请求 308 跳转 HTTPS,行为实测见 C1 篇 5.2 节)。 -
自定义前端静态文件(
--web-path用):替换内置下载页模板时挂载自定义静态文件目录;绝大多数部署用不到,保持缺省即可。
九、等价 docker run
不使用 compose 的等价单条命令(与第四章 compose 完全等价):
docker run -d \
--name transfer-sh-1.6.1-standalone \
-p 8151:8080 \
-v /opt/transfer-sh/run-data:/data \
transfer.sh:v1.6.1-noroot \
--provider local --basedir /data
实测回显(返回容器 ID 长串即启动成功):
247b4799d198161f799cb62a901ab753186f8d4d5b110cda0e79f2b58b883e02
验证(独立数据目录 run-data,端口 8151):
curl -s --upload-file hello.txt http://192.168.1.172:8151/hello.txt
http://192.168.1.172:8151/q4s3xBEqyF/hello.txt
curl -s http://192.168.1.172:8151/q4s3xBEqyF/hello.txt
transfer.sh curl upload test
line2 for range test
compose 与 docker run 的取舍:compose 适合长期部署(参数/挂载/网络声明式管理、up -d 幂等更新),docker run 适合临时验证。生产建议 compose。
十、常用运维命令
| 操作 | 命令 | 说明 |
|---|---|---|
| 状态查看 | docker compose ps | 服务运行状态与端口映射 |
| 日志查看 | docker compose logs --tail 100 app | 标准输出日志(含每次上传/下载的访问记录) |
| 日志落盘 | command: 加 --log /data/transfersh.log | 日志文件随数据目录持久化 |
| 重启服务 | docker compose restart app | 不重建容器 |
| 参数变更生效 | docker compose up -d | 配置有变化时自动重建 |
| 停止服务 | docker compose down | 停容器并删项目网络,数据目录保留 |
| 升级版本 | image: 改为新版本标签后 docker compose up -d | 数据目录不动,token 全兼容 |
| 数据备份 | tar -czf transfer-sh-data-$(date +%F).tar.gz -C /opt/transfer-sh compose-data | 见 5.3 节 |
常用运维命令实测回显汇总:
docker compose restart app
Container transfer-sh-1.6.1-web Restarting
Container transfer-sh-1.6.1-web Started
docker compose down
Container transfer-sh-1.6.1-web Stopping
Container transfer-sh-1.6.1-web Stopped
Container transfer-sh-1.6.1-web Removing
Container transfer-sh-1.6.1-web Removed
Network transfer-sh-161-stack_ts-net Removing
💡 说明:
down只删除本项目(name: transfer-sh-1.6.1-stack)的容器与网络,compose-data/数据目录不受影响;这也是第四章强调显式name:的原因——没有项目名时按目录名推断,多套部署容易误伤。
日志落盘方式的实测回显(--log 指向文件后,访问日志包含来源 IP、方法、路径、状态码与客户端 UA):
[transfer.sh]2026/11/01 06:49:47 192.168.1.172:35948 - - [2026-11-01T06:49:47Z] "GET /usvdNeBMoS/expired.txt HTTP/1.1" 404 "" "curl/8.5.0"
十一、常见问题(FAQ)
11.1 启动日志报 bind: address already in use
现象:容器反复重启,日志出现:
[transfer.sh]2026/11/01 06:51:47 starting to listen on: :8135
[transfer.sh]2026/11/01 06:51:47 ---------------------------
[transfer.sh]2026/11/01 06:51:47 listen tcp :8135: bind: address already in use
定位:同一端口上已有实例(本例是同机另一个 transfer.sh 实例占了 8135)。
解决:换端口。compose 部署里容器内固定 8080,冲突通常发生在「宿主端口」层面——把 ports: 左侧换成空闲端口即可;同机跑多个 transfer.sh 二进制实例时改各自 --listener。
11.2 上传报 Could not save metadata(数据目录属主错误)
现象:服务正常启动、首页可访问,但任何上传返回:
Could not save metadata
定位:查看数据目录属主。镜像内进程以 UID 5000 运行,mkdir 新建的目录属 root(UID 0):
drwxr-xr-x 2 0 0 4096 Nov 1 14:58 run-data
进程对目录无写权限,.metadata 落盘失败即报此错。
解决:把数据目录属主改为 5000:5000,无需重启服务:
chown -R 5000:5000 /opt/transfer-sh/run-data
ls -ln | grep run-data
drwxr-xr-x 2 5000 5000 4096 Nov 1 14:58 run-data
修复后重试上传立即成功:
http://192.168.1.172:8151/3V2uRxk344/hello.txt
11.3 用了 latest 标签,行为与文档不符
官方 README 明确不建议生产使用 latest(可能指向未发布的开发构建)。处理:image: 固定为 v1.6.1-noroot 这类版本标签,docker compose up -d 重建生效。
11.4 反向代理后 IP 白名单/认证被绕过(X-Forwarded-For 伪造)
官方 README 顶部保留了安全告警(issue #670):在 IP 过滤与 HTTP 认证场景,攻击者可通过伪造 X-Forwarded-For 请求头绕过检查。本机实测复现:实例配置 --ip-blacklist 拉黑了发起请求的源地址,但带上伪造头后请求被放行:
-- host upload 3KB + X-Forwarded-For: 8.8.8.8 (spoof test) --
HTTP:200
缓解:transfer.sh 暴露在反向代理(nginx/Caddy)之后时,在代理层只注入代理自己生成的 X-Forwarded-For 并丢弃客户端原始值;或暂时不用 IP 白名单形态,改用 --http-auth-* 认证(认证校验不依赖该头)。截至本文查询日(2026-11-01)官方尚未发布包含修复的发行版。
11.5 上传返回 Request Entity Too Large(HTTP 413)
设置了 --max-upload-size(单位 KB)后超过上限的上传被拒。这是预期行为不是故障,调整参数值即可;该参数实测回显见《transfer.sh 1.6.1 配置参数详解》5.3 节。
11.6 配了 --purge-days 但过期文件还在
清理任务按 --purge-interval(小时)定时触发,首次执行在启动后一个间隔才发生;且只对 local 后端生效。到期文件在清理动作发生前仍可下载(下载侧的 Max-Days 到期检查与磁盘清理是两条独立机制,前者即时生效,后者等清理周期)。
十二、参考链接
- GitHub 仓库:https://github.com/dutchcoders/transfer.sh (README「Docker」章节、LICENSE,查询日期 2026-11-01)
- Docker Hub:https://hub.docker.com/r/dutchcoders/transfer.sh (镜像标签清单,查询日期 2026-11-01)
- 官方 Releases:https://github.com/dutchcoders/transfer.sh/releases (v1.6.1 静态二进制与 sha256,查询日期 2026-11-01)
- 安全告警:https://github.com/dutchcoders/transfer.sh/issues/670 (X-Forwarded-For 绕过,README 横幅引用,查询日期 2026-11-01)
- 系列文档:《transfer.sh 介绍与选型指南》、《transfer.sh 1.6.1 配置参数详解》、《transfer.sh 1.6.1 curl 上传下载命令详解》