VSFTPd, SSL, and Firewalls
If you ever wanted to configure SSL/TLS encryption for an FTP server behind a firewall, the “Google wisdom” ranges from “a major pain” to “can’t be done”. Fortunately, things are not all that bad. In the configuration example below I have a CentOS box with vsftpd and iptables sitting in the LAN DMZ behind a hardware firewall. The goal of this exercise is to configure vsftpd to run FTP over TLS.
Reference diagram:
If you don’t already have vsftpd installed, do so now:
yum install vsftpd adduser ftpuser passwd ftpuser chkconfig vsftpd on
Here’s a sample /etc/vsftpd/vsftpd.conf that includes all the required directives to explicit FTP over TLS. Look over the config and pay attention: make sure you insert the right IPs and ports you wish to use. Keep in mind that /etc/vsftpd/chroot_list contains user who will NOT be chrooted. You should really keep that list short, if not empty.
anonymous_enable=NO local_enable=YES write_enable=YES local_umask=022 dirmessage_enable=YES xferlog_enable=YES connect_from_port_20=NO xferlog_file=/var/log/xferlog syslog_enable=YES xferlog_file=/var/log/xferlog xferlog_std_format=YES chroot_local_user=YES chroot_list_enable=YES chroot_list_file=/etc/vsftpd/chroot_list listen=YES pam_service_name=vsftpd userlist_enable=YES tcp_wrappers=YES force_dot_files=NO ssl_enable=YES allow_anon_ssl=NO force_local_data_ssl=YES force_local_logins_ssl=YES ssl_tlsv1=YES ssl_sslv2=NO ssl_sslv3=NO require_ssl_reuse=NO ssl_ciphers=HIGH rsa_cert_file=/etc/ssl/private/vsftpd.pem rsa_private_key_file=/etc/ssl/private/vsftpd.pem pasv_enable=YES pasv_min_port=15364 pasv_max_port=15374 # increase this range for more users pasv_address=$external_ip # your “internet” IP listen_address=$local_ip # i.e. 192.168.0.20 #implicit_ssl=YES # uncomment for implicit FTP over TLS #listen_port=990 # default port for implicit FTP over TLS
The next step is to configure SSL with vsftpd:
mkdir /etc/ssl/private openssl req -x509 -nodes -days 365 -newkey rsa:1024 -keyout /etc/ssl/private/vsftpd.pem -out /etc/ssl/private/vsftpd.pem
Now we need to add the right rules to iptables. In this example I will use port range 15364:15374. Depending on how many simultaneous users you are expecting, you may need to increase this range.
iptables -A INPUT -p tcp --sport 20 -j ACCEPT iptables -A INPUT -p tcp --dport 21 -j ACCEPT iptables -A INPUT -p tcp --dport 990 -j ACCEPT iptables -A INPUT -p tcp --dport 15364:15374 -j ACCEPT service iptables save
You will need to create the following forwarding rules on your external firewall:
*.*.*.*:20 -> vsftpd_ip:20 *.*.*.*:21 -> vsftpd_ip:21 *.*.*.*:990 -> vsftpd_ip:990 *.*.*.*:15364-15374 -> vsftpd_ip:15364-15374
Start the vsftpd service:
service vsftpd restart
A somewhat unrelated question that frequently arises when dealing with vsftpd is how to make it follow symbolic links. Now, this is actually not possible. But there is a way around by using binding mounts. For example, let’s say your FTP user home is /home/ftpusers/ftpuser1 and you want to put a link from there to /data/ftp, here’s what you do:
cd /home/ftpusers/ftpuser1 mdkir ftp_data chown ftpuser1 ftp_data mount --bind /data/ftp ftp_data
If you are using Filezilla, here’s how your connection configuration should look: