FTP servers often struggle with user management, forcing you to sync local system users with FTP accounts, which is a security and administrative nightmare.

Let’s see how vsftpd handles virtual users, a much cleaner approach. Imagine a user ftpuser who only exists within the FTP server’s configuration, not on the Linux filesystem.

# On the FTP server
sudo systemctl stop vsftpd

# Create a virtual user database file
sudo tee /etc/vsftpd/virtual_users.txt <<EOF
alice
mysecretpassword
bob
anotherpwd
EOF

# Create a DBM database from the text file
sudo db_load -T -t hash -f /etc/vsftpd/virtual_users.txt /etc/vsftpd/virtual_users.txt.db

# Set correct ownership and permissions for the DBM file
sudo chown root:root /etc/vsftpd/virtual_users.txt.db
sudo chmod 600 /etc/vsftpd/virtual_users.txt.db

# Configure vsftpd to use the DBM file for authentication
sudo tee -a /etc/vsftpd.conf <<EOF

# Virtual user configuration
guest_enable=YES
guest_username=ftp
user_sub_token=$USER
local_root=/var/ftp/users/$USER
virtual_use_local_privs=YES
userlist_enable=YES
userlist_file=/etc/vsftpd/user_list
userlist_deny=NO

# PAM configuration (we'll cover this next)
# pam_service_name=vsftpd
EOF

# Create the user list file and add our virtual users
sudo tee /etc/vsftpd/user_list <<EOF
alice
bob
EOF

# Create the home directory structure for virtual users
sudo mkdir -p /var/ftp/users/alice
sudo mkdir -p /var/ftp/users/bob

# Set ownership for the home directories to the system user that virtual users will map to
# In this case, we'll map to 'ftp' as specified by guest_username
sudo chown ftp:ftp /var/ftp/users/alice
sudo chown ftp:ftp /var/ftp/users/bob

# Ensure the virtual user list is readable by the vsftpd process
sudo chown root:root /etc/vsftpd/user_list
sudo chmod 644 /etc/vsftpd/user_list

# Start vsftpd
sudo systemctl start vsftpd

This setup bypasses standard Linux user accounts for FTP logins. guest_enable=YES tells vsftpd to treat all incoming users as guests, and guest_username=ftp maps these guests to the system user ftp. user_sub_token=$USER combined with local_root=/var/ftp/users/$USER dynamically creates home directories based on the logged-in virtual username (e.g., /var/ftp/users/alice). The virtual_users.txt.db file acts as the password database.

Now, let’s talk about PAM. PAM (Pluggable Authentication Modules) is what actually handles the authentication checks. By default, vsftpd might use its own built-in methods or a system PAM configuration. For virtual users, we often want a dedicated PAM configuration to keep things separate and secure.

# Create a custom PAM configuration file for vsftpd
sudo tee /etc/pam.d/vsftpd_virtual <<EOF
#%PAM-1.0
auth    required     pam_userdb.so db=/etc/vsftpd/virtual_users.txt
account required     pam_userdb.so db=/etc/vsftpd/virtual_users.txt
session required     pam_loginuid.so
session optional     pam_keyinit.so
session required     pam_limits.so
session required     pam_unix.so
EOF

# Update vsftpd.conf to point to this custom PAM service
sudo sed -i 's/#pam_service_name=vsftpd/pam_service_name=vsftpd_virtual/' /etc/vsftpd.conf

# Restart vsftpd to apply the PAM configuration changes
sudo systemctl restart vsftpd

Here, pam_userdb.so is the key module. It’s configured to use our virtual_users.txt.db file for both authentication (auth) and account management (account). This means when a user like alice tries to log in, PAM checks alice and mysecretpassword against the DBM file, completely ignoring /etc/passwd. The session modules handle things like setting up the user’s environment.

The most surprising thing about pam_userdb.so is that it doesn’t dynamically create users on the system. It only performs the authentication check against the specified database file. This isolation is precisely why it’s so powerful for virtual users—you can have dozens of FTP users with complex passwords without cluttering your /etc/passwd file or needing to useradd them on the server. The guest_username parameter in vsftpd.conf is still crucial because the operating system still needs some user context for file permissions and process ownership, even if the login credentials aren’t directly tied to that OS user.

If you’ve configured virtual users and PAM correctly, the next thing you’ll likely encounter is setting up passive mode FTP, which involves firewall rules and specific vsftpd configuration parameters for the data connection.

Want structured learning?

Take the full Ftp course →