How to Configure an FTP Server in Linux

how to configure FTP server in Linux

Running your own FTP server allows you to share files with other users or systems on a network in a controlled, structured way. This article explains, from first principles, how FTP servers work, and walks through installing and configuring vsftpd (Very Secure FTP Daemon) — the most widely used FTP server on Linux — including securing it with TLS, setting up user permissions, and troubleshooting common issues.

Why vsftpd?

There are several FTP server implementations for Linux (proftpd, pure-ftpd, vsftpd), but vsftpd is the most common default choice because of its strong security track record, simplicity, and wide distribution support.

flowchart LR
    A["FTP Client"] -- "Control: port 21" --> B["vsftpd Server"]
    A -- "Data: passive port range" --> B
    B --> C["/srv/ftp Filesystem"]

Step 1: Installing vsftpd

sudo apt update
sudo apt install vsftpd          # Debian/Ubuntu
sudo dnf install vsftpd          # RHEL/Fedora

Step 2: Starting and Enabling the Service

sudo systemctl enable --now vsftpd
sudo systemctl status vsftpd

Step 3: Understanding the Main Configuration File

The primary configuration file is /etc/vsftpd.conf (Debian/Ubuntu) or /etc/vsftpd/vsftpd.conf (RHEL/Fedora). Always back it up before editing:

sudo cp /etc/vsftpd.conf /etc/vsftpd.conf.bak

Step 4: Basic Secure Configuration

Edit the config file:

sudo nano /etc/vsftpd.conf

Key settings to review and set:

# Disable anonymous login (recommended for most use cases)
anonymous_enable=NO

# Allow local system users to log in
local_enable=YES

# Allow uploads
write_enable=YES

# Restrict users to their home directory (chroot jail)
chroot_local_user=YES

# Set a reasonable default umask for uploaded files
local_umask=022

# Enable logging
xferlog_enable=YES
xferlog_file=/var/log/vsftpd.log

# Passive mode port range (important for firewall rules)
pasv_enable=YES
pasv_min_port=40000
pasv_max_port=40100

After editing, restart the service:

sudo systemctl restart vsftpd

Step 5: Opening Firewall Ports

FTP needs the control port (21) and the entire passive port range open:

sudo ufw allow 21/tcp
sudo ufw allow 40000:40100/tcp

Or with firewalld on RHEL/CentOS:

sudo firewall-cmd --permanent --add-port=21/tcp
sudo firewall-cmd --permanent --add-port=40000-40100/tcp
sudo firewall-cmd --reload

Step 6: Creating an FTP-Only User

For security, it’s common to create dedicated accounts for FTP access that don’t have shell access to the whole system:

sudo useradd -m -d /home/ftpuser -s /usr/sbin/nologin ftpuser
sudo passwd ftpuser

Setting chroot_local_user=YES (from Step 4) confines this user to their own home directory, preventing them from browsing the rest of the filesystem.

Step 7: Securing FTP With TLS (FTPS)

Plain FTP transmits credentials and data unencrypted. Enabling TLS (turning FTP into FTPS) is strongly recommended for anything beyond an isolated internal network.

Generate a self-signed certificate (or use one from Let’s Encrypt for a production server):

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

Add TLS settings to vsftpd.conf:

ssl_enable=YES
rsa_cert_file=/etc/ssl/private/vsftpd.pem
rsa_private_key_file=/etc/ssl/private/vsftpd.pem
force_local_data_ssl=YES
force_local_logins_ssl=YES
ssl_tlsv1=YES
ssl_sslv2=NO
ssl_sslv3=NO

Restart the service:

sudo systemctl restart vsftpd

Clients now must connect using FTPS (explicit TLS) rather than plain FTP.

Step 8: Configuring Anonymous Access (Optional, Use With Caution)

For public file distribution (like a public software mirror), anonymous access can be useful, but should be read-only and carefully sandboxed:

anonymous_enable=YES
anon_root=/srv/ftp/public
anon_upload_enable=NO
anon_mkdir_write_enable=NO
no_anon_password=YES

A Complete Example Configuration

