Updated: 12 October 2026 · Applies to: vsftpd 3.0.5 on Ubuntu 26.04 LTS and 24.04 LTS (both tested)
To run an FTP server on Ubuntu, install vsftpd with sudo apt install vsftpd, turn on TLS, lock each FTP user into their own folder and open port 21 plus a passive port range in the firewall. The steps below give a setup where users log in with FTPS (explicit FTP over TLS) and see only their own folder. Ubuntu 18.04 is end of life; this guide is tested on Ubuntu 26.04 and 24.04, which both ship vsftpd 3.0.5.
Only moving files yourself? SFTP works over the SSH server you already have and needs no FTP server: see how to use SFTP. Use FTP when a person, a device or a program needs FTP itself.
1. Install vsftpd
sudo apt update sudo apt install vsftpd sudo cp /etc/vsftpd.conf /etc/vsftpd.conf.orig
Ubuntu’s default configuration lets system users log in, blocks anonymous logins and has TLS and uploads turned off. The next steps change that.
2. Create the FTP user and its folder
sudo adduser ftpuser sudo mkdir -p /home/ftpuser/ftp/files sudo chown nobody:nogroup /home/ftpuser/ftp sudo chmod a-w /home/ftpuser/ftp sudo chown ftpuser:ftpuser /home/ftpuser/ftp/files echo ftpuser | sudo tee -a /etc/vsftpd.userlist
The user is locked into /home/ftpuser/ftp, which must not be writable (vsftpd refuses a writable top folder, see the errors below), and uploads into files. Write the owner and group in full (ftpuser:ftpuser): on Ubuntu 26.04, whose chown comes from the new Rust coreutils, chown ftpuser: left the group as root in our test.
FTP-only user without SSH login: create the user with sudo useradd -m -s /usr/sbin/nologin ftpuser and set a password with sudo passwd ftpuser. Ubuntu’s PAM file for vsftpd only accepts shells listed in /etc/shells, so such a user gets 530 Login incorrect until you add the shell: echo /usr/sbin/nologin | sudo tee -a /etc/shells. That made the login work in our test. Other programs that check /etc/shells then also treat nologin as a valid shell.
3. Get a TLS certificate
- Let’s Encrypt (recommended): point a name such as
ftp.example.comto the server, then runsudo apt install certbotandsudo certbot certonly --standalone -d ftp.example.com. According to the Certbot documentation, the standalone mode needs port 80 free, and the files are saved in/etc/letsencrypt/live/ftp.example.com/asfullchain.pemandprivkey.pem. Add--deploy-hook "systemctl restart vsftpd"so vsftpd is restarted after each renewal. - Self-signed, for testing: Ubuntu already has one:
/etc/ssl/certs/ssl-cert-snakeoil.pemwith the key/etc/ssl/private/ssl-cert-snakeoil.key. FTP clients show a certificate warning for it.
4. Configure /etc/vsftpd.conf
Replace the file’s contents with this (the original is saved as vsftpd.conf.orig) and put your own certificate paths in the two rsa_ lines:
listen=NO listen_ipv6=YES anonymous_enable=NO local_enable=YES write_enable=YES local_umask=022 dirmessage_enable=YES use_localtime=YES xferlog_enable=YES connect_from_port_20=YES secure_chroot_dir=/var/run/vsftpd/empty pam_service_name=vsftpd chroot_local_user=YES user_sub_token=$USER local_root=/home/$USER/ftp userlist_enable=YES userlist_file=/etc/vsftpd.userlist userlist_deny=NO pasv_min_port=40000 pasv_max_port=40100 ssl_enable=YES rsa_cert_file=/etc/letsencrypt/live/ftp.example.com/fullchain.pem rsa_private_key_file=/etc/letsencrypt/live/ftp.example.com/privkey.pem force_local_logins_ssl=YES force_local_data_ssl=YES
listen_ipv6=YESwithlisten=NO(Ubuntu’s default) serves IPv4 and IPv6: our test server answered on both.write_enableallows uploads;local_umask=022makes uploaded files readable (644).chroot_local_user,user_sub_tokenandlocal_rootlock every user into/home/USERNAME/ftp.userlist_deny=NOmeans only the users in/etc/vsftpd.userlistmay log in.rootand other system accounts are blocked anyway by/etc/ftpusers.pasv_min_portandpasv_max_portfix the passive data ports so you can open them in the firewall. Behind NAT, also setpasv_address=to the public IP. Background: FTP active vs passive mode.- The last five lines require TLS for the password and for all file transfers. You need no TLS version options: with these settings our server accepted TLS 1.2 and TLS 1.3. Do not copy
ssl_tlsv1_2=YESfrom older guides; Ubuntu’s vsftpd does not know it and will not start:500 OOPS: unrecognised variable in config file: ssl_tlsv1_2.
Apply the changes:
sudo systemctl restart vsftpd sudo systemctl status vsftpd
If it does not start, see vsftpd will not start.
5. Open the firewall
sudo ufw allow 21/tcp sudo ufw allow 40000:40100/tcp
A port range needs /tcp; without it ufw answers ERROR: Must specify 'tcp' or 'udp' with multiple ports. Port 20 does not need opening: it is only the source port for outgoing active-mode connections. More on ufw: open ports with UFW.
6. Test the FTP server
On the server itself, list the user’s folder with curl (-k skips the certificate check, because the name 127.0.0.1 is not on the certificate):
curl -v --ssl-reqd -k ftp://ftpuser:PASSWORD@127.0.0.1/
The important lines from our lab server (shortened):
< 220 (vsFTPd 3.0.5) > AUTH SSL < 234 Proceed with negotiation. * SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 < 230 Login successful. < 200 PROT now Private. < 229 Entering Extended Passive Mode (|||40018|) < 226 Directory send OK.
The passive port (40018) is inside the range from step 4. Uploads into files worked (226 Transfer complete.); an upload into the top folder was refused with 553, as intended.
From your computer, use an FTP client such as FileZilla: host ftp.example.com, port 21, protocol FTP, encryption Require explicit FTP over TLS, and the user’s name and password. See configuring your website in FileZilla.
Common vsftpd errors on Ubuntu
530 Non-anonymous sessions must use encryption.: the client tried plain FTP. Choose explicit FTP over TLS.530 Permission denied.(straight after the user name): the user is not in/etc/vsftpd.userlist.530 Login incorrect.: wrong password, or the user’s shell is not in/etc/shells(step 2)./var/log/vsftpd.logshowsFAIL LOGINfor these attempts. See also 530 Login Authentication Failed.500 OOPS: vsftpd: refusing to run with writable root inside chroot(): the user can write to the top folder. Runsudo chmod a-w /home/ftpuser/ftp. With TLS required, clients often show only a TLS error instead (curl reportedwrong version numberorbad record typein our tests), because the message arrives unencrypted.553 Could not create file.: an upload into the read-only top folder. Upload intofiles.- Login works but the folder listing never arrives: the passive ports are blocked in a firewall.
Related guides: allow or deny users on vsftpd, key vsftpd settings explained, verbose logging for vsftpd and the same setup on AlmaLinux, Rocky Linux and RHEL.
Official documentation: vsftpd.conf options and Certbot user guide.
Ucartz services for this topic
- KVM VPS hosting: NVMe SSD and full root access, with Free Basic Managed Support.
- Unmanaged dedicated servers: full root access and free IPMI KVM, with Free Basic Managed Support.
- Linux server management: hardening, patching, monitoring and automation for Ubuntu, Debian, RHEL and AlmaLinux.
