# CentOS 7 搭建 vsftpd:匿名用户、本地用户、虚拟用户与 FTPS
1. 服务介绍
vsftpd(Very Secure FTP Daemon)是 Linux 常用 FTP 服务端软件,用于文件上传、下载和目录共享。它支持匿名访问、本地系统用户、基于 PAM 的虚拟用户、目录隔离、被动模式和 TLS 加密,适合内网文件交换、运维文件分发及账号隔离实验。
FTP 使用独立的控制连接和数据连接。部署时不能只检查 TCP 21,还要同时处理被动端口、防火墙、NAT、目录权限和 SELinux。本文基于 CentOS 7,分别配置匿名用户、本地用户、虚拟用户,并给出客户端和服务端验证方法。
2. 准备运行环境
• 服务端:CentOS 7.x,示例地址 10.1.100.101/24。
• 客户端:Windows 或 Linux,与服务器网络互通。
• 操作权限:root 或具备 sudo 权限的管理员账号。
• 软件源:YUM 可用。
• FTP 控制端口:TCP 21。
• 被动数据端口:本文使用 TCP 30000-31000。
• 主配置文件:/etc/vsftpd/vsftpd.conf。
• 主要日志:/var/log/xferlog、systemd journal;启用协议日志后可查看 /var/log/vsftpd.log。
安装服务端和测试工具,并备份原配置:
bash
yum install -y vsftpd ftp lftp db4-utils policycoreutils-python
cp -a /etc/vsftpd/vsftpd.conf /etc/vsftpd/vsftpd.conf.bak.$(date +%F-%H%M%S)
vsftpd -v
3. 相关知识
3.1 主动模式和被动模式
• 主动模式:客户端连接服务器 TCP 21,服务器再从 TCP 20 主动连接客户端。客户端处于 NAT 或防火墙后时容易失败。
• 被动模式:客户端同时发起控制连接和数据连接。服务器返回一个高位端口,客户端连接该端口。现代网络更常用被动模式。
• 被动模式端口必须在 vsftpd.conf、firewalld 和上级 NAT 中保持一致。
3.2 文件权限有两层
vsftpd 配置决定"功能是否允许",Linux 文件权限和 SELinux 决定"系统是否允许"。即使设置 write_enable=YES,目录无写权限或 SELinux 类型不正确,上传仍会失败。
3.3 chroot 目录隔离
chroot_local_user=YES 可把本地用户限制在 FTP 根目录。为减少目录逃逸风险,用户根目录建议由 root 管理且不可写,在根目录下创建用户可写的 upload 子目录。直接让 chroot 根目录可写可能触发 500 OOPS: vsftpd: refusing to run with writable root inside chroot()。
3.4 匿名、本地和虚拟用户
• 匿名用户:通常使用用户名 anonymous 或 ftp,适合公开下载;匿名写入风险高,应只开放单独上传目录。
• 本地用户:直接使用 Linux 系统账号认证,权限由账号和目录属主决定。
• 虚拟用户:账号保存在独立数据库中,通过 PAM 认证,再统一映射到不可登录系统的宿主账号。适合只需要 FTP、无需系统 Shell 的用户。
3.5 FTPS 与 SFTP 不同
FTPS 是 FTP 加 TLS,仍使用 FTP 控制和数据连接;SFTP 是 SSH 子系统,通常使用 TCP 22。两者协议不同,客户端配置不能混用。FTP 明文传输账号和数据,跨不可信网络时应启用 FTPS 或改用 SFTP。
4. 实验步骤
4.1 配置基础服务和被动模式
先写入通用配置。保留原文件中的注释也可以,但不要重复定义相互冲突的参数:
conf
listen=YES
listen_ipv6=NO
anonymous_enable=NO
local_enable=YES
write_enable=YES
local_umask=022
use_localtime=YES
xferlog_enable=YES
xferlog_std_format=YES
dual_log_enable=YES
log_ftp_protocol=YES
connect_from_port_20=YES
pam_service_name=vsftpd
userlist_enable=YES
chroot_local_user=YES
allow_writeable_chroot=NO
pasv_enable=YES
pasv_min_port=30000
pasv_max_port=31000
检查配置并放行端口:
bash
systemctl enable --now vsftpd
firewall-cmd --permanent --add-service=ftp
firewall-cmd --permanent --add-port=30000-31000/tcp
firewall-cmd --reload
systemctl restart vsftpd
若服务器经过 NAT,还应配置 pasv_address 为客户端可访问的地址,并在上级网关映射相同被动端口范围。
4.2 配置匿名用户
建立匿名根目录和单独上传目录。根目录保持不可写,上传目录才授予 ftp 用户写权限:
bash
mkdir -p /var/ftp/pub/upload
chown root:root /var/ftp/pub
chmod 755 /var/ftp/pub
chown ftp:ftp /var/ftp/pub/upload
chmod 733 /var/ftp/pub/upload
在 /etc/vsftpd/vsftpd.conf 增加:
conf
anonymous_enable=YES
anon_root=/var/ftp/pub
no_anon_password=YES
anon_world_readable_only=YES
anon_upload_enable=YES
anon_mkdir_write_enable=NO
anon_other_write_enable=NO
anon_umask=022
配置 SELinux 允许匿名用户写入指定目录:
bash
semanage fcontext -a -t public_content_rw_t '/var/ftp/pub/upload(/.*)?'
restorecon -Rv /var/ftp/pub/upload
setsebool -P ftpd_anon_write on
systemctl restart vsftpd
客户端连接时使用用户名 anonymous 或 ftp:

