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:8080SFTPGo WebClient 入口http://127.0.0.1:8081本地文件目录/srv/sftpgo/exchangeDocker 项目目录/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.ymlcd /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.1ports: - 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 --tail80 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 urwX,g-rwx,o-rwx /srv/sftpgo/exchange/partner01chmod这条命令的含义是目录所有者可读写进入组和其他用户无权限。它不是 WebClient 权限的替代品而是本地文件系统层面的兜底。第六步本地验证 WebClient 上传下载在本机打开 WebClienthttp://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-upload2. 不要开放管理员后台本文把管理入口放在8080WebClient 放在8081。cpolar 只映射cpolar http 8081不要执行cpolar http 80803. 临时账号用完就禁用文件收发结束后在 SFTPGo Web Admin 里把用户改成禁用状态。下次需要再启用或者重新建一个新账号。4. 密码要强最好单次使用不要用123456 password company2026 partner01建议用密码管理器生成 16 位以上随机密码。5. 不要传高度敏感文件临时文件交换站适合传普通协作文件、安装包、日志、素材。涉及身份证、合同原件、财务数据、客户隐私、密钥文件时不要直接用这种临时公网方式裸传。6. 用完关闭隧道cpolar 的价值在于“按需临时打开”。文件收发结束后就关闭隧道不要把临时入口长期挂在公网。常见问题排查1. 容器启动失败先看状态cd /opt/sftpgo sudo docker compose ps再看日志sudo docker logs --tail120 sftpgo常见原因8080或8081已被占用Compose 文件缩进错误/srv/sftpgo/config没有写入权限Docker 服务没有启动。检查端口占用sudo lsof -iTCP:8080 -sTCP:LISTEN sudo lsof -iTCP:8081 -sTCP:LISTEN如果端口被占用把 Compose 里的宿主机端口换掉例如把8081改成18081cpolar 也跟着映射新端口。修改后重启cd /opt/sftpgo sudo docker compose down sudo docker compose up -d2. Web 页面打不开先在服务器本机测试curl -I http://127.0.0.1:8080 curl -I http://127.0.0.1:8081如果本机都打不开问题在 SFTPGo 或 Docker不在 cpolar。继续检查sudo docker ps --filter namesftpgo sudo docker logs --tail80 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 urwX,g-rwx,o-rwx /srv/sftpgo/exchange/partner01然后重新登录 WebClient 测试。5. 外网地址打不开先确认本地 WebClient 能打开curl -I http://127.0.0.1:8081再确认 cpolar 映射的是8081cpolar 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 urwX,g-rwx,o-rwx /srv/sftpgo/exchange/partner01第三类文件太大或网络中断。先用 1MB 以下的小文件测试。如果小文件能上传大文件失败再检查浏览器、网络稳定性和服务器磁盘空间df -h /srv/sftpgo/exchange7. 文件权限看起来异常通过 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 启动、目录权限、账号权限、外网访问还是上传失败。我会按你的报错和截图帮你逐项排查。