On this page 68 sections
  1. How FTP and vsftpd work
  2. Install vsftpd
  3. Main configuration file
  4. Listen configuration
  5. Local users
  6. Enable write operations
  7. Local umask
  8. Anonymous FTP
  9. Anonymous FTP root
  10. Anonymous downloads
  11. Anonymous uploads
  12. Create a dedicated anonymous upload directory
  13. Anonymous upload file permissions
  14. Chroot local users
  15. Chroot exception list
  16. Chroot only selected users
  17. Writable chroot
  18. User allow and deny lists
  19. Block users
  20. Allow only selected users
  21. PAM restrictions
  22. User home directories
  23. Per-user configuration
  24. Passive FTP
  25. Passive port range
  26. Passive address behind NAT
  27. Active FTP
  28. Firewall with UFW
  29. Maximum clients
  30. Connections per IP
  31. Idle session timeout
  32. Data connection timeout
  33. Login failure delay
  34. FTP banner
  35. Directory messages
  36. ASCII mode
  37. Logging transfers
  38. Log FTP protocol
  39. Syslog
  40. File ownership for anonymous uploads
  41. Download permissions
  42. Directory listing
  43. Hide files
  44. Deny access to files
  45. TLS / FTPS
  46. TLS certificate
  47. Disable anonymous access and require TLS for local users
  48. TLS protocol options
  49. Useful complete local-user configuration
  50. Useful anonymous read-only configuration
  51. Useful anonymous upload configuration
  52. Check Linux permissions
  53. Test FTP locally
  54. Test with curl
  55. FTP client commands
  56. Check configuration after changes
  57. Verify listening sockets
  58. Common problem: Connection refused
  59. Common problem: Login incorrect
  60. Common problem: Login works but upload fails
  61. Common problem: Directory listing hangs
  62. Common problem: Writable root inside chroot
  63. Inspect effective configuration quickly
  64. Search for one setting
  65. Backup and restore configuration
  66. Important configuration map
  67. FTP vs FTPS vs SFTP
  68. Recommended lab flow
01

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.

Check FTP port
ss -lntp | grep ':21'
02

Install vsftpd

On Debian and Ubuntu, vsftpd can be installed with APT.

Install vsftpd
sudo apt update
sudo apt install vsftpd
Check service status
sudo systemctl status vsftpd
Start vsftpd
sudo systemctl start vsftpd
Restart after configuration changes
sudo systemctl restart vsftpd
Enable at boot
sudo systemctl enable vsftpd
Check if the service is listening
sudo ss -lntp | grep vsftpd
03

Main configuration file

Most server behavior is controlled from /etc/vsftpd.conf.

Edit configuration
sudo nano /etc/vsftpd.conf
Create a backup
sudo cp /etc/vsftpd.conf /etc/vsftpd.conf.bak
Show active configuration only
grep -Ev '^[[:space:]]*(#|$)' /etc/vsftpd.conf
04

Listen 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.

05

Local users

local_enable allows local system accounts to authenticate to FTP.

### Configuration: Enable local users

```ini
local_enable=YES
`

Create a local FTP user
sudo adduser ftpuser
Test login
ftp SERVER_IP
06

Enable 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.

07

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.

08

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
`

09

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
`

Create anonymous directory
sudo mkdir -p /srv/ftp/anon
Inspect directory permissions
ls -ld /srv/ftp/anon
10

Anonymous 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
`

11

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.

12

Create a dedicated anonymous upload directory

Linux filesystem permissions must match the access model configured in vsftpd.

Create upload directory
sudo mkdir -p /srv/ftp/anon/uploads
Inspect ownership
ls -ld /srv/ftp/anon /srv/ftp/anon/uploads
13

Anonymous upload file permissions

anon_umask controls the permissions removed from anonymously uploaded files.

### Configuration: Anonymous umask

```ini
anon_umask=022
`

14

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.

15

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
`

Add a non-jailed user
echo "adminuser" | sudo tee -a /etc/vsftpd.chroot_list
View chroot exceptions
cat /etc/vsftpd.chroot_list
16

Chroot 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
`

17

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/.

18

User allow and deny lists

vsftpd can check usernames against a configurable user list.

### Configuration: Enable user-list processing

```ini
userlist_enable=YES
`

19

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
`

Block a user
echo "blockeduser" | sudo tee -a /etc/vsftpd.user_list
20

Allow 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
`

Add allowed user
echo "ftpuser" | sudo tee -a /etc/vsftpd.user_list
21

PAM 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
`

Inspect PAM configuration
cat /etc/pam.d/vsftpd
22

User 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.

23

Per-user configuration

