Linux 安装与配置 vsftpd

Linux 安装与配置 vsftpd:外网登录、上传与 530/425 排错

本文以 vsftpd 为例,在常见 Linux 发行版上完成安装、配置与验证,使外网客户端能够登录并上传文件。文中涉及 IP、路径、账号均为示例,请按你的环境替换。

适用环境 :RHEL / CentOS / Alibaba Cloud Linux(dnf/yum)、Ubuntu / Debian(apt)。

你将完成:安装服务 → 创建本地用户 → 配置被动模式 → 放行端口 → 命令行/Java 上传测试 → 处理 530、425 常见错误。

安全提示 :标准 FTP 以明文传输账号与密码,不适合直接用于生产。生产环境请优先考虑 SFTP(SSH)FTPS(FTP over TLS)


目录

  1. 前置条件
  2. [安装 vsftpd](#安装 vsftpd)
  3. 启动服务
  4. [创建 FTP 用户](#创建 FTP 用户)
  5. [配置 vsftpd](#配置 vsftpd)
  6. [确认 FTP 根目录](#确认 FTP 根目录)
  7. 放行端口(安全组与防火墙)
  8. 连通性验证
  9. 上传测试
  10. 常见错误排查
  11. 安全建议

1. 前置条件

项目 说明
服务器 一台可 SSH 登录的 Linux 主机;外网访问需具备公网 IP
权限 root 或具备 sudo 的普通用户
云主机 若使用 ECS/云服务器,需能修改安全组入站规则
替换项 下文 203.0.113.10 为文档用示例公网 IP(RFC 5737 TEST-NET),请改为你的真实公网 IP

为何外网必须配置被动模式?

FTP 控制连接使用 21 端口;传输目录列表与文件时,会再建立数据连接

  • 主动模式(PORT):服务器连回客户端,易被 NAT/防火墙拦截。
  • 被动模式(PASV) :客户端连服务器的 pasv_min_portpasv_max_port 区间;公网场景通常必须启用,并正确设置 pasv_address 与端口放行,否则易出现 425

2. 安装 vsftpd

RHEL / CentOS / Alibaba Cloud Linux

bash 复制代码
sudo dnf install -y vsftpd
# 较老系统可使用:sudo yum install -y vsftpd

Ubuntu / Debian

bash 复制代码
sudo apt update
sudo apt install -y vsftpd

3. 启动服务

bash 复制代码
sudo systemctl enable --now vsftpd
sudo systemctl status vsftpd --no-pager

输出中出现 active (running) 表示服务已启动。


4. 创建 FTP 用户

vsftpd 默认使用本地系统用户 登录(非匿名)。以下示例用户名为 ftpuser

bash 复制代码
sudo useradd -m -s /bin/bash ftpuser
sudo passwd ftpuser

验证账号与密码(能成功切换即表示凭据有效):

bash 复制代码
su - ftpuser
pwd
exit

5. 配置 vsftpd

5.1 备份原配置

bash 复制代码
sudo cp /etc/vsftpd/vsftpd.conf /etc/vsftpd/vsftpd.conf.bak.$(date +%F)

5.2 写入推荐配置

pasv_address 改为你的公网 IP(勿使用内网 IP,否则外网客户端会连错地址导致 425):

bash 复制代码
sudo tee /etc/vsftpd/vsftpd.conf > /dev/null << 'EOF'
listen=YES
listen_ipv6=NO

anonymous_enable=NO
local_enable=YES
write_enable=YES

local_umask=022
use_localtime=YES
xferlog_enable=YES
connect_from_port_20=YES

# 将用户限制在其主目录内(chroot)
chroot_local_user=YES
allow_writeable_chroot=YES

pam_service_name=vsftpd
userlist_enable=NO

# 被动模式(公网访问必备)
pasv_enable=YES
pasv_min_port=50000
pasv_max_port=50100
pasv_address=203.0.113.10
EOF
配置项 作用
local_enable=YES 允许本地用户登录
write_enable=YES 允许上传、删除、重命名等写操作
chroot_local_user=YES 登录后限制在用户主目录,降低越权风险
allow_writeable_chroot=YES 在 chroot 下仍允许可写目录(配合上传)
pasv_* 被动模式地址与端口范围,需与安全组/防火墙一致

应用配置:

bash 复制代码
sudo systemctl restart vsftpd
sudo systemctl status vsftpd --no-pager

确认被动模式相关项已生效:

bash 复制代码
grep -nE '^(pasv_enable|pasv_min_port|pasv_max_port|pasv_address)=' /etc/vsftpd/vsftpd.conf

6. 确认 FTP 根目录

未设置 local_root 时,用户登录后的默认目录为其家目录

bash 复制代码
getent passwd ftpuser

示例输出:

text 复制代码
ftpuser:x:1000:1000::/home/ftpuser:/bin/bash

第六个字段 /home/ftpuser 即为 FTP 根目录。应用侧若需配置「远程基础路径」,可填写该路径,例如:

yaml 复制代码
# 应用配置示例(按你的项目字段名调整)
remote-base-dir: /home/ftpuser

固定到自定义目录(可选)

若希望统一使用 /data/ftpuser

bash 复制代码
sudo mkdir -p /data/ftpuser
sudo chown ftpuser:ftpuser /data/ftpuser

/etc/vsftpd/vsftpd.conf 末尾追加:

conf 复制代码
local_root=/data/ftpuser

然后执行 sudo systemctl restart vsftpd


7. 放行端口(安全组与防火墙)

7.1 云安全组(外网访问时优先检查)

入方向至少放行:

协议 端口 说明
TCP 21 FTP 控制连接
TCP 50000--50100 被动模式数据连接(须与 pasv_min_port / pasv_max_port 一致)

仅放行 21 时,常见现象为:能登录,但无法列目录或上传(425)

7.2 firewalld(RHEL 系常见)

bash 复制代码
sudo firewall-cmd --permanent --add-port=21/tcp
sudo firewall-cmd --permanent --add-port=50000-50100/tcp
sudo firewall-cmd --reload

7.3 ufw(Ubuntu/Debian 常见)

bash 复制代码
sudo ufw allow 21/tcp
sudo ufw allow 50000:50100/tcp
sudo ufw reload

8. 连通性验证

客户端 (例如 Windows PowerShell)测试端口是否可达,将 203.0.113.10 换成你的公网 IP:

powershell 复制代码
Test-NetConnection 203.0.113.10 -Port 21
Test-NetConnection 203.0.113.10 -Port 50000
结果 含义
21 通、50000 不通 被动端口未放行或 pasv_address 配置错误,易出现 425
均不通 检查安全组、本机防火墙、vsftpd 是否监听

9. 上传测试

9.1 Windows 自带 ftp 客户端

powershell 复制代码
ftp 203.0.113.10

连接成功后依次输入(密码输入时不回显,属正常现象):

text 复制代码
user ftpuser
# 按提示输入密码
binary
pwd
ls
put D:\local\test_upload.txt
bye

已启用 chroot_local_user 时,用户通常已在主目录内,pwd 可能显示 /,即对应其家目录根。

9.2 Java(Apache Commons Net)

Maven 依赖:

xml 复制代码
<dependency>
  <groupId>commons-net</groupId>
  <artifactId>commons-net</artifactId>
  <version>3.11.1</version>
</dependency>

示例代码(请修改 host、账号、密码与本地文件路径;勿将真实密码提交到版本库):

java 复制代码
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;

import java.io.FileInputStream;
import java.io.InputStream;

public class FtpUploadTest {
    public static void main(String[] args) throws Exception {
        String host = System.getenv().getOrDefault("FTP_HOST", "203.0.113.10");
        int port = 21;
        String username = System.getenv().getOrDefault("FTP_USER", "ftpuser");
        String password = System.getenv().getOrDefault("FTP_PASS", "请改为强密码");
        String baseDir = "/home/ftpuser";

        String localFile = "D:/local/test_upload.txt";
        String remoteFileName = "test_upload.txt";

        FTPClient ftp = new FTPClient();
        ftp.connect(host, port);

        try {
            if (!ftp.login(username, password)) {
                throw new RuntimeException("FTP login failed: " + ftp.getReplyString());
            }

            ftp.enterLocalPassiveMode();
            ftp.setFileType(FTP.BINARY_FILE_TYPE);

            if (baseDir != null && !baseDir.isBlank()) {
                if (!ftp.changeWorkingDirectory(baseDir)) {
                    throw new RuntimeException(
                        "changeWorkingDirectory failed: " + baseDir + ", reply=" + ftp.getReplyString());
                }
            }

            try (InputStream input = new FileInputStream(localFile)) {
                if (!ftp.storeFile(remoteFileName, input)) {
                    throw new RuntimeException("Upload failed, reply=" + ftp.getReplyString());
                }
            }

            System.out.println("Upload success: " + remoteFileName);
        } finally {
            try { ftp.logout(); } catch (Exception ignored) {}
            try { ftp.disconnect(); } catch (Exception ignored) {}
        }
    }
}

运行前可设置环境变量(避免硬编码密码):

bash 复制代码
export FTP_HOST=203.0.113.10
export FTP_USER=ftpuser
export FTP_PASS='你的强密码'

10. 常见错误排查

10.1 530 Login incorrect

可能原因 处理步骤
未启用本地用户 确认 local_enable=YES
用户在黑名单中 检查 /etc/vsftpd/ftpusers/etc/vsftpd/user_list,删除对应用户名行后重启服务
密码错误 sudo passwd ftpuser,并用 su - ftpuser 验证
bash 复制代码
sudo grep -n '^ftpuser$' /etc/vsftpd/ftpusers /etc/vsftpd/user_list 2>/dev/null
sudo systemctl restart vsftpd

10.2 425 Failed to establish connection

多为被动模式数据连接失败,按顺序检查:

  1. pasv_enable=YES,且 pasv_address公网 IP
  2. pasv_min_port / pasv_max_port 与安全组、防火墙放行范围一致
  3. 客户端使用被动模式(如 Java 中 enterLocalPassiveMode()
bash 复制代码
grep -nE '^(pasv_enable|pasv_min_port|pasv_max_port|pasv_address)=' /etc/vsftpd/vsftpd.conf

11. 安全建议

  • 使用强密码,并通过环境变量或密钥管理注入,避免写入代码仓库。
  • 限制安全组来源 IP,仅允许业务需要的网段访问 21 与被动端口段。
  • 定期审计 vsftpd 日志与上传目录权限。
  • 生产环境优先采用 SFTP 或配置 FTPS(TLS),避免明文 FTP。

参考

相关推荐
北京耐用通信2 天前
耐达讯自动化PROFIBUS光纤模块:工业通信的“光电翻译官”
人工智能·科技·网络协议·自动化·信息与通信
星恒讯工业路由器2 天前
4G自组网与VPDN专网技术解析
网络·物联网·信息与通信·4g自组网·vpdn专网
星恒讯工业路由器3 天前
5G‑A大上行:七大技术补短板
网络·信息与通信·6g·5g‑a·5g-a大上行
深圳市晶科鑫实业有限公司3 天前
5G与AIoT时代:如何选择晶振常用频率?
服务器·单片机·物联网·5g·智能路由器·健康医疗·信息与通信
YUANQIANG20243 天前
博弈论中势函数与势博弈构造:为什么看似 “先射箭后画靶”
算法·信息与通信
hz567893 天前
2026 年 RTC 音视频 SDK 解析:技术架构、主流厂商与选型指南
架构·云计算·音视频·webrtc·实时音视频·信息与通信
爱浦路 IPLOOK3 天前
5G UPF商用部署:从技术原理到落地价值
科技·信息与通信
SAP上海工博云署3 天前
2026年中小企业SAP服务商选型技术解析
大数据·运维·数据库·人工智能·信息可视化·运维开发·信息与通信
dxxt_yy3 天前
铁路光缆精准定位:鼎讯信通 G-6000 优势解析
信息与通信