listen=YES
listen_ipv6=NO
anonymous_enable=NO
local_enable=YES
write_enable=YES
local_umask=022
dirmessage_enable=YES
xferlog_enable=YES
xferlog_file=/var/log/vsftpd.log
connect_from_port_20=YES
chroot_local_user=YES
allow_writeable_chroot=YES
pasv_enable=YES
pasv_min_port=40000
pasv_max_port=40100
ssl_enable=YES
rsa_cert_file=/etc/ssl/private/vsftpd.pem
rsa_private_key_file=/etc/ssl/private/vsftpd.pem
force_local_data_ssl=YES
force_local_logins_ssl=YES

Comparison: vsftpd vs. Other FTP Servers

ServerEase of SetupSecurity Track RecordCommon Use Case
vsftpdEasyExcellentGeneral-purpose, security-focused default
ProFTPdModerate (highly configurable)GoodComplex, module-heavy setups
Pure-FTPdEasyGoodSimple virtual-user hosting setups

Real-World Use Case: Internal File Drop for a Branch Office

A company wants a branch office to upload daily sales reports to headquarters over FTPS.

Step 1: Create a dedicated user:

sudo useradd -m -s /usr/sbin/nologin branch01
sudo passwd branch01

Step 2: Restrict them to an uploads-only directory using chroot and directory permissions:

sudo mkdir -p /home/branch01/uploads
sudo chown branch01:branch01 /home/branch01/uploads
sudo chmod 750 /home/branch01/uploads

Step 3: Confirm chroot_local_user=YES and force_local_data_ssl=YES are set, then restart:

sudo systemctl restart vsftpd

Step 4: The branch office connects using an FTPS-capable client (e.g., FileZilla in FTPS mode) and uploads their daily report to the uploads folder.

Best Practices

  • Disable anonymous access unless you specifically need public, unauthenticated file sharing.
  • Always enable TLS (FTPS) for anything beyond a fully isolated, trusted internal network.
  • Chroot users into their home directories to prevent them from browsing or modifying files outside their designated area.
  • Use dedicated FTP-only accounts with nologin shells rather than full system accounts.
  • Restrict the passive port range to a small, known range, and open exactly that range in your firewall — don’t open large arbitrary port ranges.
  • Monitor /var/log/vsftpd.log regularly for failed login attempts or unusual activity.
  • Consider SFTP instead of FTP/FTPS entirely for new deployments, since it reuses your existing SSH infrastructure and is generally simpler to secure.

Troubleshooting

Problem: 500 OOPS: vsftpd: refusing to run with writable root inside chroot()

Modern vsftpd refuses to start if a chrooted user’s home directory is writable by that same user (a security protection). Fix by either making the home directory read-only and creating a writable subdirectory, or explicitly allowing it:

allow_writeable_chroot=YES

Problem: Client can log in but ls hangs

This is a classic passive-mode/firewall issue. Confirm the passive port range is open in your firewall and matches the pasv_min_port/pasv_max_port settings.

Problem: Uploads fail with “Permission denied”

Check both the Linux filesystem permissions on the target directory and write_enable=YES in the config:

ls -ld /home/ftpuser/uploads

Problem: TLS handshake fails

Verify certificate paths are correct and readable by the vsftpd process:

sudo journalctl -u vsftpd -n 50

Problem: Service won’t start after config changes

Check syntax and permissions on the config file, and review logs:

sudo systemctl status vsftpd
sudo journalctl -u vsftpd -n 50

Conclusion

Setting up a Linux FTP server with vsftpd is straightforward once you understand the key building blocks: the control/data channel model, chroot jails for user isolation, passive port ranges for firewall compatibility, and TLS for encryption. Following the security-first defaults in this guide — disabling anonymous access, enforcing FTPS, and chrooting users — gives you a solid, production-ready file transfer service, while still leaving open the option to migrate to SFTP for even simpler, SSH-based security in the future.

Further Reading

Total
1
Shares

Leave a Reply

Previous Post
how to use web browser as an FTP client

How to Use a Web Browser as an FTP Client

Next Post
how to use command line FTP client in linux

How to Use the Command-Line FTP Client in Linux

Related Posts