ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Linux 配置 FTP 服务器实现文件上传下载(vsftpd 完整实战)

Linux 配置 FTP 服务器实现文件上传下载(vsftpd 完整实战)

前言


vsftpd(Very Secure FTP Daemon)是 Linux 上最主流的 FTP 服务端,特点是轻量、稳定、安全性好。适合这些场景:



  • 给外包/客户开个账号传文件

  • 老设备、老系统只支持 FTP

  • 内网快速搭个文件中转站


先说句实在话:FTP 是明文协议,账号密码和数据在网上裸奔。除非有历史包袱,否则新项目建议直接用 SFTP(基于 SSH,零配置成本)或 FTPS。本文最后会讲怎么给 vsftpd 加上 TLS 加密。


环境:Rocky Linux 8 / CentOS 7(Ubuntu 差异已标注)




一、安装


# Rocky / CentOS
dnf install -y vsftpd

# Ubuntu / Debian
# apt install -y vsftpd

vsftpd -v # 确认版本,后面有些配置项和版本相关

先备份配置,这步别省:


cp /etc/vsftpd/vsftpd.conf /etc/vsftpd/vsftpd.conf.bak


注意路径差异:CentOS 系在/etc/vsftpd/,Ubuntu 是/etc/vsftpd.conf(没有子目录)。





二、创建 FTP 用户


# -d 指定家目录,-s 指定不可登录的 shell(安全)
useradd -d /data/ftp/ftpuser -s /sbin/nologin ftpuser

# 设置系统密码
passwd ftpuser

# 目录准备
mkdir -p /data/ftp/ftpuser
chown -R ftpuser:ftpuser /data/ftp/ftpuser
chmod 755 /data/ftp/ftpuser


为什么要-s /sbin/nologin?FTP 用户只需要能传文件,不需要能 SSH 登录服务器。给它/sbin/nologin能有效降低被爆破后的危害。但要注意:某些发行版需要把 shell 加入/etc/shells,详见 6.2。





三、配置 vsftpd.conf


完整配置如下(同样给精简可用的版本):


# ========== 基本设置 ==========
# 禁止匿名登录(重要!默认可能是 YES)
anonymous_enable=NO

# 允许本地用户登录
local_enable=YES

# 允许写操作(上传、删除、改名都靠它)
write_enable=YES

# 本地用户上传文件的权限掩码,022 = 755
local_umask=022

# ========== 目录与日志 ==========
dirmessage_enable=YES
xferlog_enable=YES
xferlog_std_format=YES
connect_from_port_20=YES

# 以独立模式运行并监听
listen=YES
listen_ipv6=NO

# PAM 认证模块
pam_service_name=vsftpd
userlist_enable=YES

# ========== 禁锢用户在家目录 ==========
# 用户登录后只能在自家目录,无法 cd 到上级
chroot_local_user=YES
allow_writeable_chroot=YES

# ========== 被动模式(NAT/防火墙环境必配)==========
pasv_enable=YES
pasv_min_port=30000
pasv_max_port=30100
# 公网访问时必填,填服务器的公网 IP
# pasv_address=203.0.113.10

核心参数说明




参数说明



anonymous_enable=NO必改项。默认开启匿名访问,等于谁都能传文件

write_enable=YES不开这个,用户只能下载不能上传

chroot_local_user=YES把用户锁在自家目录,防止翻看服务器其他文件

allow_writeable_chroot=YES关键项,见 6.1,不加会直接报错登不上

pasv_min_port/pasv_max_port被动模式端口范围,防火墙要放行这一段

pasv_address服务器在 NAT 后面时,必须填公网 IP





四、启动服务与防火墙


systemctl enable --now vsftpd
systemctl status vsftpd

防火墙:


firewall-cmd --permanent --add-service=ftp
firewall-cmd --permanent --add-port=30000-30100/tcp
firewall-cmd --reload

为什么还要加端口范围?FTP 有两种模式:



  • 主动模式(Active):服务端主动连客户端。客户端在 NAT 后面时基本用不了。

  • 被动模式(Passive):客户端连服务端的随机高端口。现代客户端默认都是被动模式,所以必须放行pasv_min_port~pasv_max_port。


SELinux:


getenforce
setsebool -P ftpd_full_access on # 允许 vsftpd 读写用户家目录



五、验证测试


5.1 服务端自测


ftp localhost
# 输入用户名密码,能登录就说明基本 OK

5.2 Linux 客户端测试


# 方式一:ftp 命令
ftp 192.168.1.10

# 方式二:lftp(更好用,支持被动模式切换)
dnf install -y lftp
lftp -u ftpuser,密码 192.168.1.10

5.3 curl 测试(适合脚本化验证)


# 下载
curl -u ftpuser:密码 ftp://192.168.1.10/test.txt

# 上传
curl -u ftpuser:密码 -T local.txt ftp://192.168.1.10/

# 列目录
curl -u ftpuser:密码 ftp://192.168.1.10/


注意:curl 默认走主动模式,在某些网络环境下会失败。加上--ftp-pasv强制被动模式再试:


curl --ftp-pasv -u ftpuser:密码 ftp://192.168.1.10/

如果加了这个参数就好了,说明是主动/被动模式搞错了,不是服务端问题。



5.4 用 FileZilla 等图形工具


连接时把「传输模式」设为被动,字符集设为UTF-8,中文文件名才不会乱码。




六、常见问题排查(重点)


6.1500 OOPS: vsftpd: refusing to run with writable root inside chroot()


这是配chroot_local_user=YES后最经典的错误。