匿名用户只能在 upload 子目录上传,不能修改根目录:

匿名上传目录容易被滥用。生产环境应限制来源地址、文件大小、速率和定期清理策略;不需要匿名上传时关闭 anon_upload_enable。
4.3 配置本地用户和目录隔离
创建本地 FTP 用户:
bash
useradd qwe
passwd qwe
mkdir -p /srv/ftp/qwe/upload
chown root:root /srv/ftp/qwe
chmod 755 /srv/ftp/qwe
chown qwe:qwe /srv/ftp/qwe/upload
chmod 750 /srv/ftp/qwe/upload
在配置文件中启用本地用户:
conf
local_enable=YES
write_enable=YES
local_umask=022
chroot_local_user=YES
allow_writeable_chroot=NO
user_sub_token=$USER
local_root=/srv/ftp/$USER
如果只允许指定账号登录,可启用用户白名单:
conf
userlist_enable=YES
userlist_deny=NO
userlist_file=/etc/vsftpd/user_list
bash
printf '%s\n' qwe > /etc/vsftpd/user_list
chmod 600 /etc/vsftpd/user_list
systemctl restart vsftpd
chroot_local_user 和 chroot_list_enable 的组合关系如下:

本地用户登录后查看目录:

执行 cd .. 后再次查看目录,仍停留在隔离根目录,说明 chroot 生效:

4.4 配置虚拟用户
创建不可登录系统的宿主账号和虚拟用户目录:
bash
useradd -r -d /srv/ftp/virtual -s /sbin/nologin ftpvirtual
mkdir -p /srv/ftp/virtual/li4/upload /srv/ftp/virtual/wang5/upload
chown root:root /srv/ftp/virtual/li4 /srv/ftp/virtual/wang5
chmod 755 /srv/ftp/virtual/li4 /srv/ftp/virtual/wang5
chown -R ftpvirtual:ftpvirtual /srv/ftp/virtual/li4/upload /srv/ftp/virtual/wang5/upload
建立账号文本。奇数行为用户名,下一行为对应密码:
text
li4
请替换为强密码
wang5
请替换为另一个强密码
原实验账号文件格式如下。图中 123456 仅是实验示例,实际部署必须更换:

生成 Berkeley DB,并删除明文账号文件:
bash
db_load -T -t hash -f /etc/vsftpd/vusers.txt /etc/vsftpd/vusers.db
chmod 600 /etc/vsftpd/vusers.db
rm -f /etc/vsftpd/vusers.txt
建立 /etc/pam.d/vsftpd-virtual:
pam
auth required pam_userdb.so db=/etc/vsftpd/vusers
account required pam_userdb.so db=/etc/vsftpd/vusers
PAM 数据库路径不带 .db 后缀:

