The most surprising thing about encrypting FTP traffic with FTPS is that it’s fundamentally a lie – FTPS doesn’t encrypt FTP, it encrypts a separate protocol that happens to use the same port numbers.

Let’s see this in action. We’ll set up a simple vsftpd server on one machine and connect to it from a client.

First, the server setup. We need a certificate. For testing, we can generate a self-signed one, but for production, you’d get one from a trusted Certificate Authority (CA).

# On the server
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/ssl/private/vsftpd.pem -out /etc/ssl/private/vsftpd.pem

This creates a single .pem file that contains both the private key and the certificate. Now, configure vsftpd to use it. Edit /etc/vsftpd.conf:

# Enable local users
local_enable=YES
write_enable=YES

# Enable FTPS
ssl_enable=YES
allow_anon_ssl=NO
force_local_data_ssl=YES
force_local_logins_ssl=YES

# Point to our certificate
rsa_cert_file=/etc/ssl/private/vsftpd.pem
rsa_private_key_file=/etc/ssl/private/vsftpd.pem

# Optional: Use TLS v1.2 and v1.3 for better security
ssl_tlsv1=NO
ssl_sslv2=NO
ssl_sslv3=NO
ssl_tlsv1_1=YES
ssl_tlsv1_2=YES
ssl_tlsv1_3=YES

Restart vsftpd:

sudo systemctl restart vsftpd

Now, on the client, we’ll use curl to demonstrate. curl supports FTPS.

# On the client
curl -v -k "ftps://your_server_ip/path/to/file" -u username:password

The -k flag tells curl to ignore certificate validation errors, which is fine for testing with a self-signed certificate. You’ll see a lot of output, but look for the TLS handshake details. curl will negotiate a TLS session before any FTP commands are sent. This is the "encrypted" part.

The problem vsftpd solves is that FTP itself is a plaintext protocol. All commands (like USER, PASS, LIST) and data are sent unencrypted. FTPS wraps this in SSL/TLS, but it’s a bit of a kludge. There are two modes: Implicit and Explicit.

  • Implicit FTPS: This is what we’ve configured above. The client connects to the FTP port (usually 21) and immediately initiates a TLS handshake. The server must be listening for this. It’s like saying, "We’re speaking TLS from the get-go."
  • Explicit FTPS (FTPES): The client connects to port 21 and sends the AUTH TLS command. If the server supports it, it initiates a TLS handshake. After that, all FTP commands and data are encrypted. This is more flexible because a server can potentially handle both plain FTP and FTPS on the same port.

The core issue is that FTP uses two channels: a command channel (port 21) and a data channel. The data channel’s port is negotiated dynamically by default (passive mode). FTPS has to encrypt both of these.

For Implicit FTPS, both command and data channels are encrypted using the TLS session established on port 21.

For Explicit FTPS, the command channel is encrypted after AUTH TLS. When a data transfer command (like RETR or STOR) is issued, a new TLS session is negotiated for the data channel. This can be tricky with firewalls because the server needs to open ports for passive mode data transfers, and those ports also need to be secured.

The way vsftpd handles this is by using the OpenSSL library. When ssl_enable is set to YES, vsftpd uses OpenSSL to wrap the FTP protocol. The force_local_data_ssl and force_local_logins_ssl options ensure that any connection attempt from a local user must go through SSL/TLS.

A common pitfall is firewall configuration. If you’re using passive mode, which is standard for FTPS, the server needs to open a range of ports for data connections. These ports must be allowed through the firewall. In vsftpd.conf, you’d configure this with pasv_min_port and pasv_max_port:

pasv_min_port=40000
pasv_max_port=50000

You’d then need to open ports 40000-50000 in your server’s firewall for TCP traffic.

The real magic, and the thing that often trips people up, is that the TLS handshake happens before the FTP protocol commands. This means that any tool or client that doesn’t understand how to initiate an AUTH TLS command or how to negotiate TLS on port 21 for Implicit FTPS will simply fail. It’s not that FTP is being encrypted; it’s that a secure channel is being established, and then FTP commands are sent over that channel.

The next hurdle you’ll likely encounter is dealing with clients that don’t support FTPS well, or understanding the nuances of active vs. passive mode FTPS with complex firewall rules.

Want structured learning?

Take the full Ftp course →