原因:你把用户禁锢在家目录了,但家目录本身是可写的。用户如果能写自己的"根目录",就能通过上传.ssh之类的目录实现越权,所以 vsftpd 拒绝启动。


解法一(推荐):确认 vsftpd 版本 ≥ 3.0,加上


allow_writeable_chroot=YES

解法二(更安全,不依赖配置项):把家目录设成不可写,另建子目录给用户写:


chmod 755 /data/ftp/ftpuser
mkdir /data/ftp/ftpuser/upload
chown ftpuser:ftpuser /data/ftp/ftpuser/upload

这样用户能进家目录(只读),但要写东西得进upload子目录。安全性比解法一好。



版本坑:allow_writeable_chroot在 vsftpd 3.0.2 曾被移除,3.0.3 又加回来了。如果你加了这行还报unknown option,说明版本不对,只能用解法二。



6.2530 Login incorrect


这个错误信息很笼统,原因有好几个,按下面顺序排查:


① shell 不在/etc/shells里


grep nologin /etc/shells

如果没输出,说明/sbin/nologin没被列为合法 shell,PAM 会拒绝。加上:


echo /sbin/nologin >> /etc/shells

② 用户被列入了黑名单


cat /etc/vsftpd/ftpusers # 这个文件里的用户一律禁止 FTP 登录
cat /etc/vsftpd/user_list # 配合 userlist_enable=YES,默认是黑名单

root默认就在这两个文件里,这是故意的,不要删。你自己的用户如果也在里面,删掉对应行。


③ PAM 配置问题


检查/etc/pam.d/vsftpd,确认pam_shells.so和pam_listfile.so没有误伤。


④ 密码本身错了


先确认能su - ftpuser切换成功,排除密码问题。


6.3 能登录能列目录,但上传失败


检查这三点:


grep write_enable /etc/vsftpd/vsftpd.conf # 是不是 NO
ls -ld /data/ftp/ftpuser # 目录属主对不对
getsebool ftpd_full_access # SELinux 放行了吗

文件系统权限和 SELinux 都要过,和 NFS 一样是两层校验。


6.4 被动模式连不上(能登录但列不出目录 / 一直卡住)


症状:能连上、能认证,但执行ls就卡住或超时。


原因:被动模式的数据端口被防火墙拦了。


# 确认配置生效
grep pasv /etc/vsftpd/vsftpd.conf

# 确认防火墙放行了整个范围
firewall-cmd --list-all | grep -A2 ports

如果服务器在云上(阿里云/腾讯云),别忘了安全组也要放行 30000-30100。这是最容易被忽略的一层。


用抓包定位到底卡在哪:


tcpdump -i any -n port 21 or portrange 30000-30100

6.5 中文文件名乱码


确认客户端用UTF-8编码连接。FileZilla 里:站点管理器 → 字符集 → 强制 UTF-8。


vsftpd 本身在较新版本默认就是 UTF-8,老版本可能需要:


utf8_filesystem=YES



七、进阶:给 FTP 加上 TLS 加密(FTPS)


既然 FTP 是明文的,生产环境强烈建议启用 TLS。


① 生成自签证书(内网够用;公网建议买正式证书)


openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \
-keyout /etc/vsftpd/vsftpd.key \
-out /etc/vsftpd/vsftpd.crt \
-subj "/C=CN/ST=Beijing/L=Beijing/O=MyOrg/CN=192.168.1.10"

chmod 600 /etc/vsftpd/vsftpd.key

② 配置中追加


ssl_enable=YES
allow_anon_ssl=NO
force_local_data_ssl=YES
force_local_logins_ssl=YES
ssl_tlsv1_2=YES
ssl_tlsv1_1=NO
ssl_tlsv1=NO
ssl_sslv2=NO
ssl_sslv3=NO
rsa_cert_file=/etc/vsftpd/vsftpd.crt
rsa_private_key_file=/etc/vsftpd/vsftpd.key
require_ssl_reuse=NO
ssl_ciphers=HIGH

重启:


systemctl restart vsftpd

客户端就要用FTPS(不是 SFTP)连接,并且因为是自签证书,需要选择"信任该证书"。



require_ssl_reuse=NO这行建议加上。某些客户端(尤其是 FileZilla)在 TLS 会话复用上和 vsftpd 有兼容性问题,不加这个可能连不上。





八、安全加固清单




措施做法



禁用匿名anonymous_enable=NO

禁锢目录chroot_local_user=YES+ 不可写家目录

限制登录用user_list白名单,只放需要的用户

禁用 root保持/etc/vsftpd/ftpusers里有 root

加密传输启用 TLS(第七节)

限制来源防火墙 + 云安全组限制源 IP

防爆破配合 fail2ban 监控/var/log/secure

被动端口收窄pasv_min_port/pasv_max_port范围开小一点





九、总结




环节关键点



用户useradd -s /sbin/nologin,shell 要进/etc/shells

核心配置anonymous_enable=NO、write_enable=YES、chroot_local_user=YES

chroot 报错allow_writeable_chroot=YES或改用手法更稳的"不可写家目录 + 子目录"

防火墙放行 ftp +被动端口范围(云服务器还要配安全组)

SELinuxsetsebool -P ftpd_full_access on

排错卡在列目录 = 被动模式端口没通;530 = shell/黑名单/PAM



最后再提醒一次:FTP 明文传输,新项目优先考虑 SFTP。如果必须用 FTP,请务必按第七节把 TLS 打开。




如果这篇帮你少踩了一个坑,点个赞吧。有问题评论区见,报错信息贴全我好判断。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进