Last updated: 2026-06-25
vsftpd TLS/SSL Configuration Guide
This guide provides recommended TLS/SSL settings for vsftpd (Very Secure FTP Daemon), a lightweight and security-focused FTP server for Linux. vsftpd supports both explicit FTPS (STARTTLS on port 21) and implicit FTPS (direct TLS on port 990).
Prerequisites
- vsftpd 3.0.3 or later
- OpenSSL 1.1.1 or later
- A valid SSL/TLS certificate
Certificate Setup
vsftpd expects PEM-formatted certificate files:
chmod 600 /etc/vsftpd/ssl/privkey.pem
chown root:root /etc/vsftpd/ssl/privkey.pem
Enable TLS
Add the following settings to /etc/vsftpd/vsftpd.conf (or /etc/vsftpd.conf depending on your distribution).
Basic TLS Settings
ssl_enable=YES
rsa_cert_file=/etc/vsftpd/ssl/fullchain.pem
rsa_private_key_file=/etc/vsftpd/ssl/privkey.pem
Require TLS for All Connections
Force both anonymous and local users to use encrypted connections:
allow_anon_ssl=NO
force_local_data_ssl=YES
force_local_logins_ssl=YES
- force_local_logins_ssl=YES requires TLS for the control channel (login credentials).
- force_local_data_ssl=YES requires TLS for the data channel (file transfers).
Protocol Versions
Disable older protocols and require TLS 1.2 or later:
ssl_tlsv1=NO
ssl_tlsv1_1=NO
ssl_sslv2=NO
ssl_sslv3=NO
ssl_tlsv1_2=YES
Version note: The
ssl_tlsv1_2directive requires vsftpd 3.0.4+. On unpatched vsftpd 3.0.3, this directive is unrecognized and vsftpd will refuse to start. In that case, omitssl_tlsv1_2=YESand rely on disabling older protocols (ssl_tlsv1=NO,ssl_sslv2=NO,ssl_sslv3=NO); TLS 1.2 will be used by default.The
ssl_tlsv1_1directive is available in vsftpd 3.0.4+ and some distribution-patched builds of 3.0.3. If your build does not recognize it, omit it; disablingssl_tlsv1andssl_sslv2/ssl_sslv3is still effective. vsftpd does not have a dedicatedssl_tlsv1_3directive; TLS 1.3 is available automatically when using OpenSSL 1.1.1+.
Cipher Suites
Configure strong cipher suites for TLS 1.2. TLS 1.3 cipher suites are managed by OpenSSL automatically and cannot be overridden via ssl_ciphers:
ssl_ciphers=ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305
Additional Security Settings
require_ssl_reuse=NO
strict_ssl_read_eof=YES
- require_ssl_reuse=NO allows data connections without TLS session reuse. Some FTP clients do not support session reuse, and enabling this can cause transfer failures. Set to
YESif all your clients support it. - strict_ssl_read_eof=YES requires proper TLS shutdown, preventing truncation attacks.
Implicit FTPS
By default, vsftpd uses explicit FTPS (STARTTLS on port 21). To use implicit FTPS (TLS from the start on port 990):
implicit_ssl=YES
listen_port=990
Note that implicit and explicit FTPS cannot run on the same listener. To support both, you need two vsftpd instances with separate configuration files.
Passive Mode
Configure passive mode ports for FTPS data connections. Your firewall must allow these ports:
pasv_enable=YES
pasv_min_port=49152
pasv_max_port=65534
pasv_address=your.public.ip.address
Complete Configuration
# General settings
listen=YES
# listen=YES binds IPv4 only and is mutually exclusive with listen_ipv6=YES;
# do not set both in one config. For dual-stack, either run two vsftpd instances
# (one with listen=YES, one with listen_ipv6=YES), or use listen_ipv6=YES bound
# to :: instead, which accepts both IPv6 and IPv4 clients.
anonymous_enable=NO
local_enable=YES
write_enable=YES
chroot_local_user=YES
allow_writeable_chroot=YES
# TLS settings
ssl_enable=YES
rsa_cert_file=/etc/vsftpd/ssl/fullchain.pem
rsa_private_key_file=/etc/vsftpd/ssl/privkey.pem
# Require TLS
allow_anon_ssl=NO
force_local_data_ssl=YES
force_local_logins_ssl=YES
# Protocol versions
ssl_tlsv1=NO
ssl_tlsv1_1=NO
ssl_sslv2=NO
ssl_sslv3=NO
ssl_tlsv1_2=YES # requires vsftpd 3.0.4+; omit on unpatched 3.0.3
# Cipher suites
ssl_ciphers=ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305
# Session settings
require_ssl_reuse=NO
strict_ssl_read_eof=YES
# Passive mode
pasv_enable=YES
pasv_min_port=49152
pasv_max_port=65534
Security Notes
The cipher suite and protocol configuration in this guide addresses the following known TLS vulnerabilities:
- POODLE (CVE-2014-3566, 2014): SSL 3.0 is disabled. TLS_FALLBACK_SCSV was added in OpenSSL 1.0.1j / 1.0.2 (October 2014); SSL 3.0 disabled by default in OpenSSL 1.1.0 (August 2016).
- BEAST (CVE-2011-3389, 2011): Mitigated by recommending TLS 1.2 as the minimum; AEAD-only ciphers eliminate the CBC padding oracle.
- CRIME (CVE-2012-4929, 2012): TLS compression is off by default in OpenSSL 1.1.0+; do not enable it.
- Lucky13 (2013): AEAD-only cipher list eliminates CBC padding timing side-channels entirely.
- FREAK (CVE-2015-0204, 2015): EXPORT-grade ciphers are excluded from the cipher string. Removed from OpenSSL 1.1.0 (August 2016).
- LOGJAM (CVE-2015-4000, 2015): Short-key DHE is excluded; only ECDHE key exchange is recommended.
- Sweet32 (CVE-2016-2183, 2016): 3DES is excluded from the cipher string.
- ROBOT (2017): Static RSA key exchange is excluded; only ECDHE is recommended.
- Downgrade attacks: TLS_FALLBACK_SCSV prevents protocol version rollback.
- Renegotiation injection (CVE-2009-3555, 2009): Secure renegotiation is enforced by default in OpenSSL 0.9.8m+; TLS 1.3 removes renegotiation entirely.
The following are not addressable through TLS configuration alone:
- Heartbleed (CVE-2014-0160, 2014): A memory disclosure bug in OpenSSL 1.0.1 through 1.0.1f. Fixed in OpenSSL 1.0.1g (April 7, 2014). Addressed by patching OpenSSL, not by TLS configuration.
- BREACH (CVE-2013-3587, 2013): Not applicable. BREACH targets HTTP-level response compression; FTP does not involve HTTP.
- DROWN (CVE-2016-0800, 2016): Requires SSLv2 to be enabled on any server sharing the same private key. Ensure SSLv2 is disabled on all services that use the same certificate and key pair.
Verification
Restart vsftpd:
systemctl restart vsftpd
Test with OpenSSL (explicit FTPS):
openssl s_client -connect ftp.example.com:21 -starttls ftp
Test with OpenSSL (implicit FTPS):
openssl s_client -connect ftp.example.com:990
Test with lftp:
lftp -u username -e "set ftp:ssl-force true; set ssl:verify-certificate yes; ls; quit" ftp.example.com
Test with curl:
curl --ftp-ssl --user username:password ftps://ftp.example.com/
Check the vsftpd log for connection details:
journalctl -u vsftpd