FTP/SFTP Server with vsftpd: Complete Setup Guide
Introduction
File Transfer Protocol (FTP) has served as a fundamental method for transferring files across networks since 1971, making it one of the internet's oldest protocols still in widespread use. While modern alternatives like SFTP, SCP, and cloud storage have emerged, FTP remains ubiquitous in web hosting, legacy system integration, automated file exchanges, and scenarios requiring simple, universal file transfer capabilities.
vsftpd (Very Secure FTP Daemon) stands as the most popular FTP server implementation for Linux systems, powering millions of servers worldwide. Designed with security as the primary focus, vsftpd emphasizes simplicity, performance, and stability while supporting both traditional FTP and secure connections via SSL/TLS (FTPS). Combined with SFTP (SSH File Transfer Protocol) provided by OpenSSH, you can offer both legacy FTP support and modern secure file transfer from a single server.
This comprehensive guide walks you through deploying a production-ready FTP/SFTP server using vsftpd and OpenSSH. You'll learn installation procedures, user management, security hardening with SSL/TLS, chroot jails, virtual users, passive mode configuration, bandwidth limiting, monitoring, and troubleshooting techniques.
Whether hosting a web development environment, providing file upload capabilities for clients, building an automated file exchange system, supporting legacy applications requiring FTP, or creating a secure file transfer service for your organization, this guide provides everything needed for professional FTP/SFTP deployment.
Use Case Overview
Why Deploy an FTP/SFTP Server?
FTP and SFTP servers provide critical file transfer capabilities for various scenarios:
Web Hosting and Development: Web developers and designers need simple, reliable methods to upload website files to servers. FTP clients integrated into development tools provide familiar workflows.
Client File Exchange: Businesses sharing files with customers, vendors, or partners benefit from FTP's universal client support and straightforward access model compared to complex collaboration platforms.
Automated Data Transfers: Systems requiring scheduled, automated file transfers (backup systems, data synchronization, report delivery) leverage FTP's scriptable nature and wide protocol support.
Legacy System Integration: Many enterprise applications, industrial systems, and government platforms mandate FTP support for data interchange, making FTP servers essential for integration.
Bulk File Distribution: Distributing large files or software packages to numerous recipients efficiently through direct FTP access rather than bandwidth-intensive downloads.
Secure File Storage: SFTP provides encrypted file transfer and storage, ideal for sensitive documents, financial data, healthcare records, or confidential business information.
Media Production Workflows: Video production houses, photography studios, and graphic design agencies transferring large media files between locations and team members.
IoT Device Communication: Internet of Things devices uploading sensor data, camera footage, or telemetry information to centralized servers for processing and analysis.
FTP vs SFTP vs FTPS
Understanding the differences between protocols:
FTP (File Transfer Protocol):
- Transport: Plain text, unencrypted
- Ports: 21 (control), 20 (data) + random high ports (passive mode)
- Security: None, credentials and data transmitted in clear text
- Use Case: Legacy systems, non-sensitive public data
- Firewall: Complex due to multiple ports and passive mode requirements
FTPS (FTP over SSL/TLS):
- Transport: Encrypted via SSL/TLS
- Ports: 21 (control), 20 (data) + configured passive range
- Security: Strong encryption for credentials and data
- Use Case: Secure FTP when legacy FTP client compatibility required
- Firewall: Still complex but secure
SFTP (SSH File Transfer Protocol):
- Transport: SSH protocol (not FTP-based)
- Ports: 22 (single port for all traffic)
- Security: Strong SSH encryption and authentication
- Use Case: Modern secure file transfer, recommended for new deployments
- Firewall: Simple, single port
Common Deployment Scenarios
Web Development Server: Developers uploading HTML, CSS, JavaScript, and PHP files to staging or production web servers using FTP clients like FileZilla.
Client Portal: Accounting firms, law offices, or consultancies providing secure file exchange portals for clients to upload and download sensitive documents.
Backup Destination: Network backup systems transferring incremental backups to centralized FTP servers for disaster recovery and archival purposes.
Content Management: Publishing workflows where journalists, writers, or content creators upload articles, images, and videos to CMS platforms via FTP.
E-commerce Integration: Online stores exchanging product catalogs, inventory data, and order information with suppliers, drop-shippers, or fulfillment partners.
Data Analytics: Business intelligence systems ingesting CSV files, database exports, or log files from various sources via automated FTP transfers.
Scientific Data Exchange: Research institutions sharing large datasets, experimental results, or genomic data with collaborators worldwide.
Requirements
System Requirements
Minimum Requirements (Personal/Small Site, 1-10 users):
- CPU: 1 core at 1.5+ GHz
- RAM: 512MB
- Storage: Depends on data storage needs (minimum 10GB)
- Network: 10 Mbps bandwidth
- OS: Ubuntu 20.04/22.04, Debian 11/12, CentOS 8, Rocky Linux 8/9
Recommended Requirements (Business, 10-50 users):
- CPU: 2 cores at 2.0+ GHz
- RAM: 2GB
- Storage: 100GB-1TB SSD
- Network: 100 Mbps bandwidth
- OS: Ubuntu 22.04 LTS
High-Performance Requirements (Enterprise, 100+ concurrent connections):
- CPU: 4+ cores at 2.5+ GHz
- RAM: 8GB+
- Storage: 1TB+ SSD or RAID array
- Network: 1 Gbps dedicated bandwidth
- OS: Ubuntu 22.04 LTS
Network Requirements
Port Configuration:
- FTP Control: 21/TCP
- FTP Data (Active): 20/TCP
- FTP Data (Passive): Configurable range (e.g., 50000-50100/TCP)
- SFTP: 22/TCP (shared with SSH)
- FTPS Control: 21/TCP (with TLS)
- FTPS Data: Passive range with TLS
Firewall Considerations: FTP passive mode requires opening a range of high ports. SFTP uses only port 22, simplifying firewall configuration.
NAT/Routing: FTP active mode requires bidirectional connectivity. Behind NAT, passive mode is required.
Software Requirements
vsftpd: Version 3.0+ recommended for latest security and features.
OpenSSH Server: For SFTP functionality (typically pre-installed).
SSL/TLS Certificates: For FTPS encryption (Let's Encrypt or self-signed).
Optional Components:
- ProFTPD: Alternative to vsftpd with more features
- Pure-FTPd: Another secure FTP daemon option
- fail2ban: Protection against brute-force attacks
Prerequisites Knowledge
- Basic Linux command-line skills
- Understanding of file permissions and ownership
- Network concepts (ports, firewalls, NAT)
- SSL/TLS certificate basics
- User account management
Step-by-Step Setup
Step 1: Install vsftpd
Update system packages:
# Ubuntu/Debian
sudo apt update && sudo apt upgrade -y
# CentOS/Rocky Linux
sudo dnf update -y
Install vsftpd:
# Ubuntu/Debian
sudo apt install vsftpd -y
# CentOS/Rocky Linux
sudo dnf install vsftpd -y
Verify installation:
vsftpd -v
Step 2: Backup Default Configuration
Create backup of original configuration:
sudo cp /etc/vsftpd.conf /etc/vsftpd.conf.original
Step 3: Basic vsftpd Configuration
Create new configuration:
sudo nano /etc/vsftpd.conf
Add the following basic configuration:
# Listen on IPv4
listen=YES
listen_ipv6=NO
# Disable anonymous FTP
anonymous_enable=NO
# Enable local users
local_enable=YES
# Enable write access
write_enable=YES
# Set local umask
local_umask=022
# Chroot users to home directories
chroot_local_user=YES
allow_writeable_chroot=YES
# Directory messages
dirmessage_enable=YES
# Logging
xferlog_enable=YES
xferlog_file=/var/log/vsftpd.log
log_ftp_protocol=YES
# Connection settings
ftpd_banner=Welcome to FTP Server
max_clients=50
max_per_ip=5
# Passive mode configuration
pasv_enable=YES
pasv_min_port=50000
pasv_max_port=50100
pasv_address=YOUR_SERVER_PUBLIC_IP
# Security settings
ssl_enable=NO # We'll enable this later with SSL
userlist_enable=YES
userlist_file=/etc/vsftpd.user_list
userlist_deny=NO
# Performance
use_localtime=YES
Important: Replace YOUR_SERVER_PUBLIC_IP with your actual server's public IP address.
Save and exit.
Step 4: Create FTP User
Create dedicated FTP user with home directory:
sudo useradd -m -d /home/ftpuser -s /bin/bash ftpuser
sudo passwd ftpuser
Create FTP directory structure:
sudo mkdir -p /home/ftpuser/ftp/upload
sudo chown nobody:nogroup /home/ftpuser/ftp
sudo chmod a-w /home/ftpuser/ftp
sudo chown ftpuser:ftpuser /home/ftpuser/ftp/upload
This structure:
/home/ftpuser/ftp- Read-only root directory (security measure)/home/ftpuser/ftp/upload- Writable upload directory
Add user to allowed list:
echo "ftpuser" | sudo tee -a /etc/vsftpd.user_list
Step 5: Configure Firewall
Allow FTP ports:
# UFW (Ubuntu/Debian)
sudo ufw allow 20:21/tcp
sudo ufw allow 50000:50100/tcp
sudo ufw allow 22/tcp # For SFTP
# Firewalld (CentOS/Rocky)
sudo firewall-cmd --permanent --add-port=20-21/tcp
sudo firewall-cmd --permanent --add-port=50000-50100/tcp
sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --reload
Step 6: Start and Enable vsftpd
Enable vsftpd to start on boot:
sudo systemctl enable vsftpd
Start vsftpd:
sudo systemctl start vsftpd
Check status:
sudo systemctl status vsftpd
Step 7: Test FTP Connection
From another machine or using FTP client:
ftp SERVER_IP
Enter username (ftpuser) and password.
Test commands:
ftp> ls
ftp> cd upload
ftp> put testfile.txt
ftp> get testfile.txt
ftp> bye
Step 8: Configure SFTP (SSH File Transfer)
SFTP typically works out of the box with OpenSSH. Configure chroot for SFTP users:
Create SFTP-only group:
sudo groupadd sftpusers
Create SFTP user:
sudo useradd -m -d /home/sftpuser -s /sbin/nologin -G sftpusers sftpuser
sudo passwd sftpuser
Configure SSH for SFTP chroot:
sudo nano /etc/ssh/sshd_config
Add at the end:
# SFTP Configuration
Match Group sftpusers
ChrootDirectory /home/%u
ForceCommand internal-sftp
AllowTcpForwarding no
X11Forwarding no
Restart SSH:
sudo systemctl restart sshd
Test SFTP connection:
sftp sftpuser@SERVER_IP
Configuration
SSL/TLS Encryption (FTPS)
Generate SSL certificate:
sudo mkdir -p /etc/ssl/private
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout /etc/ssl/private/vsftpd.key \
-out /etc/ssl/certs/vsftpd.crt
Follow prompts to enter certificate information.
Update vsftpd.conf:
# Enable SSL
ssl_enable=YES
# SSL certificate paths
rsa_cert_file=/etc/ssl/certs/vsftpd.crt
rsa_private_key_file=/etc/ssl/private/vsftpd.key
# SSL settings
allow_anon_ssl=NO
force_local_data_ssl=YES
force_local_logins_ssl=YES
ssl_tlsv1=YES
ssl_sslv2=NO
ssl_sslv3=NO
require_ssl_reuse=NO
ssl_ciphers=HIGH
Restart vsftpd:
sudo systemctl restart vsftpd
Test secure connection:
# Using lftp
lftp -u ftpuser SERVER_IP
Virtual Users with Database Authentication
Create virtual user database:
sudo apt install libpam-pwdfile apache2-utils -y
Create virtual users file:
sudo mkdir -p /etc/vsftpd
sudo htpasswd -c -d /etc/vsftpd/virtual_users virtualuser1
sudo htpasswd -d /etc/vsftpd/virtual_users virtualuser2
Create PAM configuration:
sudo nano /etc/pam.d/vsftpd_virtual
Add:
auth required pam_pwdfile.so pwdfile=/etc/vsftpd/virtual_users
account required pam_permit.so
Update vsftpd.conf:
# Virtual users configuration
guest_enable=YES
guest_username=vsftpd_virtual
pam_service_name=vsftpd_virtual
user_sub_token=$USER
local_root=/var/ftp/$USER
Create virtual user home directories:
sudo mkdir -p /var/ftp/virtualuser1
sudo mkdir -p /var/ftp/virtualuser2
sudo chown -R vsftpd_virtual:vsftpd_virtual /var/ftp
Create virtual user system account:
sudo useradd -d /var/ftp -s /sbin/nologin vsftpd_virtual
Per-User Configuration
Create user-specific configuration:
sudo mkdir -p /etc/vsftpd/user_conf
Update vsftpd.conf:
user_config_dir=/etc/vsftpd/user_conf
Create user-specific config file:
sudo nano /etc/vsftpd/user_conf/ftpuser
Add user-specific settings:
# Custom settings for ftpuser
local_root=/home/ftpuser/ftp
max_clients=10
download_enable=YES
write_enable=YES
local_umask=022
Bandwidth Limiting
Limit transfer rates per connection:
# Limit download to 500 KB/s
local_max_rate=512000
# For anonymous users (if enabled)
anon_max_rate=256000
IP-Based Access Control
Restrict access by IP address:
Enable TCP wrappers:
sudo nano /etc/hosts.allow
Add:
vsftpd: 192.168.1.0/24
vsftpd: 10.0.0.0/8
sudo nano /etc/hosts.deny
Add:
vsftpd: ALL
Or use vsftpd native configuration:
sudo nano /etc/vsftpd.conf
Add:
tcp_wrappers=YES
Logging and Auditing
Enhance logging:
# Detailed logging
xferlog_enable=YES
xferlog_std_format=NO
log_ftp_protocol=YES
syslog_enable=YES
# Custom log file
vsftpd_log_file=/var/log/vsftpd.log
# Log file transfers separately
xferlog_file=/var/log/vsftpd_xfer.log
dual_log_enable=YES
Monitor logs:
sudo tail -f /var/log/vsftpd.log
Anonymous FTP (Public Downloads)
Enable anonymous access for public file distribution:
# Enable anonymous FTP
anonymous_enable=YES
anon_root=/var/ftp/pub
# Anonymous permissions
anon_upload_enable=NO
anon_mkdir_write_enable=NO
anon_other_write_enable=NO
# Anonymous rate limit
anon_max_rate=256000
Create anonymous directory:
sudo mkdir -p /var/ftp/pub
sudo chown -R ftp:ftp /var/ftp/pub
sudo chmod 555 /var/ftp/pub
Optimization
Connection Limits
Control concurrent connections:
# Global connection limit
max_clients=100
# Per-IP connection limit
max_per_ip=3
# Connection timeout
idle_session_timeout=600
data_connection_timeout=120
Passive Mode Optimization
Optimize passive mode for NAT:
# Enable passive mode
pasv_enable=YES
# Passive port range (firewall-friendly)
pasv_min_port=50000
pasv_max_port=50100
# Public IP for passive mode (required behind NAT)
pasv_address=YOUR_PUBLIC_IP
# Passive mode security
pasv_addr_resolve=NO
Performance Tuning
Increase performance for high-traffic servers:
# Enable async I/O
async_abor_enable=YES
# Connection persistence
one_process_model=NO
# Increase file handles
max_clients=200
# Disable reverse DNS lookups
reverse_lookup_enable=NO
# Optimize data transfer
use_sendfile=YES
Kernel Tuning
Optimize Linux kernel for FTP server:
sudo nano /etc/sysctl.conf
Add:
# Increase connection backlog
net.core.somaxconn = 1024
# Increase network buffers
net.core.rmem_max = 134217728
net.core.wmem_max = 134217728
# Optimize TCP
net.ipv4.tcp_fin_timeout = 15
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_max_syn_backlog = 8192
# Increase file handles
fs.file-max = 65536
Apply:
sudo sysctl -p
Security Hardening
Implement fail2ban
Protect against brute-force attacks:
sudo apt install fail2ban -y
Create vsftpd jail:
sudo nano /etc/fail2ban/jail.local
Add:
[vsftpd]
enabled = true
port = ftp,ftp-data,ftps,ftps-data
logpath = /var/log/vsftpd.log
maxretry = 3
bantime = 3600
findtime = 600
Restart fail2ban:
sudo systemctl restart fail2ban
Disable Root Login
Prevent root access via FTP:
# In vsftpd.conf
userlist_enable=YES
userlist_file=/etc/vsftpd.user_list
userlist_deny=NO
Create user list without root:
echo "ftpuser" | sudo tee /etc/vsftpd.user_list
echo "sftpuser" | sudo tee -a /etc/vsftpd.user_list
Enforce Strong Passwords
Implement password complexity requirements:
sudo apt install libpam-pwquality -y
sudo nano /etc/pam.d/common-password
Add:
password requisite pam_pwquality.so retry=3 minlen=12 difok=3 ucredit=-1 lcredit=-1 dcredit=-1 ocredit=-1
Chroot Best Practices
Properly configure chroot to prevent escapes:
# Chroot all local users
chroot_local_user=YES
# Allow writable chroot (vsftpd 3.0+)
allow_writeable_chroot=YES
# Alternative: Use chroot list
# chroot_list_enable=YES
# chroot_list_file=/etc/vsftpd.chroot_list
Hide System Information
Minimize information disclosure:
# Custom banner
ftpd_banner=FTP Server Ready
# Hide file ownership
hide_ids=YES
# Disable STAT command
seccomp_sandbox=NO
Troubleshooting
Cannot Connect to FTP Server
Verify service is running:
sudo systemctl status vsftpd
Check listening ports:
sudo netstat -tlnp | grep vsftpd
Should show port 21 listening.
Test locally:
ftp localhost
If works locally but not remotely, check firewall.
Verify firewall rules:
# UFW
sudo ufw status
# Firewalld
sudo firewall-cmd --list-all
500 OOPS: vsftpd: refusing to run with writable root
This error occurs with chroot when home directory is writable.
Solution 1: Enable allow_writeable_chroot:
allow_writeable_chroot=YES
Solution 2: Make chroot directory read-only:
sudo chmod a-w /home/ftpuser/ftp
Passive Mode Not Working
Check passive port range in firewall:
sudo ufw allow 50000:50100/tcp
Verify pasv_address is set correctly:
pasv_address=YOUR_PUBLIC_IP
Get public IP:
curl ifconfig.me
Test passive mode:
Use FTP client in passive mode:
ftp> passive
Passive mode on.
ftp> ls
530 Login Incorrect
Verify user exists in allowed list:
cat /etc/vsftpd.user_list
Check userlist settings:
userlist_enable=YES
userlist_deny=NO # Must be NO for allow-list mode
Test password:
su - ftpuser
If fails, reset password:
sudo passwd ftpuser
SSL/TLS Connection Issues
Verify certificate paths:
ls -la /etc/ssl/certs/vsftpd.crt
ls -la /etc/ssl/private/vsftpd.key
Check SSL settings:
ssl_enable=YES
force_local_data_ssl=YES
force_local_logins_ssl=YES
Test with FTP client supporting SSL:
Use FileZilla or lftp with explicit SSL/TLS.
Check logs for SSL errors:
sudo tail -f /var/log/vsftpd.log | grep -i ssl
SFTP Chroot Not Working
Verify directory ownership:
Chroot directory must be owned by root:
sudo chown root:root /home/sftpuser
sudo chmod 755 /home/sftpuser
Create writable subdirectory:
sudo mkdir /home/sftpuser/upload
sudo chown sftpuser:sftpuser /home/sftpuser/upload
Check SSH configuration:
sudo sshd -t
Verify no syntax errors.
Review SSH logs:
sudo tail -f /var/log/auth.log
Monitoring and Maintenance
Monitor Active Connections
View current FTP sessions:
sudo ps aux | grep vsftpd
Detailed connection information:
sudo netstat -anp | grep :21
Log Analysis
Parse transfer logs:
sudo grep "UPLOAD\|DOWNLOAD" /var/log/vsftpd_xfer.log
Count failed login attempts:
sudo grep "FAIL LOGIN" /var/log/vsftpd.log | wc -l
Most active users:
sudo awk '{print $8}' /var/log/vsftpd_xfer.log | sort | uniq -c | sort -rn | head -10
Disk Usage Monitoring
Monitor user disk usage:
sudo du -sh /home/ftpuser/ftp/*
Implement quotas:
sudo setquota -u ftpuser 10000000 12000000 0 0 /
Automated Backups
Backup FTP user directories:
sudo mkdir -p /backup/ftp
sudo rsync -av /home/ftpuser/ftp/ /backup/ftp/ftpuser/
Automate with cron:
sudo crontab -e
Add:
0 2 * * * /usr/bin/rsync -av /home/ftpuser/ftp/ /backup/ftp/ftpuser/
Conclusion
You now have a production-ready FTP/SFTP server providing secure, reliable file transfer capabilities with vsftpd and OpenSSH. This solution offers the flexibility needed for modern file transfer requirements while maintaining backward compatibility with legacy FTP clients.
Key achievements from this guide:
- Secure file transfer with FTPS and SFTP encryption
- Robust user management supporting local, virtual, and chrooted users
- Comprehensive security through SSL/TLS, fail2ban, and access controls
- Performance optimization for high-traffic environments
- Flexible configuration supporting various deployment scenarios
- Monitoring and logging for security analysis and compliance
Regular maintenance includes monitoring failed login attempts, reviewing transfer logs, updating SSL certificates, managing disk quotas, and keeping vsftpd packages updated for security patches. Implement automated backups of user data and configuration files to ensure quick recovery from failures.
Whether supporting web development workflows, providing client file exchange, enabling legacy system integration, or building secure file transfer infrastructure, vsftpd and SFTP provide the foundation for professional file server deployment.
Transfer securely!