修改 vsftpd 配置:
conf
anonymous_enable=NO
local_enable=YES
write_enable=YES
guest_enable=YES
guest_username=ftpvirtual
virtual_use_local_privs=YES
pam_service_name=vsftpd-virtual
user_sub_token=$USER
local_root=/srv/ftp/virtual/$USER
chroot_local_user=YES
allow_writeable_chroot=NO
如果不同虚拟用户需要不同权限,增加独立配置目录:
conf
user_config_dir=/etc/vsftpd/vconfig
bash
mkdir -p /etc/vsftpd/vconfig
cat > /etc/vsftpd/vconfig/li4 <<'EOF'
write_enable=NO
download_enable=YES
EOF
cat > /etc/vsftpd/vconfig/wang5 <<'EOF'
write_enable=YES
download_enable=YES
EOF
chmod 600 /etc/vsftpd/vconfig/*
systemctl restart vsftpd
4.5 可选:启用 FTPS
生成实验用自签名证书:
bash
openssl req -x509 -nodes -newkey rsa:2048 -days 365 \
-keyout /etc/pki/tls/private/vsftpd.key \
-out /etc/pki/tls/certs/vsftpd.crt
chmod 600 /etc/pki/tls/private/vsftpd.key
在配置文件中增加:
conf
ssl_enable=YES
rsa_cert_file=/etc/pki/tls/certs/vsftpd.crt
rsa_private_key_file=/etc/pki/tls/private/vsftpd.key
force_local_logins_ssl=YES
force_local_data_ssl=YES
ssl_tlsv1=YES
ssl_sslv2=NO
ssl_sslv3=NO
require_ssl_reuse=NO
自签名证书只适合实验。生产环境应使用受客户端信任的证书,并使用支持显式 FTPS 的客户端测试。
5. 验证结果
5.1 服务端验证
bash
systemctl status vsftpd --no-pager
ss -lntp | grep ':21'
firewall-cmd --list-services
firewall-cmd --list-ports
getsebool ftpd_anon_write
journalctl -u vsftpd -n 80 --no-pager
检查配置和目录权限:
bash
grep -Ev '^#|^$' /etc/vsftpd/vsftpd.conf
namei -l /var/ftp/pub/upload
namei -l /srv/ftp/qwe/upload
5.2 匿名用户验证
Linux 客户端:
bash
lftp -u anonymous ftp://10.1.100.101
连接后执行:
text
ls
cd upload
put test.txt
ls
预期:能浏览公开目录,只能在 upload 子目录上传,不能删除或改写根目录内容。
5.3 本地用户验证
bash
lftp -u qwe ftp://10.1.100.101
登录后执行 pwd、ls、cd .. 和 put test.txt -o upload/test.txt。预期用户不能离开 /srv/ftp/qwe 映射的根目录,只能写入 upload。
Windows 客户端可执行:
powershell
Test-NetConnection 10.1.100.101 -Port 21
ftp 10.1.100.101
5.4 虚拟用户验证
bash
lftp -u li4 ftp://10.1.100.101
lftp -u wang5 ftp://10.1.100.101
预期:两个虚拟账号均不能登录系统 Shell;li4 只能下载,wang5 可在自己的 upload 目录上传。服务端可确认宿主进程和文件属主:
bash
ps -ef | grep '[v]sftpd'
find /srv/ftp/virtual -maxdepth 3 -ls
5.5 常见故障排查
bash
journalctl -u vsftpd -n 100 --no-pager
tail -n 100 /var/log/xferlog
tail -n 100 /var/log/vsftpd.log 2>/dev/null
ausearch -m AVC -ts recent
• 530 Login incorrect:检查账号、PAM 文件名、用户数据库路径和 userlist。
• 500 OOPS: refusing to run with writable root inside chroot():让根目录归 root 且不可写,把写权限放到子目录;不要优先关闭安全检查。
• 能登录但无法列目录或传输:检查被动端口、防火墙、NAT 和客户端 PASV 模式。
• 550 Permission denied:同时检查 vsftpd 写开关、Linux 权限和 SELinux 上下文。
• 虚拟用户能认证但目录错误:检查 user_sub_token、local_root 和目录名是否与虚拟用户名一致。