
做了这么多年服务器运维我隔三差五就会被人拉到跟前问怎么给同事搭一个能传文件、但又不用装乱七八糟FTP服务端的地方这种需求在CentOS 7上我基本闭着眼睛选SFTP。因为它是基于SSH的文件传输协议系统自带的openssh就能提供服务不需要额外安装vsftpd这类组件加密传输、单端口、权限还直接沿用系统账号比传统FTP省心太多。这篇文章我就从安装配置、客户端使用、高频报错到安全加固把我在真实环境里踩过的坑和验证过可行的方案完整写一遍。不管你是刚接手服务器的新人还是被“收到太大的SFTP包”这类报错搞到头疼的老手照着做基本都能搞定。1. 动手之前SFTP到底是什么为什么多数场景都比FTP靠谱1.1 一句话理解SFTP它就是“披着SSH外壳的文件传输协议”很多人第一次听到SFTP会把它和FTP混在一起其实两者完全不同。SFTP的全称是SSH File Transfer Protocol它不是一个独立运行的服务而是复用OpenSSH的SSH连接来传输文件。默认端口和SSH一样都是22客户端连上来之后通过SSH隧道内嵌的sftp子系统来列目录、上传下载。也就是说只要你服务器上装了openssh-server就已经自带SFTP能力了根本不需要再单独装一个FTP服务端。这里有个关键认知SFTP走的是SSH协议所以它的安全性建立在SSH的基础之上。用户登录时用的是系统账号的密码或者SSH密钥账号权限和系统用户完全对应。这意味着你能精确控制某个人能传哪个目录、能不能登录Shell而文件在网络上传输时又是全程加密的。对于企业内部给同事开传输通道、给客户交付文件、或者自己管理服务器数据备份这几乎是最省事的方式。1.2 和FTP、SCP摆在一起对比选择理由就出来了我在实际选型时有时会有人问“那直接用FTP不就行吗”“SCP不也能传文件”这里我把三者的核心差异列出来对比看就明白了。对比项SFTPFTPSCP协议基础SSHFTP/TCP 21SSH传输加密全程加密默认明文FTPS才加密全程加密服务端系统自带openssh需要安装vsftpd等系统自带openssh默认端口222122防火墙规则只需放行SSH端口需要放行多个复杂端口只需放行SSH端口目录交互支持list/rename/delete等支持只支持推拉文件用户管理直接用系统账号可虚拟账号或系统账号系统账号FTP最麻烦的是主动/被动模式、数据端口范围、防火墙放行规则这些老难题尤其是服务器有安全组或者云防火墙时要开一串端口特别烦。SCP虽然简单但它只适合单向传文件没法方便地列目录、删除、重命名交互体验远不如SFTP。所以如果只是日常文件传输SFTP是综合成本最低的选择。1.3 先想清楚需求再动手这里要搭一个什么样的SFTP环境配置之前最好先把需求定义清楚。我这次的项目场景很典型给团队里的同事开几个账号每个人只能在自己的目录里上传下载文件不能登录Shell执行命令不能看到别人的目录更不能到处乱跑。这种需求恰恰是SFTP最容易实现的高频场景。技术方案上我会用OpenSSH自带的 internal-sftp 作为sftp子系统然后用ChrootDirectory把每个用户禁锢在指定目录里。整个配置不需要装任何额外软件只改一个sshd_config文件、建几个用户和目录就能完成。2. CentOS 7上从零搭建SFTP照着敲就行2.1 检查环境确认系统自带的SSH组件都齐CentOS 7默认会安装openssh-server你可以先用命令确认一下版本和sftp组件是否都在ssh -V rpm -qa | grep openssh正常情况下能看到openssh-server对应的版本号。然后看sftp子系统文件是否存在ls -l /usr/libexec/openssh/sftp-server这一步不是废话。我在线上遇过有人把openssh-server卸载过、或者系统是从精简模板装的sftp-server这个二进制可能不在。如果不存在可以先通过 yum 装回来yum install -y openssh-server确认之后再检查sshd服务本身是正常启动的systemctl status sshd只要sshd服务在跑说明SSH通道是好的接下来就是在这个基础上调整sftp配置。2.2 创建专用用户组和用户Shell必须选nologin我习惯的做法是先建一个统一的用户组比如sftpusers然后把所有需要开通传输账号的人都塞进这个组后面sshd_config里只需要写一个Match Group就能覆盖所有人非常省心。groupadd sftpusers然后创建基础目录比如 /data/sftp 作为所有sftp用户目录的根路径mkdir -p /data/sftp chown root:root /data/sftp chmod 755 /data/sftp接下来给用户zhangsan建目录和账号mkdir -p /data/sftp/zhangsan useradd -g sftpusers -s /sbin/nologin -d /data/sftp/zhangsan zhangsan echo 初始密码 | passwd --stdin zhangsan这里有几个细节要说明。第一Shell指定成 /sbin/nologin 是防止用户用SSH登录成Shell这是一个双保险。第二用户的家目录我直接指定成 /data/sftp/zhangsan而这个目录我已经提前建好且用户还没有权限接管后面还要手动chown成root。如果目录不存在useradd会自动帮用户建目录并且把属主设成用户自己这样sshd的ChrootDirectory检测会直接报错所以我宁可自己先建好目录再建用户权限完全可控。2.3 修改sshd_config一个Match块管住所有SFTP用户配置文件在 /etc/ssh/sshd_config改之前先备份cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date %Y%m%d)然后用vim打开找到默认的这行#Subsystem sftp /usr/libexec/openssh/sftp-server把它替换成Subsystem sftp internal-sftpinternal-sftp是sshd内置的sftp服务实现相比调用外部二进制sftp-server配置Match组时更方便也更安全推荐生产环境用它。然后在文件末尾追加这一段Match Group sftpusers ChrootDirectory /data/sftp/%u ForceCommand internal-sftp AllowTcpForwarding no X11Forwarding no逐行解释一下。Match Group sftpusers表示以下配置只对sftpusers组生效ChrootDirectory会把用户禁锢在 /data/sftp/用户名 这个目录里用户登录后看到的“/”就是这里看不到服务器其他路径ForceCommand internal-sftp强制该组用户连接时必须启动sftp子系统即使他用SSH客户端请求一个shell也会被强制掰到sftp这是挡住Shell登录的关键AllowTcpForwarding no和X11Forwarding no则是顺带把SSH隧道转发和图形界面转发关掉避免用户借通道做端口转发之类的操作。改完之后先检查语法再平滑重启sshd -t systemctl restart sshdsshd -t这一步千万别省。我见过有人改完配置文件直接重启结果选项写错导致SSH服务起不来人还在机房外连都连不回去了。先检查语法过一遍再重启永远是对的。2.4 目录权限是最大的隐形杀手属主和权限这么设才稳跑通配置的人很多能一次跑通的人不多九成问题都出在目录属主和权限上。sshd对于ChrootDirectory的目录有强制要求整个路径上每一级目录都必须是root所有而且不能被其他用户写。注意不是只有最后一级而是 /data、/data/sftp、/data/sftp/zhangsan 这些层级都不能让普通用户有写权限。所以我前面的配置里 /data 和 /data/sftp 都是root:root且755这没问题。但 /data/sftp/zhangsan 这个目录就有点讲究了它作为chroot的根目录同样必须是root所有、不可写chown root:sftpusers /data/sftp/zhangsan chmod 750 /data/sftp/zhangsan这里权限我用的750。有的人喜欢755也没问题只要确保普通用户对这个目录本身没有写权限就行。但这会带来一个问题chroot根目录不能写用户连进去之后只能在“/”下面看却没法创建文件那传输功能就废了。所以正确的做法是在chroot根目录里面再创建一个普通用户自己所有的子目录专门用来读写mkdir -p /data/sftp/zhangsan/upload chown zhangsan:sftpusers /data/sftp/zhangsan/upload chmod 750 /data/sftp/zhangsan/upload这样用户zhangsan通过SFTP登录后会看到根目录下有一个upload文件夹他能往upload里随便传东西但动不了根目录本身。这个设计思路在实际使用时非常重要我给团队开账号时都会直接在群公告里说明登录后请进入upload目录操作。到这里一个最基础的SFTP环境已经好了。可以用命令行验证一下sftp zhangsan127.0.0.1如果连接后能进入sftp提示符并看到upload目录说明服务端配置成功。3. 客户端连接实测命令行、Tabby和WinSCP都安排上3.1 命令行sftp最常用的命令和几条实用技巧服务端搭好了客户端这边先从命令行开始。Linux和macOS都自带sftp客户端Windows 10以上系统也内置了OpenSSH的sftp可以直接在PowerShell里用。连接命令很简单sftp 用户名服务器IP如果SSH端口改了用-P参数指定端口注意是大写的Psftp -P 22222 用户名服务器IP连接成功后提示符会变成 sftp 说明已经进入了sftp交互模式。常用操作我整理成了一张表。命令作用pwd查看远端当前目录lpwd查看本地当前目录ls列出远端目录内容lls列出本地目录内容cd 目录切换远端目录lcd 目录切换本地目录put 本地文件上传文件到当前远端目录get 远端文件下载文件到本地当前目录mput 本地文件批量上传mget 远端文件批量下载chmod 权限 文件修改远端文件权限bye / exit / quit退出sftp几个小技巧。下载目录想整目录拉回来用 get -r 远端目录上传目录想整目录推上去用 put -r 本地目录。实际用的时候get指令下载文件时还可以在最后跟一个本地路径比如 get /home/user/test.sh /tmp/这样能直接把文件放到指定位置不用先lcd切目录。批量传文件时mget支持通配符例如 mget *.log一次拿完所有日志文件这条我在排查服务器问题时经常用相当顺手。3.2 Tabby连上SSH却找不到SFTP按钮问题多半在这里热词里有“tabby使用ssh连接到服务器后怎么没有sftp按钮”这个问题我确实也被问过很多次。Tabby是一个比较流行的现代终端工具它本身自带SFTP文件管理面板不需要额外插件。连上SSH之后窗口右侧通常会有一个竖排的侧边栏里面有一个“SFTP”标签点一下就会展开远端文件目录直接支持上传下载。如果你连上之后发现没有这个按钮最可能的原因是右侧边栏被折叠了。试着把鼠标移到窗口最右侧看有没有一个呼出侧边栏的小箭头或者直接看顶部菜单里的“View”类目找Sidebar相关的切换选项。有些版本需要点击连接页签右上角的展开图标才能看到文件面板。还有一个容易被忽视的原因你新建连接时如果选的是Raw连接或者其他协议类型而不是SSH连接那自然不会有SFTP面板。只有通过SSH方式连上服务端Tabby才知道要走sftp子系统。如果确认是SSH连接还是没有SFTP按钮那就得检查服务端本身能不能正常提供sftp子服务。最简单的验证方法就是你用命令行sftp连一下服务端如果能进去说明服务端没问题问题在Tabby界面操作上如果命令行也进不去那就是服务端配置有问题回到第2章排查。3.3 WinSCP和FileZilla连接时的注意点图形化工具里Windows用户用得最多的是WinSCP跨平台比较多的是FileZilla。连接时的核心参数其实都一样文件协议要选“SFTP”或者“SFTP - SSH File Transfer Protocol”而不是普通FTP主机名填服务器IP或域名端口填22如果服务端改了SSH端口就填对应端口用户名密码填你创建的sftp账号。WinSCP这里有个小坑连接成功后如果发现中文文件名乱码需要在站点设置里把字符编码改成UTF-8具体位置在“高级” - “环境” - “文件名UTF-8编码”。FileZilla一般默认UTF-8但遇到老系统也可能要手动选择。如果你用密钥登录WinSCP会要求把OpenSSH格式的私钥转换成PPK格式导入时按提示操作就行。FileZilla则更宽容一些直接加载OpenSSH格式私钥通常就能用。还有一点WinSCP默认会记住密码如果服务器策略比较严格可以关闭会话保存里的缓存密码选项避免被同事顺手连上。4. 高频报错排查实录从“收到了太大的SFTP包”开始讲4.1 收到太大的SFTP包原因是握手时混进了几句欢迎词“收到了太大的SFTP包。请求的最大包长度为xxxxxx。包长度为xxxxxx。”这个报错在WinSCP、FileZilla和Tabby里都见过表现形式略有不同但本质原因只有一个客户端在和服务端建立sftp会话时SSH通道里先吐出来了一段正常的文本输出而不是sftp协议要求的版本包。sftp客户端把这段文本当成协议包去解析结果包长度变得异常巨大于是提示包太大直接断开。那这段文本是从哪来的最常见的来源是/etc/motd和/etc/issue.net。有些系统会在用户登录后展示一段欢迎信息比如“Welcome to the server”或者各种系统提示。如果sshd_config里配置了Banner /etc/xxx这种选项SSH认证成功之后也会先输出这个文本。SFTP客户端可不认这些它期望的第一条数据是SFTP版本号结果收到的是字符串一解析就爆。排查方法ssh -v 用户名服务器IP看认证通过后是否输出了非协议文本。或者直接查看系统文件cat /etc/motd cat /etc/issue.net grep -i banner /etc/ssh/sshd_config解决办法分几种。第一是直接清空motd文件内容用 echo 覆盖成空文件echo /etc/motd第二是把sshd_config里的Banner和PrintMotd相关配置去掉再重启sshdsed -i s/^Banner/#Banner/ /etc/ssh/sshd_config systemctl restart sshd这里有个经验有些发行版的pam_motd模块会在PAM验证阶段再次输出motd光在sshd_config里设PrintMotd no可能压不住干脆清空motd文件内容最直接。另外如果你在用户目录的.bashrc或.bash_profile里写了echo语句也不会影响sftp——因为sftp用户被ForceCommand强制走internal-sftp根本不会执行shell登录脚本。但如果是普通的SSH用户再手动启动sftp那就可能触发这种情况同样清理掉相关echo即可。4.2 Connection closed十个里有九个是chroot目录配置错了另一个高频报错是密码输对了服务端认证通过了然后连接立刻被关闭WinSCP提示“连接被关闭”sshd的系统日志里通常能看到类似这样的记录fatal: bad ownership or modes for chroot directory /data/sftp/zhangsan翻译过来就是chroot目录的属主或权限不符合要求。sshd对ChrootDirectory的要求非常死板这个目录以及它的所有父目录属主都必须是root而且对普通用户不能有写权限。很多新手照着教程建了目录但没注意useradd的时候系统已经把这个目录的属主设置成了用户本身于是sshd一看目录是普通用户的直接拒绝chroot连接就断了。排查命令很简单一眼就能看出来ls -ld /data /data/sftp /data/sftp/zhangsan正确的结果应该是每一层都是root所有且权限不是777或775这类让其他用户可写的类型。如果发现zhangsan目录属主变成了zhangsan执行chown root:sftpusers /data/sftp/zhangsan chmod 750 /data/sftp/zhangsan然后重启sshd再连一次。这个问题解决掉大部分“连上就断”的故障就消失了。4.3 上传文件报权限拒绝八成没建用户自己的上传目录很多人配置好了sftp用命令行连接也正常目录列表也能看到但一上传文件就报“Permission denied”。我自己刚开始配的时候也栽过这个跟头原因就是chroot根目录必须root所有、不可写用户当然没有写入权限而我又没有在根目录下面给用户建一个可写的upload子目录。解决办法就是在chroot的根目录下建一个属于该用户自己的子目录mkdir -p /data/sftp/zhangsan/upload chown zhangsan:sftpusers /data/sftp/zhangsan/upload chmod 750 /data/sftp/zhangsan/upload配置完之后用户通过SFTP登录看到的就是一个带upload文件夹的根目录往upload里上传下载都很正常。如果用户反馈“看不到目录”或“空空的”也要先想到是不是我忘了建upload目录。4.4 其他常见问题速查表除了上面几个大坑我把日常巡检和答疑中经常碰到的问题也整理成一张表方便你直接对号入座。现象可能原因解决办法连接超时或端口不通云安全组/防火墙没放行SSH端口在安全组和firewalld中放行对应端口密码正确但登录失败用户被锁定或pam配置限制用faillock --reset清锁定状态能连上但不能进入sftp面板服务端子系统配置损坏检查Subsystem行是否正确sshd -t测试登录后立刻断开ChrootDirectory目录属主不是rootchown root:rootchmod 750无法上传文件缺少用户所有和可写目录在chroot根目录下建upload子目录收到太大的SFTP包motd/banner文本干扰协议握手清空motd移除Banner配置客户端中文乱码编码不是UTF-8WinSCP/FileZilla设置UTF-8Locked out自己sshd_config写错导致sshd没起来用VNC/控制台或启动参数恢复sshd还遇到过一种情况有人修改了sshd的Port到高位端口却忘了在SELinux里给这个新端口打标签导致从外部连不上本地测试又一切正常。这个和sftp本身关系不大但排查起来很迷惑放在速查表里提醒一下。5. 安全加固和日常维护的几条建议5.1 改端口之前先把防火墙和SELinux想清楚默认的22端口常年被扫描很多团队为了减少噪音会把SSH和SFTP服务改到高位端口比如22222。做法很简单sed -i s/^#Port 22/Port 22222/ /etc/ssh/sshd_config systemctl restart sshd但改了端口之后有两个地方必须同步处理。第一个是firewalld防火墙只放行新端口旧端口是否保留看你需求firewall-cmd --permanent --add-port22222/tcp firewall-cmd --reload第二个是SELinuxCentOS 7默认enforcing下新端口没有打上ssh_port_t标签外部流量会被拒绝本地连却没问题非常容易误判成防火墙问题。用semanage把端口加入SELinux策略yum install -y policycoreutils-python semanage port -a -t ssh_port_t -p tcp 22222如果你不想折腾SELinux也可以临时 setenforce 0 测试但从生产安全角度看不建议永久关闭SELinux。5.2 只让SFTP干活别让它干别的前面Match块里已经加了ForceCommand internal-sftp、AllowTcpForwarding no、X11Forwarding no这相当于给sftp用户上了三道锁。还有一条可以考虑限制该组用户只能从特定IP段访问。在Match Group段里再加一行Match Group sftpusers ChrootDirectory /data/sftp/%u ForceCommand internal-sftp AllowTcpForwarding no X11Forwarding no Match Address 192.168.10.*注意这个写法Match Address要放在Match Group之下表示这个组里只允许192.168.10网段访问。如果客户端来自其他网段即使账号密码正确也会被拒绝。对于只给内网同事使用的场景这条规则很实用。另外如果你只打算用密钥认证来登录sftp也可以在sshd_config全局关闭密码登录PasswordAuthentication no但这条会影响普通SSH用户所以要和同事确认不会误伤其他人。更稳妥的方式是在Match块里针对sftpusers组单独设置Match Group sftpusers PasswordAuthentication no不过要注意如果把全局PasswordAuthentication设置成yes而又在Match块里no那逻辑是能生效的。具体执行前一定先sshd -t检查。5.3 批量创建用户与目录一个脚本打包搞定给一个人开账号是命令敲敲就好给十个人开账号就得写脚本了。我平时给团队批量开通sftp账号直接跑一段循环脚本#!/bin/bash SFTP_BASE/data/sftp groupadd sftpusers 2/dev/null for user in zhangsan lisi wangwu; do mkdir -p $SFTP_BASE/$user/upload useradd -g sftpusers -s /sbin/nologin -d $SFTP_BASE/$user $user 2/dev/null echo ${user}初始密码 | passwd --stdin $user chown root:sftpusers $SFTP_BASE/$user chmod 750 $SFTP_BASE/$user chown $user:sftpusers $SFTP_BASE/$user/upload chmod 750 $SFTP_BASE/$user/upload done systemctl restart sshd脚本执行完之后sshd_config里那个Match Group sftpusers已经覆盖了新增用户不需要再改配置文件非常方便。用户离职时用 userdel -r 用户名 删掉用户和家目录清理得也干净。日志和审计这方面sftp的登录事件会记录在 /var/log/secure 里每次密码验证成功都能看到。但是单个文件的get、put操作默认不会记录到系统日志如果公司有审计需求需要额外上auditd或者文件传输审计工具这一点可以在前期需求阶段就明确避免最后补坑。配置完成之后我个人的习惯是先拿一个测试账号完整走一遍流程命令行sftp连一次WinSCP传一个小文件下载一个文件再从Tabby里看看SFTP面板是否正常。整套流程验证没问题再往群里发账号和密码。不要小看这个验证步骤它真的能帮你省掉后面大量“为什么我连不上”的求助消息。如果后续人多了需要扩展目录结构给每个项目组单独分目录或者需要给某个客户开一个只读账号本质都是在这个基础上改目录权限和Match规则。SFTP这套机制的好处就是它足够灵活系统账号、目录权限、SSH规则这些底层能力都在只要理解了ChrootDirectory和目录属主的逻辑很多衍生需求都能很快落地。