Nginx代理FTP
1 需求
近期,需要通过Nginx代理内网FTP服务,以便外网用户进行访问,故针对此展开技术调研。
软件版本:
- Nginx: 1.18.0;
- vsftpd: 3.0.2;
- CentOS: CentOS Linux release 7.9.2009 (Core).
2 FTP模式
FTP具有两个端口,分别为控制端口(完成诸如登录,目录查询/切换等命令),数据端口(负责具体数据传输).
CentOS上安装vsftpd后,启动服务可发现vsftpd在21端口上监听命令(此时无客户端接入),具体如下图所示:
FTP连接模式具有两种,分别为主动模式(PORT)以及被动模式(PASV)。
主动模式:
(1)当FTP客户端以主动模式连接服务端时,客户端以动态选择的端口号向服务器的命令端口发起连接;
(2)连接建立后,用户在发出列目录或传输文件的命令后,会要求建立数据连接;
(3)FTP客户端在控制连接上发出主动模式指令,告知服务器客户端的数据连接端口号;
(4)服务端收到指令后,会使用20号端口连接客户端指定的数据连接端口号,从而建立数据连接。
被动模式:
被动模式的连接过程与主动模式类似,区别点在于客户端发出列目录或传输文件的命令后,客户端会发送PASV指令至服务端;
服务端收到PASV指令后,告知客户端服务端的数据连接IP地址和端口号;
客户端根据返回的服务端数据连接IP和端口号,发起数据连接。
3 问题 & 解决思路
当前,客户端需要通过Nginx代理方能访问FTP服务端。通过Nginx stream可以实现控制命令的转发,但是对于客户端和服务端协商的数据连接,较难实现代理。
不过查阅相关文档,vsftpd支持设置数据连接的端口范围,亦支持设置数据连接的IP。
因此,我们可以指定vsftpd模式为被动模式(默认即为被动模式),设置数据连接IP地址为Nginx代理地址,合理设置数据连接端口范围(Nginx监听本地此端口范围内数据)。当ftp客户端与vsftpd服务端协商数据连接后,ftp客户端根据数据连接IP(已设置为Nginx代理地址)以及端口号发起连接(实际连接至Nginx服务器),Nginx将此端口上监听的数据转发至vsftpd对应的数据端口。
4 方案示例
机器信息:
- Nginx代理机: 192.168.56.101;
- vsftpd服务端: 192.168.56.102;
- 测试机: 192.168.56.106。
此处,利用开发机上安装的虚拟机完成验证,未具体限制网段。
vsftpd服务端配置:
# cat /etc/vsftpd/vsftpd.conf
listen=YES
listen_ipv6=NO # 修改listen配置,只允许监听在IPv4地址,这是因为在被动模式下,设置pasv_address存在bug(具体可搜索stackoverflow)
pasv_enable=YES # 开启pasv模式
pasv_min_port=50000 # pasv模式下,数据连接最小端口号
pasv_max_port=50002 # pasv模式下,数据连接最大端口号
pasv_address=192.168.56.101 # pasv模式下,告知客户端的数据连接IP
pasv_promiscuous=YES # 关闭pasv模式下,关闭对IP地址的检查,此检查确保控制连接和数据连接来自同一IP
pasv_promiscuous关闭存在安全隐患;
在实际组网情况下,Nginx转发时可设置保留源IP信息,但是客户端与服务端无法直接访问,因此只能放弃保留源IP信息。
Nginx配置:
stream {
upstream ftp { # FTP控制面转发
server 192.168.56.102:21 max_fails=2 fail_timeout=3s weight=1;
}
server { # 转发FTP控制面请求
listen 11000; #监听端口
#失败重试
proxy_next_upstream on;
proxy_next_upstream_timeout 0;
proxy_next_upstream_tries 0;
#超时配置
proxy_connect_timeout 1s;
proxy_timeout 10m;
#限速配置
proxy_upload_rate 1024k;
proxy_download_rate 2048k;
#上游服务器
proxy_pass ftp;
}
upstream ftp_pasv1 {
server 192.168.56.102:50000 max_fails=2 fail_timeout=3s weight=1;
}
upstream ftp_pasv2 {
server 192.168.56.102:50001 max_fails=2 fail_timeout=3s weight=1;
}
upstream ftp_pasv3 {
server 192.168.56.102:50002 max_fails=2 fail_timeout=3s weight=1;
}
server { # 转发客户端发送到Nginx代理机的数据连接
listen 50000;
proxy_pass ftp_pasv1;
}
server { # 转发客户端发送到Nginx代理机的数据连接
listen 50001;
proxy_pass ftp_pasv2;
}
server { # 转发客户端发送到Nginx代理机的数据连接
listen 50002;
proxy_pass ftp_pasv3;
}
}
此处省略对FTP数据连接的具体控制(诸如限速)。
5 验证
重启vsftpd以及Nginx,从测试机:192.168.56.103发起连接,具体如下所示:
tcpdump抓包分析:
6 弊端
使用Nginx代理FTP服务,存在以下缺点:
- 控制连接和数据连接是否来自同一连接无法验证,存在安全隐患;
- FTP被动模式下,数据端口范围较宽时,Nginx添加配置比较麻烦;
- Nginx代理机需要开放较多端口,诸如iptables等安全设置复杂。
使用SFTP,简单又可靠。
本文同步发布于本人博客网站,欢迎查看《Nginx代理FTP全流程分析》。