Docker 部署 SFTPGo:把家用服务器变成安全文件交换站,外网临时收发不用开 NAS 后台
Docker 部署 SFTPGo:把家用服务器变成安全文件交换站,外网临时收发不用开 NAS 后台

家里有一台小主机、办公室有一台闲置 mini PC,平时用来跑 Docker、备份照片、同步资料。偶尔遇到一个很现实的需求:外部同事要临时传一个大文件,或者你要给对方发一个安装包、设计稿、日志压缩包。
很多人的第一反应是:把 NAS 后台映射出去,或者临时开一个公网端口。
我不建议这么做。
NAS 后台里通常有存储管理、用户管理、套件管理、系统设置,一旦暴露到公网,风险和收益不成比例。更稳妥的做法是:单独部署一个文件交换服务,只给外部人员一个低权限账号,只能访问一个独立目录,用完就关账号、关隧道。
这篇就用 Docker 部署 SFTPGo,把它变成一个临时、安全、可控的文件交换站;需要外网访问时,再用 cpolar 临时映射 SFTPGo 的 WebClient 入口,而不是把整块 NAS 或管理后台暴露出去。
这套方案适合什么场景
适合:
- 家用服务器、办公室小主机、迷你主机上临时收发文件;
- 给外部同事开一个临时上传/下载账号;
- 每个账号绑定独立目录,避免看到其他文件;
- 不想让对方安装 SFTP 客户端,只想通过网页上传下载;
- 不想开放 NAS 管理后台,只暴露必要的文件交换入口。
不适合:
- 长期公开网盘;
- 存放高度敏感资料;
- 给陌生人开放匿名上传;
- 把它当成完整 NAS 管理系统替代品。
SFTPGo 是一个文件传输服务器,支持 SFTP、FTP/S、WebDAV、HTTP WebClient 等能力。本文重点用它的 WebClient:外部同事打开网页,输入账号密码,就能上传或下载指定目录里的文件。
注意:SFTPGo 不等同于 NAS 后台。它更像一个“文件交换层”,适合做临时账号、目录隔离、权限控制;不要把它和群晖、威联通、TrueNAS 这类管理后台混在一起暴露。
整体流程

