How to set up a secure FTP service with vsftpd on Linux

This article was originally written for xmodulo.

FTP or File Transfer Protocol is one of the widely used services on the Internet, mainly for transferring files from one host to other. FTP itself was not designed as a secure protocol, and as such, the classic FTP service is vulnerable to common attacks such as man in the middle and brute force attacks.
Many applications with security features can be used to set up secure FTP services. For example, FTPS (FTP Secure) uses SSL/TLS certificates to encrypt end to end data. Based on client-side requirements, FTPS can be configured to support encrypted and/or unencrypted connections. SFTP (SSH File Transfer Protocol) is another method of ensuring security of transit data. SFTP is built as an extension of SSH, and can be used with other security protocols as well.
This tutorial will focus on setting up and securing FTP service using vsftpd with SSL/TLS enabled.
Just a bit of background: A typical FTP server listens on TCP ports 20 for data and 21 for command (also known as control port). Connection establishment and exchange of command parameters are done over port 21. FTP connections support two methods: active and passive modes. During connection establishment in active mode, the server initiates a connection from its port 20 (data) to the client. In passive mode, the server dedicates a random data port for each client session, and notifies the client about the port. The client then initiates a connection to the server's random port.
According to RFC 1635, FTP supports public access through a special user anonymous without any password and/or user ftp with password ftp. In addition to such public users, vsftpd also supports logins from local Linux users. Linux users can access their home directories i.e., /home/user by connecting to the server using FTP and providing their login credentials.

Insall vsftpd on Linux

To install vsftpd on Ubuntu, Debian or Linux Mint, use apt-get command. The vsftpd service will automatically launch upon boot.
$ sudo apt-get install vsftpd
To install vsftpd on CentOS, Fedora or RHEL, we can easily do it using yum. The service is started and add to system startup as well.
# yum install vsftpd
# service vsftpd start
# chkconfig vsftpd on
The most basic form of FTP services using vsftpd is now ready to be used. We can access FTP service by pointing our browser to the URL ftp://[ServerName/IP] or by connecting using FTP client like FileZilla with username anonymous and no password OR username ftp and password ftp.
When vsftpd is installed, a system user ftp with home directory /var/ftp is added in the system. Whenever an anonymous FTP connection is established, the session always defaults to /var/ftp directory. So, we can use this directory as the home directory for FTP public users. Any file/directory put in under /var/ftp is accessible via ftp://[ServerName/IP].
The location of vsftpd configuration file is found in the following locations:
  • Ubuntu, Debian or Linux Mint: /etc/vsftpd.conf
  • CentOS, Fedora or RHEL: /etc/vsftpd/vsftpd.conf
In the rest of the tutorial, use vsftpd.conf file in the corresponding location on your Linux system.

Tuning FTP Users

To disable public access, we explicitly disable the user anonymous in vsftpd.conf. Commenting out the line will not work since vsftpd will run using default values. You need to restart vsftpd as well.
# service vsfptd restart
Mandatory authentication is thus enabled, and only existing Linux users will be able to connect using their login credentials.
To enable/disable local users, we can modify vsftpd.conf file. If we disable local users, we have to make sure that the user anonymous is granted access.
# service vsfptd restart
To connect to the system using a specific user, we simply modify the URL as ftp://username@[ServerName/IP]. The home directory of the respective user is accessible via FTP using this method.

Confining Users to Their Home Directories

When a user accesses a remote server using FTP, the user can navigate the entire system as long as files/directories are readable. This is not recommended at all since any user will be able to read and download system files under /etc, /var, /usr and other locations through a FTP session.
To make local users restricted to only their home directories during FTP sessions, we can modify the following parameter.
# service vsftpd restart
Now, local users will only be able to access their home directories, but no other files or directories in the system.

Enabling SSL/TLS Encryption

FTP is by design a clear text protocol which means anyone can easily snoop on file transfer traffic between a client and a remote FTP server. To encrypt FTP communication, you can enable SSL/TLS in vsftpd.
The first step is to create an SSL/TLS certificate and a private key as follows. It will store the generated certificate/key in a target .pem file.
On Debian/Ubuntu:
$ sudo openssl req -x509 -days 365 -newkey rsa:2048 -nodes -keyout /etc/vsftpd.pem -out /etc/vsftpd.pem
On CentOS/Fedora/RHEL:
$ sudo openssl req -x509 -days 365 -newkey rsa:2048 -nodes -keyout /etc/vsftpd/vsftpd.pem -out /etc/vsftpd/vsftpd.pem
Then add the following parameters in vsftpd.conf configuration file.
# enable TLS/SSL

# force client to use TLS when logging in

# specify SSL certificate/private key (Debian/Ubuntu)
# For CentOS/Fedora/RHEL, replace it with /etc/vsftpd/vsftpd.pem

# define port range for passive mode connections
Finally restart vsftpd.
# service vsftpd restart

Controlling Connections and Bandwidth

vsftpd offers several methods to control connections and user bandwidth. We will use a couple of them to tune our FTP server.
## bandwidth allocation per anonymous session is set to roughly 30 KB/s ##

## each local user is granted roughly 30 KB/s bandwidth ##

## client session is terminated after being idle for 300 seconds ##

## maximum number of connections per source IP, which can help secure against DoS and DDoS attacks ##

Tuning Firewall

Finally, if you are running iptables firewall on your system (e.g., CentOS), make sure to adjust firewall rules to allow FTP traffic. The following rules should help you get started.
# iptables -I INPUT -p tcp --dport 20 -j ACCEPT
# iptables -I INPUT -p tcp --dport 21 -j ACCEPT
# iptables -I INPUT -p tcp --dport 64000:65535 -j ACCEPT
The first two rules allow traffic on FTP data/control ports. The last rule allow passive mode connections whose port range is already defined in vsftpd.conf.

Enable Logging

In case you encounter any issue during the setup in this tutorial, you can enable logging by modifying the following parameter in vsftpd.conf.
# service vsftpd restart

Connecting to a FTP Server with FileZilla

There are several FTP clients which support SSL/TLS, notably, FileZilla. To connect to an SSL/TLS-enabled FTP site on FileZilla, use the following setting for the FTP host.
The first time you are connecting to an SSL/TLS-enabled FTP server, you will be presented with the site's certificate. Go ahead and trust the certificate to log in.

Troubleshooting sftpd

1. If you are getting the following error while connecting to a FTP server, it may be because your firwall is blocking FTP traffic. Make sure that you opened your firewall for necessary FTP ports as described above.
ftp: connect: No route to host
2. If you are getting the following error when connecting to a chroot-ed FTP server running on CentOS/RHEL, disabling SELinux is one option.
500 OOPS: cannot change directory:/home/dev
Login failed.
While turning off SELinux is a quick solution, it may not be safe to do so in a production environment. So instead, turning the following boolean on in SELinux can fix the problem.
$ sudo setsebool -P ftp_home_dir on
3. If you are getting the following errors while accessing an SSL/TLS-enabled FTP server on FileZilla, make sure to add "ssl_ciphers=HIGH" in vsftpd.conf. The default cipher (DES-CBC3-SHA) is not supported by FileZilla.
Trace: GnuTLS alert 40: Handshake failed
Error: GnuTLS error -12: A TLS fatal alert has been received.
"SSL_accept failed: error:1408A0C1:SSL routines:SSL3_GET_CLIENT_HELLO:no shared cipher"
To sum up, setting up a FTP server using vsftpd is not difficult. The default installation with user anonymous should be able to support small classic FTP services. vsftpd has many tunable parameters that make it versatile.
Hope this helps.