On this page 68 sections
- How FTP and vsftpd work
- Install vsftpd
- Main configuration file
- Listen configuration
- Local users
- Enable write operations
- Local umask
- Anonymous FTP
- Anonymous FTP root
- Anonymous downloads
- Anonymous uploads
- Create a dedicated anonymous upload directory
- Anonymous upload file permissions
- Chroot local users
- Chroot exception list
- Chroot only selected users
- Writable chroot
- User allow and deny lists
- Block users
- Allow only selected users
- PAM restrictions
- User home directories
- Per-user configuration
- Passive FTP
- Passive port range
- Passive address behind NAT
- Active FTP
- Firewall with UFW
- Maximum clients
- Connections per IP
- Idle session timeout
- Data connection timeout
- Login failure delay
- FTP banner
- Directory messages
- ASCII mode
- Logging transfers
- Log FTP protocol
- Syslog
- File ownership for anonymous uploads
- Download permissions
- Directory listing
- Hide files
- Deny access to files
- TLS / FTPS
- TLS certificate
- Disable anonymous access and require TLS for local users
- TLS protocol options
- Useful complete local-user configuration
- Useful anonymous read-only configuration
- Useful anonymous upload configuration
- Check Linux permissions
- Test FTP locally
- Test with curl
- FTP client commands
- Check configuration after changes
- Verify listening sockets
- Common problem: Connection refused
- Common problem: Login incorrect
- Common problem: Login works but upload fails
- Common problem: Directory listing hangs
- Common problem: Writable root inside chroot
- Inspect effective configuration quickly
- Search for one setting
- Backup and restore configuration
- Important configuration map
- FTP vs FTPS vs SFTP
- Recommended lab flow
How FTP and vsftpd work
vsftpd (Very Secure FTP Daemon) is an FTP server for Unix-like systems. FTP normally uses TCP port 21 for the control connection and a separate TCP connection for directory listings and file transfers.
The main configuration file is usually /etc/vsftpd.conf.
ss -lntp | grep ':21'Install vsftpd
On Debian and Ubuntu, vsftpd can be installed with APT.
sudo apt update
sudo apt install vsftpdsudo systemctl status vsftpdsudo systemctl start vsftpdsudo systemctl restart vsftpdsudo systemctl enable vsftpdsudo ss -lntp | grep vsftpdMain configuration file
Most server behavior is controlled from /etc/vsftpd.conf.
sudo nano /etc/vsftpd.confsudo cp /etc/vsftpd.conf /etc/vsftpd.conf.bakgrep -Ev '^[[:space:]]*(#|$)' /etc/vsftpd.confListen configuration
vsftpd can listen directly for incoming IPv4 connections.
### Configuration: Enable standalone IPv4 listener
```ini
listen=YES
listen_ipv6=NO`
On systems configured for IPv6, listen_ipv6=YES can be used instead. Do not normally enable both standalone listener options at the same time.
### Configuration: Change FTP control port
```ini
listen_port=21`
Changing the port does not encrypt or secure FTP; it only changes where the service listens.
Local users
local_enable allows local system accounts to authenticate to FTP.
### Configuration: Enable local users
```ini
local_enable=YES`
sudo adduser ftpuserftp SERVER_IPEnable write operations
FTP write commands are disabled unless write access is enabled globally.
### Configuration: Enable write commands
```ini
write_enable=YES`
This allows write operations when the authenticated user also has the required Linux filesystem permissions.
Local umask
local_umask controls which permission bits are removed when a local FTP user creates a file or directory.
The important point is that umask is a mask, not the final permission value.
### Default creation permissions
Linux normally starts with these maximum permissions:
```text
Files 666 → rw-rw-rw-
Directories 777 → rwxrwxrwx`
Files start from 666 rather than 777 because normal file creation does not automatically add execute permission.
### How to calculate umask
A useful mental model is:
```text
Final permissions = Base permissions with the umask bits removed`
For the common masks used with vsftpd, this is often written as:
```text
FILE
666
-022
----
644
DIRECTORY
777
-022
----
755`
Therefore:
```ini
local_umask=022
New file → 644 → rw-r--r--
New directory → 755 → rwxr-xr-x`
### Understanding the three digits
Each position represents a permission class:
```text
Owner Group Others
022 0 2 2`
Permission values are:
```text
4 = read
2 = write
1 = execute`
A 2 in the umask removes the write bit from that permission class.
For 022:
```text
Owner → remove nothing
Group → remove write
Others → remove write`
### Configuration: Standard local umask
```ini
local_umask=022`
Typical result:
```text
Files 644 rw-r--r--
Directories 755 rwxr-xr-x`
### Configuration: Group-private umask
```ini
local_umask=027`
Calculation:
```text
FILE
666
-027
----
640
DIRECTORY
777
-027
----
750`
Typical result:
```text
Files 640 rw-r-----
Directories 750 rwxr-x---`
### Configuration: Private user files
```ini
local_umask=077`
Calculation:
```text
FILE
666
-077
----
600
DIRECTORY
777
-077
----
700`
Typical result:
```text
Files 600 rw-------
Directories 700 rwx------`
### Common umask reference
| Umask | New file | New directory | Typical effect |
|---|---|---|---|
| 000 | 666 | 777 | Everyone can write |
| 002 | 664 | 775 | Owner/group collaborative |
| 022 | 644 | 755 | Common default |
| 027 | 640 | 750 | No access for others |
| 077 | 600 | 700 | Owner only |
### Important: subtraction is only a shortcut
The most accurate explanation is that the umask removes permission bits. Simple octal subtraction gives the expected result for common masks such as 022, 027, and 077, but the underlying operation is a bit mask.
Conceptually:
```text
final_mode = base_mode AND (NOT umask)`
Example with a file and umask 022:
```text
Base file permissions
666 → rw-rw-rw-
Umask
022 → ----w--w-
Remove those bits
644 → rw-r--r--`
### Anonymous user umask
Local and anonymous FTP users have separate vsftpd settings.
```ini
local_umask=022
anon_umask=077`
In this example:
```text
Local uploaded file → typically 644
Anonymous uploaded file → typically 600`
local_umask applies to local users, while anon_umask applies to anonymous uploads.
Anonymous FTP
Anonymous FTP allows users to connect without a normal local account.
### Configuration: Enable anonymous access
```ini
anonymous_enable=YES`
### Configuration: Disable anonymous access
```ini
anonymous_enable=NO`
Anonymous FTP root
anon_root changes the directory presented as the root of an anonymous FTP session.
### Configuration: Set anonymous root
```ini
anon_root=/srv/ftp/anon`
sudo mkdir -p /srv/ftp/anonls -ld /srv/ftp/anonAnonymous downloads
A common anonymous FTP design allows public downloads but prevents anonymous modification of files.
### Configuration: Anonymous read-only server
```ini
anonymous_enable=YES
anon_root=/srv/ftp/anon
write_enable=NO`
Anonymous uploads
write_enable=YES is only the global write switch. Anonymous users require additional anonymous-specific options.
### Configuration: Allow anonymous uploads
```ini
write_enable=YES
anon_upload_enable=YES`
The destination directory must also be writable by the account used internally for anonymous FTP.
### Configuration: Allow anonymous directory creation
```ini
anon_mkdir_write_enable=YES`
### Configuration: Allow additional anonymous write operations
```ini
anon_other_write_enable=YES`
This option permits anonymous FTP write operations other than upload and directory creation and should be enabled only when specifically required.
Create a dedicated anonymous upload directory
Linux filesystem permissions must match the access model configured in vsftpd.
sudo mkdir -p /srv/ftp/anon/uploadsls -ld /srv/ftp/anon /srv/ftp/anon/uploadsAnonymous upload file permissions
anon_umask controls the permissions removed from anonymously uploaded files.
### Configuration: Anonymous umask
```ini
anon_umask=022`
Chroot local users
A chroot jail restricts an FTP session to a specific filesystem subtree.
### Configuration: Jail all local users
```ini
chroot_local_user=YES`
For a typical user whose FTP root is the home directory, the user sees that location as / inside the FTP session.
Chroot exception list
The meaning of vsftpd.chroot_list depends on chroot_local_user.
When chroot_local_user=YES, users listed in the chroot list are exceptions and are not jailed.
### Configuration: Jail users except listed accounts
```ini
chroot_local_user=YES
chroot_list_enable=YES
chroot_list_file=/etc/vsftpd.chroot_list`
echo "adminuser" | sudo tee -a /etc/vsftpd.chroot_listcat /etc/vsftpd.chroot_listChroot only selected users
When chroot_local_user=NO, the list behavior is reversed: users in the list are jailed.
### Configuration: Jail only users in the list
```ini
chroot_local_user=NO
chroot_list_enable=YES
chroot_list_file=/etc/vsftpd.chroot_list`
Writable chroot
vsftpd may reject a configuration where the root of a chroot is writable by the FTP user.
### Configuration: Allow writable chroot root
```ini
allow_writeable_chroot=YES`
This is convenient for labs, but a cleaner design is often to keep the jail root non-writable and create a writable subdirectory such as uploads/.
User allow and deny lists
vsftpd can check usernames against a configurable user list.
### Configuration: Enable user-list processing
```ini
userlist_enable=YES`
Block users
With userlist_deny=YES, users present in the file are denied FTP login.
### Configuration: Deny listed users
```ini
userlist_enable=YES
userlist_deny=YES
userlist_file=/etc/vsftpd.user_list`
echo "blockeduser" | sudo tee -a /etc/vsftpd.user_listAllow only selected users
With userlist_deny=NO, only users present in the configured list are allowed by this user-list mechanism.
### Configuration: FTP allow-list
```ini
userlist_enable=YES
userlist_deny=NO
userlist_file=/etc/vsftpd.user_list`
echo "ftpuser" | sudo tee -a /etc/vsftpd.user_listPAM restrictions
vsftpd commonly uses PAM for local authentication. Distribution defaults may also prevent some system accounts from logging in.
### Configuration: PAM service name
```ini
pam_service_name=vsftpd`
cat /etc/pam.d/vsftpdUser home directories
By default, local FTP users normally start from their local login directory.
### Configuration: Force a local FTP root
```ini
local_root=/srv/ftp/users`
A per-user layout may require additional configuration or user-specific settings.
Per-user configuration
Example:
```ini
local_root=/srv/ftp/sam`
sudo mkdir -p /etc/vsftpd/user_configsudo nano /etc/vsftpd/user_config/samPassive FTP
Passive mode is commonly used when clients are behind NAT or firewalls.
In passive mode, the client creates both the control connection and the data connection.
### Configuration: Enable passive mode
```ini
pasv_enable=YES`
Passive port range
Restricting passive data connections to a known range simplifies firewall configuration.
### Configuration: Set passive range
```ini
pasv_min_port=40000
pasv_max_port=40100`
The firewall must allow TCP/21 and the configured passive TCP range.
Passive address behind NAT
If the FTP server is behind NAT, it may need to advertise its externally reachable address.
### Configuration: Advertise public address
```ini
pasv_address=203.0.113.10`
Use the actual externally reachable address for the server.
### Configuration: Resolve passive address from DNS
```ini
pasv_addr_resolve=YES
pasv_address=ftp.example.com`
Active FTP
Active mode uses a separate data connection initiated from the server toward the client.
### Configuration: Allow active mode
```ini
port_enable=YES`
Active FTP can be more difficult to use through client-side NAT and firewalls.
Firewall with UFW
The FTP control port and passive data range must be reachable.
sudo ufw allow 21/tcpsudo ufw allow 40000:40100/tcpsudo ufw statusMaximum clients
vsftpd can limit the total number of simultaneous clients.
### Configuration: Limit simultaneous clients
```ini
max_clients=50`
Connections per IP
A separate limit can restrict concurrent clients from the same source address.
### Configuration: Limit clients per IP
```ini
max_per_ip=5`
Idle session timeout
Idle control sessions can be disconnected automatically.
### Configuration: Control connection timeout
```ini
idle_session_timeout=600`
The value is expressed in seconds.
Data connection timeout
A stalled data transfer can also be timed out.
### Configuration: Data timeout
```ini
data_connection_timeout=120`
Login failure delay
A delay can be introduced after failed authentication attempts.
### Configuration: Failed login delay
```ini
delay_failed_login=3`
The value is expressed in seconds.
FTP banner
A custom banner can be displayed when clients connect.
### Configuration: Custom banner
```ini
ftpd_banner=Authorized FTP service`
Avoid exposing unnecessary server or environment information in banners.
Directory messages
vsftpd can display directory-specific messages.
### Configuration: Enable directory messages
```ini
dirmessage_enable=YES`
ASCII mode
FTP historically supports ASCII-mode file transformations. Binary transfers are normally preferable for arbitrary files.
### Configuration: Allow ASCII download and upload
```ini
ascii_download_enable=YES
ascii_upload_enable=YES`
These options are usually unnecessary for modern general-purpose file transfer.
Logging transfers
Transfer logging is useful for auditing and troubleshooting.
### Configuration: Enable transfer log
```ini
xferlog_enable=YES`
### Configuration: Standard vsftpd log
```ini
xferlog_std_format=NO
vsftpd_log_file=/var/log/vsftpd.log`
sudo tail -f /var/log/vsftpd.logLog FTP protocol
Protocol-level logging can show FTP commands and responses and is especially useful in a lab.
### Configuration: Enable protocol logging
```ini
log_ftp_protocol=YES`
Protocol logs can contain sensitive session information, so use them carefully on production systems.
Syslog
vsftpd can send its logging output through the system log facility.
### Configuration: Use syslog
```ini
syslog_enable=YES`
sudo journalctl -u vsftpdsudo journalctl -fu vsftpdFile ownership for anonymous uploads
vsftpd can change ownership of anonymously uploaded files.
### Configuration: Change ownership of uploaded anonymous files
```ini
chown_uploads=YES
chown_username=ftpowner`
Use a dedicated non-privileged account rather than a privileged system account.
Download permissions
download_enable controls whether downloads are permitted.
### Configuration: Disable downloads
```ini
download_enable=NO`
This can be useful for an upload-only workflow when combined with appropriate directory permissions and other restrictions.
Directory listing
Directory listing commands can be disabled.
### Configuration: Disable directory listings
```ini
dirlist_enable=NO`
Users may still be able to access a known filename depending on the remaining configuration and filesystem permissions.
Hide files
Files matching a pattern can be hidden from directory listings.
### Configuration: Hide dotfiles
```ini
hide_file={.*}`
Hiding a file is not an access-control mechanism.
Deny access to files
deny_file can deny FTP access to paths matching a pattern.
### Configuration: Deny access to hidden files
```ini
deny_file={.*}`
Filesystem permissions should still be used as the primary access-control mechanism.
TLS / FTPS
Plain FTP does not encrypt authentication credentials or transferred data. vsftpd supports FTP over TLS, commonly called FTPS.
### Configuration: Enable TLS
```ini
ssl_enable=YES`
### Configuration: Require encrypted local logins
```ini
force_local_logins_ssl=YES`
### Configuration: Require encrypted data transfers
```ini
force_local_data_ssl=YES`
TLS certificate
vsftpd needs a certificate and private key.
### Configuration: Certificate paths
```ini
rsa_cert_file=/etc/ssl/certs/vsftpd.pem
rsa_private_key_file=/etc/ssl/private/vsftpd.key`
Use certificate files appropriate for your environment.
Disable anonymous access and require TLS for local users
A useful starting point for a local-user FTPS server is:
### Configuration: Local users with TLS
```ini
anonymous_enable=NO
local_enable=YES
write_enable=YES
local_umask=022
chroot_local_user=YES
ssl_enable=YES
force_local_logins_ssl=YES
force_local_data_ssl=YES
rsa_cert_file=/etc/ssl/certs/vsftpd.pem
rsa_private_key_file=/etc/ssl/private/vsftpd.key`
TLS protocol options
Older SSL/TLS versions should not be enabled merely for compatibility unless the environment specifically requires them.
### Configuration: Disable obsolete SSL protocols
```ini
ssl_sslv2=NO
ssl_sslv3=NO`
Available TLS-related directives can vary with the vsftpd build and distribution version. Check the installed manual before applying version-specific TLS settings.
Useful complete local-user configuration
This example enables local users, uploads, chroot isolation, passive mode and logging.
### Configuration: Local FTP server
```ini
listen=YES
listen_ipv6=NO
anonymous_enable=NO
local_enable=YES
write_enable=YES
local_umask=022
chroot_local_user=YES
allow_writeable_chroot=YES
userlist_enable=YES
userlist_deny=YES
userlist_file=/etc/vsftpd.user_list
pasv_enable=YES
pasv_min_port=40000
pasv_max_port=40100
xferlog_enable=YES
log_ftp_protocol=YES
idle_session_timeout=600
data_connection_timeout=120`
Useful anonymous read-only configuration
This configuration creates a simple public download server.
### Configuration: Anonymous download server
```ini
listen=YES
listen_ipv6=NO
anonymous_enable=YES
local_enable=NO
anon_root=/srv/ftp/anon
write_enable=NO
pasv_enable=YES
pasv_min_port=40000
pasv_max_port=40100
xferlog_enable=YES`
Useful anonymous upload configuration
Anonymous upload servers require special care because both vsftpd settings and Linux filesystem permissions affect the result.
### Configuration: Anonymous upload example
```ini
anonymous_enable=YES
anon_root=/srv/ftp/anon
write_enable=YES
anon_upload_enable=YES
anon_mkdir_write_enable=YES
anon_umask=022
pasv_enable=YES
pasv_min_port=40000
pasv_max_port=40100
xferlog_enable=YES`
Prefer a dedicated writable subdirectory rather than making the anonymous FTP root broadly writable.
Check Linux permissions
Many FTP problems are actually filesystem permission problems rather than vsftpd configuration problems.
namei -l /srv/ftp/anon/uploadsls -ld /srv/ftp/anon/uploadsls -la /srv/ftp/anon/uploadsTest FTP locally
Testing from the server itself helps separate daemon problems from firewall or NAT problems.
ftp 127.0.0.1nc -vz 127.0.0.1 21Test with curl
Avoid putting real passwords directly in shell commands when command history or process visibility is a concern.
curl ftp://SERVER_IP/curl -u username ftp://SERVER_IP/curl -u username ftp://SERVER_IP/file.txt -o file.txtcurl -u username -T file.txt ftp://SERVER_IP/FTP client commands
Inside the FTP client:
```bash
ls
pwd
cd directory
lcd local-directory
get file.txt
put file.txt
mget *.txt
mput *.txt
binary
passive
delete file.txt
mkdir directory
rmdir directory
bye`
ftp SERVER_IPCheck configuration after changes
Restart the daemon and immediately inspect its status and logs.
sudo systemctl restart vsftpd
sudo systemctl --no-pager --full status vsftpdsudo journalctl -u vsftpd -n 50 --no-pagerVerify listening sockets
This confirms which address and port vsftpd is actually using.
sudo ss -lntp | grep ':21'Common problem: Connection refused
A refused connection usually means no service is listening on the target address and port, or a network policy is actively rejecting it.
sudo systemctl status vsftpd
sudo ss -lntp | grep ':21'Common problem: Login incorrect
Check the username, password, PAM configuration, user lists and whether local logins are enabled.
grep -E '^(local_enable|userlist_enable|userlist_deny|userlist_file|pam_service_name)=' /etc/vsftpd.confCommon problem: Login works but upload fails
Check both write_enable and Linux filesystem permissions.
grep -E '^(write_enable|local_umask|anon_upload_enable|anon_mkdir_write_enable)=' /etc/vsftpd.confnamei -l /path/to/upload/directoryCommon problem: Directory listing hangs
If authentication works but ls, downloads or uploads hang, investigate the FTP data connection, passive mode, firewall and NAT configuration.
grep -E '^pasv_' /etc/vsftpd.confsudo ufw statusCommon problem: Writable root inside chroot
A chrooted user may be rejected when the chroot root is writable.
### Configuration: Lab workaround
```ini
allow_writeable_chroot=YES`
A stronger directory design is to keep the jail root owned and non-writable by the FTP user and provide a writable subdirectory.
Inspect effective configuration quickly
Filtering comments and blank lines makes large default configuration files easier to review.
grep -Ev '^[[:space:]]*(#|$)' /etc/vsftpd.confSearch for one setting
grep -n 'chroot' /etc/vsftpd.confgrep -n '^pasv_' /etc/vsftpd.confBackup and restore configuration
Always keep a known-good copy before experimenting with multiple directives.
sudo cp /etc/vsftpd.conf /etc/vsftpd.conf.baksudo cp /etc/vsftpd.conf.bak /etc/vsftpd.conf
sudo systemctl restart vsftpdImportant configuration map
The most useful directives to remember are:
```ini
# Anonymous users
anonymous_enable=YES
anon_root=/srv/ftp/anon
anon_upload_enable=YES
anon_mkdir_write_enable=YES
anon_other_write_enable=YES
anon_umask=022
# Local users
local_enable=YES
local_root=/path
local_umask=022
# Writes
write_enable=YES
# Chroot
chroot_local_user=YES
chroot_list_enable=YES
chroot_list_file=/etc/vsftpd.chroot_list
allow_writeable_chroot=YES
# User access control
userlist_enable=YES
userlist_deny=YES
userlist_file=/etc/vsftpd.user_list
# Passive FTP
pasv_enable=YES
pasv_min_port=40000
pasv_max_port=40100
pasv_address=PUBLIC_IP
# Logging
xferlog_enable=YES
log_ftp_protocol=YES
vsftpd_log_file=/var/log/vsftpd.log
# Limits
max_clients=50
max_per_ip=5
idle_session_timeout=600
data_connection_timeout=120
# TLS / FTPS
ssl_enable=YES
force_local_logins_ssl=YES
force_local_data_ssl=YES
rsa_cert_file=/etc/ssl/certs/vsftpd.pem
rsa_private_key_file=/etc/ssl/private/vsftpd.key`
FTP vs FTPS vs SFTP
FTP, FTPS and SFTP should not be treated as the same protocol.
```bash
FTP → File Transfer Protocol, normally control connection on TCP/21
FTPS → FTP protected with TLS
SFTP → SSH File Transfer Protocol, normally over SSH/TCP 22`
SFTP is part of the SSH ecosystem and does not use vsftpd.
Recommended lab flow
A useful order for learning and demonstrating vsftpd is:
```bash
1. Install vsftpd
2. Verify TCP/21
3. Test anonymous access
4. Configure anon_root
5. Enable local users
6. Enable uploads
7. Observe Linux permissions and umask
8. Jail local users with chroot
9. Add chroot exceptions
10. Block selected users
11. Configure passive ports
12. Configure firewall rules
13. Enable logging
14. Observe FTP traffic
15. Add TLS / FTPS`