Example:

```ini
local_root=/srv/ftp/sam
`

Create directory
sudo mkdir -p /etc/vsftpd/user_config
Example configuration for user sam
sudo nano /etc/vsftpd/user_config/sam
24

Passive 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
`

25

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.

26

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
`

27

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.

28

Firewall with UFW

The FTP control port and passive data range must be reachable.

Allow FTP control connection
sudo ufw allow 21/tcp
Allow passive range
sudo ufw allow 40000:40100/tcp
Show firewall rules
sudo ufw status
29

Maximum clients

vsftpd can limit the total number of simultaneous clients.

### Configuration: Limit simultaneous clients

```ini
max_clients=50
`

30

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
`

31

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.

32

Data connection timeout

A stalled data transfer can also be timed out.

### Configuration: Data timeout

```ini
data_connection_timeout=120
`

33

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.

34

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.

35

Directory messages

vsftpd can display directory-specific messages.

### Configuration: Enable directory messages

```ini
dirmessage_enable=YES
`

36

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.

37

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
`

Follow vsftpd log
sudo tail -f /var/log/vsftpd.log
38

Log 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.

39

Syslog

vsftpd can send its logging output through the system log facility.

### Configuration: Use syslog

```ini
syslog_enable=YES
`

Inspect service journal
sudo journalctl -u vsftpd
Follow service journal
sudo journalctl -fu vsftpd
40

File 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.

41

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.

42

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.

43

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.

44

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.

45

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
`

46

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.

47

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
`

48

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.

49

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
`

50

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
`

51

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.

52

Check Linux permissions

Many FTP problems are actually filesystem permission problems rather than vsftpd configuration problems.

Inspect path permissions
namei -l /srv/ftp/anon/uploads
Inspect directory
ls -ld /srv/ftp/anon/uploads
Inspect files
ls -la /srv/ftp/anon/uploads
53

Test FTP locally

Testing from the server itself helps separate daemon problems from firewall or NAT problems.

Connect locally
ftp 127.0.0.1
Test TCP port
nc -vz 127.0.0.1 21
54

Test with curl

Avoid putting real passwords directly in shell commands when command history or process visibility is a concern.

List FTP directory
curl ftp://SERVER_IP/
Authenticate with curl
curl -u username ftp://SERVER_IP/
Download file
curl -u username ftp://SERVER_IP/file.txt -o file.txt
Upload file
curl -u username -T file.txt ftp://SERVER_IP/
55

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
`

Open server
ftp SERVER_IP
56

Check configuration after changes

Restart the daemon and immediately inspect its status and logs.

Restart and check status
sudo systemctl restart vsftpd
sudo systemctl --no-pager --full status vsftpd
Show recent service errors
sudo journalctl -u vsftpd -n 50 --no-pager
57

Verify listening sockets

This confirms which address and port vsftpd is actually using.

Inspect port 21
sudo ss -lntp | grep ':21'
58

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.

Check service and socket
sudo systemctl status vsftpd
sudo ss -lntp | grep ':21'
59

Common problem: Login incorrect

Check the username, password, PAM configuration, user lists and whether local logins are enabled.

Check relevant settings
grep -E '^(local_enable|userlist_enable|userlist_deny|userlist_file|pam_service_name)=' /etc/vsftpd.conf
60

Common problem: Login works but upload fails

Check both write_enable and Linux filesystem permissions.

Check write configuration
grep -E '^(write_enable|local_umask|anon_upload_enable|anon_mkdir_write_enable)=' /etc/vsftpd.conf
Check destination permissions
namei -l /path/to/upload/directory
61

Common problem: Directory listing hangs

If authentication works but ls, downloads or uploads hang, investigate the FTP data connection, passive mode, firewall and NAT configuration.

Check passive settings
grep -E '^pasv_' /etc/vsftpd.conf
Check firewall
sudo ufw status
62

Common 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.

63

Inspect effective configuration quickly

Filtering comments and blank lines makes large default configuration files easier to review.

Show active directives
grep -Ev '^[[:space:]]*(#|$)' /etc/vsftpd.conf
64

Search for one setting

Find chroot configuration
grep -n 'chroot' /etc/vsftpd.conf
Find passive configuration
grep -n '^pasv_' /etc/vsftpd.conf
65

Backup and restore configuration

Always keep a known-good copy before experimenting with multiple directives.

Backup
sudo cp /etc/vsftpd.conf /etc/vsftpd.conf.bak
Restore
sudo cp /etc/vsftpd.conf.bak /etc/vsftpd.conf
sudo systemctl restart vsftpd
66

Important 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
`

67

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.

68

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
`