本文会做 6 件事:
- 在服务器上准备 SFTPGo 数据目录;
- 用 Docker Compose 启动 SFTPGo;
- 初始化管理员账号;
- 创建一个低权限文件交换用户;
- 用 WebClient 在本地验证上传和下载;
- 用 cpolar 临时映射 WebClient,让外部同事访问测试。
本文示例约定:
- SFTPGo 管理入口:
http://127.0.0.1:8080 - SFTPGo WebClient 入口:
http://127.0.0.1:8081 - 本地文件目录:
/srv/sftpgo/exchange - Docker 项目目录:
/opt/sftpgo - 临时用户:
partner01
如果你的服务器没有 /srv 或 /opt 写入权限,可以换成当前用户目录,例如 ~/sftpgo。路径换了以后,下面命令里的路径也要一起换。
第一步:准备本地目录
先在服务器上创建项目目录、配置目录和文件交换目录:
sudo mkdir -p /opt/sftpgo
sudo mkdir -p /srv/sftpgo/config
sudo mkdir -p /srv/sftpgo/exchange/partner01
sudo chown -R 1000:1000 /srv/sftpgo
cd /opt/sftpgo
这里的 1000:1000 是 SFTPGo Docker 镜像默认使用的普通用户 UID/GID。这样容器内的 SFTPGo 进程可以正常读写挂载目录。
目录含义:
/opt/sftpgo # Docker Compose 文件目录
/srv/sftpgo/config # SFTPGo 配置和内置数据
/srv/sftpgo/exchange # 对外文件交换根目录
/srv/sftpgo/exchange/partner01 # partner01 用户的独立目录
这一步很关键。后面给外部同事开的账号,只绑定 /srv/sftpgo/exchange/partner01,不要绑定整块 NAS 目录,也不要绑定你的照片、备份、Docker 配置目录。
第二步:编写 Docker Compose 文件
在 /opt/sftpgo 下创建 docker-compose.yml:
cd /opt/sftpgo
sudo tee docker-compose.yml > /dev/null <<'EOF'
services:
sftpgo:
image: drakkan/sftpgo:latest
container_name: sftpgo
restart: unless-stopped
ports:
- "127.0.0.1:8080:8080"
- "127.0.0.1:8081:8081"
environment:
SFTPGO_HTTPD__BINDINGS__0__PORT: "8080"
SFTPGO_HTTPD__BINDINGS__0__ADDRESS: "0.0.0.0"
SFTPGO_HTTPD__BINDINGS__0__ENABLE_WEB_ADMIN: "true"
SFTPGO_HTTPD__BINDINGS__0__ENABLE_WEB_CLIENT: "true"
SFTPGO_HTTPD__BINDINGS__1__PORT: "8081"
SFTPGO_HTTPD__BINDINGS__1__ADDRESS: "0.0.0.0"
SFTPGO_HTTPD__BINDINGS__1__ENABLE_WEB_ADMIN: "false"
SFTPGO_HTTPD__BINDINGS__1__ENABLE_WEB_CLIENT: "true"
volumes:
- /srv/sftpgo/config:/var/lib/sftpgo
- /srv/sftpgo/exchange:/srv/sftpgo/exchange
EOF
这个 Compose 文件里有两个 Web 端口:
8080:本机管理入口,用来创建用户、设置权限;8081:只启用 WebClient,不启用 Web 管理后台,用来临时映射给外部同事。
并且两个端口都只绑定在 127.0.0.1:
ports:
- "127.0.0.1:8080:8080"
- "127.0.0.1:8081:8081"
这表示局域网里的其他机器不能直接访问这两个端口。需要外网临时访问时,我们只用 cpolar 映射 8081,不映射 8080。
第三步:启动 SFTPGo
执行:
cd /opt/sftpgo
sudo docker compose up -d
查看容器状态:
sudo docker compose ps
正常会看到 sftpgo 处于运行状态。
再看日志:
sudo docker logs --tail=80 sftpgo
本机测试 Web 入口:
curl -I http://127.0.0.1:8080
curl -I http://127.0.0.1:8081
能返回 HTTP 响应头,就说明 Web 服务已经起来了。
第四步:初始化管理员账号
在服务器本机浏览器打开:
http://127.0.0.1:8080
第一次进入 SFTPGo Web Admin,会要求创建管理员账号。
建议这样设置:
- 管理员用户名不要用
admin; - 密码至少 16 位,包含大小写字母、数字、符号;
- 管理员账号只自己使用,不发给外部同事;
- 管理入口
8080不做公网映射。
初始化完成后,用管理员账号登录 Web Admin。
第五步:创建临时文件交换用户
进入 SFTPGo Web Admin 后,创建用户:
Users -> Add user
示例配置:
Username: partner01
Password: 使用随机强密码
Status: Active
Filesystem provider: Local filesystem
Home dir: /srv/sftpgo/exchange/partner01
权限建议按需求给,不要默认全开。
如果对方只需要下载文件:
Permissions: list, download
如果对方需要上传文件:
Permissions: list, upload, overwrite, create_dirs
如果对方只是临时上传,不建议给删除权限。这样即使对方误操作,也不会把目录里的文件删掉。
创建完成后,回到服务器确认目录权限:
sudo chown -R 1000:1000 /srv/sftpgo/exchange/partner01
sudo chmod -R u+rwX,g-rwx,o-rwx /srv/sftpgo/exchange/partner01
chmod 这条命令的含义是:目录所有者可读写进入,组和其他用户无权限。它不是 WebClient 权限的替代品,而是本地文件系统层面的兜底。
第六步:本地验证 WebClient 上传下载
在本机打开 WebClient:
http://127.0.0.1:8081
用刚创建的用户登录:
Username: partner01
Password: 你给 partner01 设置的密码
先做下载测试。
在服务器里放一个测试文件:
echo "hello from sftpgo" | sudo tee /srv/sftpgo/exchange/partner01/readme.txt > /dev/null
sudo chown 1000:1000 /srv/sftpgo/exchange/partner01/readme.txt
刷新 WebClient,应该能看到 readme.txt,点击可以下载。
再做上传测试:
- 在 WebClient 里点击上传;
- 上传一个小文件,例如
test.txt; - 回到服务器检查文件是否落到目录里:
sudo ls -lah /srv/sftpgo/exchange/partner01
如果文件能上传、能下载,这个临时文件交换账号就已经可用了。
第七步:用 cpolar 临时映射 WebClient
到这里,SFTPGo 只在本机可访问。外部同事还打不开。
临时外网访问可以用 cpolar,把本地 8081 映射成一个公网 HTTPS 地址。重点是:只映射 WebClient 端口 8081,不要映射管理端口 8080,更不要映射 NAS 后台。
如果服务器已经安装并登录 cpolar,直接执行:
cpolar http 8081
命令启动后,终端会显示一个公网访问地址,形式类似:
https://xxxx.cpolar.top
把这个地址发给外部同事,让对方使用 partner01 的账号密码登录。
如果你更习惯用 cpolar Web UI,可以在服务器本机打开:
http://127.0.0.1:9200
然后创建 HTTP 隧道:
协议:HTTP
本地地址:127.0.0.1
本地端口:8081
创建后,在 cpolar 的隧道列表里复制公网地址。
这里不要填 8080。8080 是管理入口,里面有用户管理和系统配置,不应该给外部人员访问。
第八步:外部同事访问测试
给外部同事发送三样东西:
访问地址:https://xxxx.cpolar.top
用户名:partner01
密码:单独通过另一种渠道发送
说明:只用于本次文件收发,用完会关闭
建议不要把地址、用户名、密码放在同一条消息里。比如地址发 IM,密码电话或另一个聊天工具发。
让对方测试:
- 打开 cpolar 公网地址;
- 进入 SFTPGo WebClient 登录页;
- 输入
partner01和密码; - 上传一个小文件;
- 下载你提前放好的
readme.txt; - 你在服务器上确认文件是否出现。
服务器端检查:
sudo ls -lah /srv/sftpgo/exchange/partner01
测试完成后,如果只是一次性收发文件,立刻做两件事:
- 在 SFTPGo Web Admin 里禁用
partner01; - 停止 cpolar 隧道。
如果是前台运行的 cpolar http 8081,在终端按:
Ctrl + C
如果是在 cpolar Web UI 创建的隧道,就在 Web UI 里停止对应隧道。
安全边界:这几条不要省

