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.com to the server, then run sudo apt install certbot and sudo 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/ as fullchain.pem and privkey.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.pem with 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=YES with listen=NO (Ubuntu’s default) serves IPv4 and IPv6: our test server answered on both.
  • write_enable allows uploads; local_umask=022 makes uploaded files readable (644).
  • chroot_local_user, user_sub_token and local_root lock every user into /home/USERNAME/ftp.
  • userlist_deny=NO means only the users in /etc/vsftpd.userlist may log in. root and other system accounts are blocked anyway by /etc/ftpusers.
  • pasv_min_port and pasv_max_port fix the passive data ports so you can open them in the firewall. Behind NAT, also set pasv_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=YES from 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.log shows FAIL LOGIN for 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. Run sudo chmod a-w /home/ftpuser/ftp. With TLS required, clients often show only a TLS error instead (curl reported wrong version number or bad record type in our tests), because the message arrives unencrypted.
  • 553 Could not create file.: an upload into the read-only top folder. Upload into files.
  • 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

Was this answer helpful? 0 Users Found This Useful (0 Votes)