Software & Configuration

FTP Server (vsftpd)

Install and configure vsftpd as a secure FTP server on Linux with virtual users, chroot jail, and passive mode

vsftpd (Very Secure FTP Daemon) is the standard FTP server on Ubuntu/Debian. This guide sets it up with a chroot jail (users can't browse outside their home directory), passive mode for firewall compatibility, and optional TLS encryption.

Plain FTP transmits credentials and data in cleartext. Use FTPS (FTP over TLS) as configured in this guide, or prefer SFTP (SSH-based, no additional setup needed, already enabled if SSH is running).


Installation

sudo apt update
sudo apt install vsftpd -y
sudo systemctl enable vsftpd

Basic configuration

Back up the default config and replace it:

sudo cp /etc/vsftpd.conf /etc/vsftpd.conf.bak
sudo nano /etc/vsftpd.conf
# Disable anonymous access
anonymous_enable=NO

# Allow local Linux users to log in
local_enable=YES
write_enable=YES
local_umask=022

# Chroot users to their home directory
chroot_local_user=YES
allow_writeable_chroot=YES

# Passive mode (required for most firewalls/NAT)
pasv_enable=YES
pasv_min_port=40000
pasv_max_port=50000
pasv_address=YOUR_SERVER_IP

# Logging
xferlog_enable=YES
xferlog_file=/var/log/vsftpd.log

# Hide server identity
ftpd_banner=FTP Server

# Restrict to FTP users list (optional)
userlist_enable=YES
userlist_file=/etc/vsftpd.userlist
userlist_deny=NO

Apply:

sudo systemctl restart vsftpd

Create an FTP user

# Create user with no shell access (FTP only)
sudo useradd -m -s /usr/sbin/nologin ftpuser1
sudo passwd ftpuser1

# Add to allowed users list
echo "ftpuser1" | sudo tee -a /etc/vsftpd.userlist

Set the home directory as the FTP root:

sudo mkdir -p /home/ftpuser1/files
sudo chown ftpuser1:ftpuser1 /home/ftpuser1/files

With chroot_local_user=YES, the user's home directory must not be writable by the user (vsftpd requirement). Create a subdirectory (/home/ftpuser1/files) for uploads instead, or set allow_writeable_chroot=YES.


Enable FTPS (FTP over TLS)

Generate a self-signed certificate (or use your Let's Encrypt cert):

sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout /etc/ssl/private/vsftpd.key \
  -out /etc/ssl/certs/vsftpd.crt

Or use Let's Encrypt:

sudo ln -s /etc/letsencrypt/live/example.com/fullchain.pem /etc/ssl/certs/vsftpd.crt
sudo ln -s /etc/letsencrypt/live/example.com/privkey.pem /etc/ssl/private/vsftpd.key

Add to /etc/vsftpd.conf:

# Enable TLS
ssl_enable=YES
rsa_cert_file=/etc/ssl/certs/vsftpd.crt
rsa_private_key_file=/etc/ssl/private/vsftpd.key

# Require TLS for data and login
force_local_data_ssl=YES
force_local_logins_ssl=YES

# TLS settings
ssl_tlsv1_2=YES
ssl_sslv2=NO
ssl_sslv3=NO
require_ssl_reuse=NO
ssl_ciphers=HIGH

Restart:

sudo systemctl restart vsftpd

Firewall rules

# FTP control port
sudo ufw allow 21/tcp

# Passive mode data ports
sudo ufw allow 40000:50000/tcp

Virtual users (isolated FTP accounts)

For hosting multiple FTP accounts without creating Linux users, use PAM virtual users:

Install required packages:

sudo apt install libpam-pwdfile apache2-utils -y

Create the virtual users password file:

sudo htpasswd -c -B /etc/vsftpd/vpasswd client1
sudo htpasswd -B /etc/vsftpd/vpasswd client2

Create PAM config:

sudo nano /etc/pam.d/vsftpd-virtual
auth required pam_pwdfile.so pwdfile /etc/vsftpd/vpasswd
account required pam_permit.so

Update vsftpd.conf:

# Disable local user login, use virtual users
local_enable=NO
virtual_use_local_privs=YES
guest_enable=YES
guest_username=ftp
pam_service_name=vsftpd-virtual
user_sub_token=$USER
local_root=/var/ftp/users/$USER

Create home directories for virtual users:

sudo mkdir -p /var/ftp/users/client1
sudo mkdir -p /var/ftp/users/client2
sudo chown -R ftp:ftp /var/ftp/users/

Logs and monitoring

# Live connection log
sudo tail -f /var/log/vsftpd.log

# Active connections
sudo netstat -tnp | grep :21

# Service status
sudo systemctl status vsftpd

Troubleshoot common issues

ErrorCauseFix
500 OOPS: vsftpd: refusing to run with writable root inside chrootHome dir is writableAdd allow_writeable_chroot=YES or chmod a-w /home/user
530 Login incorrectUser not in userlistAdd username to /etc/vsftpd.userlist
425 Failed to establish connectionPassive ports blockedOpen ports 40000-50000 in firewall
TLS handshake failedCertificate issueCheck cert path and permissions

On this page