这套方案的安全感,来自“只暴露必要入口”和“只给必要权限”。不要因为它能跑通,就把边界放大。
1. 不要映射整块 NAS
不要把 SFTPGo 用户的 Home dir 设置成:
/volume1
/mnt/nas
/srv
/home
/
应该给每个外部人员单独建目录,例如:
/srv/sftpgo/exchange/partner01
/srv/sftpgo/exchange/customer-a
/srv/sftpgo/exchange/project-x-upload
2. 不要开放管理员后台
本文把管理入口放在 8080,WebClient 放在 8081。cpolar 只映射:
cpolar http 8081
不要执行:
cpolar http 8080
3. 临时账号用完就禁用
文件收发结束后,在 SFTPGo Web Admin 里把用户改成禁用状态。下次需要再启用,或者重新建一个新账号。
4. 密码要强,最好单次使用
不要用:
123456
password
company2026
partner01
建议用密码管理器生成 16 位以上随机密码。
5. 不要传高度敏感文件
临时文件交换站适合传普通协作文件、安装包、日志、素材。涉及身份证、合同原件、财务数据、客户隐私、密钥文件时,不要直接用这种临时公网方式裸传。
6. 用完关闭隧道
cpolar 的价值在于“按需临时打开”。文件收发结束后就关闭隧道,不要把临时入口长期挂在公网。
常见问题排查
1. 容器启动失败
先看状态:
cd /opt/sftpgo
sudo docker compose ps
再看日志:
sudo docker logs --tail=120 sftpgo
常见原因:
8080或8081已被占用;- Compose 文件缩进错误;
/srv/sftpgo/config没有写入权限;- Docker 服务没有启动。
检查端口占用:
sudo lsof -iTCP:8080 -sTCP:LISTEN
sudo lsof -iTCP:8081 -sTCP:LISTEN
如果端口被占用,把 Compose 里的宿主机端口换掉,例如把 8081 改成 18081,cpolar 也跟着映射新端口。
修改后重启:
cd /opt/sftpgo
sudo docker compose down
sudo docker compose up -d
2. Web 页面打不开
先在服务器本机测试:
curl -I http://127.0.0.1:8080
curl -I http://127.0.0.1:8081
如果本机都打不开,问题在 SFTPGo 或 Docker,不在 cpolar。
继续检查:
sudo docker ps --filter name=sftpgo
sudo docker logs --tail=80 sftpgo
如果本机能打开,但局域网其他机器打不开,这是正常的。本文故意把端口绑定在 127.0.0.1,避免局域网直接访问。
3. 登录失败
检查 4 件事:
- 用户名是否写错;
- 密码是否复制时带了空格;
- 用户状态是否 Active;
- 是否用管理员账号登录了 WebClient,或用普通用户登录了 Web Admin。
本文外部同事应该访问的是:
http://127.0.0.1:8081
公网时访问的是 cpolar 映射出来的 8081 地址。
4. 目录权限不对
如果 WebClient 登录后看不到文件,或者上传时报错,先看目录权限:
sudo ls -ld /srv/sftpgo/exchange/partner01
sudo ls -lah /srv/sftpgo/exchange/partner01
重新设置目录归属:
sudo chown -R 1000:1000 /srv/sftpgo/exchange/partner01
sudo chmod -R u+rwX,g-rwx,o-rwx /srv/sftpgo/exchange/partner01
然后重新登录 WebClient 测试。
5. 外网地址打不开
先确认本地 WebClient 能打开:
curl -I http://127.0.0.1:8081
再确认 cpolar 映射的是 8081:
cpolar http 8081
如果你用的是 cpolar Web UI,检查隧道配置:
协议:HTTP
本地地址:127.0.0.1
本地端口:8081
不要填错成 8080,也不要填成容器内部 IP。
如果公网地址之前能打开,后来打不开,重新启动一次隧道并复制新的公网地址。免费随机地址会变化,不要继续使用旧地址。
6. 上传失败
上传失败通常有三类原因。
第一类:SFTPGo 用户权限不够。
在用户权限里确认至少包含:
list, upload
如果需要覆盖同名文件,再加:
overwrite
如果需要创建目录,再加:
create_dirs
第二类:本地目录不可写。
执行:
sudo chown -R 1000:1000 /srv/sftpgo/exchange/partner01
sudo chmod -R u+rwX,g-rwx,o-rwx /srv/sftpgo/exchange/partner01
第三类:文件太大或网络中断。
先用 1MB 以下的小文件测试。如果小文件能上传,大文件失败,再检查浏览器、网络稳定性和服务器磁盘空间:
df -h /srv/sftpgo/exchange
7. 文件权限看起来异常
通过 WebClient 上传的文件属于容器内运行用户,对应宿主机上通常显示为 UID 1000。
查看:
sudo ls -lah /srv/sftpgo/exchange/partner01
如果你还要让宿主机上的其他服务读取这些文件,可以把后续处理脚本也放在同一用户权限下运行,或者在处理前调整属主。不要为了省事直接给整个目录 777。
收尾:一次临时收发的标准动作
一次外部文件交换结束后,我建议按这个顺序收尾:
1. 确认文件已经收齐或发完
2. 在 SFTPGo Web Admin 禁用临时用户
3. 停止 cpolar 隧道
4. 把文件从 exchange 目录转移到内部长期存储
5. 清空临时目录
清空临时目录前先确认路径:
sudo find /srv/sftpgo/exchange/partner01 -maxdepth 1 -type f -print
确认无误后再删除文件:
sudo find /srv/sftpgo/exchange/partner01 -maxdepth 1 -type f -delete
不要对不熟悉的目录执行 rm -rf,尤其不要在 NAS 挂载目录里随手复制删除命令。
小结
这套方案的核心不是“把文件服务暴露到公网”,而是把暴露范围压到最小:
- SFTPGo 负责文件交换;
- 每个外部人员一个低权限账号;
- 每个账号一个独立目录;
- WebClient 负责临时上传下载;
- cpolar 只在需要时映射 WebClient;
- 管理后台和 NAS 后台都不对外开放。
如果只是临时给同事收发文件,这比直接开放 NAS 后台安全得多,也比临时搭一个共享目录更可控。
你可以按本文先跑一遍本地流程,再开 cpolar 做外网测试。卡住的话,留言说清楚你卡在哪一步:Docker 启动、目录权限、账号权限、外网访问,还是上传失败。我会按你的报错和截图帮你逐项排查。
更多推荐


所有评论(0)