How to set up Vsftpd for a User's Directory in Ubuntu

To set up Vsftpd For A User' s Directory in Ubuntu

File Transfer Protocol is a network protocol for transferring files between clients and server. To move files more securely we can use Vsftpd. In this article we will learn how to set up Vsftpd for a User' s Directory in Ubuntu.

To install Vsftpd

Run the following command to update your system.

root@linuxhelp1:~# apt-get update 
Hit:1 http://in.archive.ubuntu.com/ubuntu xenial InRelease
Hit:2 http://security.ubuntu.com/ubuntu xenial-security InRelease                             
Hit:3 http://in.archive.ubuntu.com/ubuntu xenial-updates InRelease       
Ign:4 http://download.opensuse.org/repositories/home:/Horst3180/xUbuntu_16.04  InRelease
Hit:5 http://in.archive.ubuntu.com/ubuntu xenial-backports InRelease     
Hit:6 http://download.opensuse.org/repositories/home:/Horst3180/xUbuntu_16.04  Release
Get:7 http://download.opensuse.org/repositories/home:/Horst3180/xUbuntu_16.04  Release.gpg [481 B]
Fetched 481 B in 1s (378 B/s)       
Reading package lists... Done


After updating, install the vsftpd package from the below command.

root@linuxhelp1:~# apt-get install vsftpd -y 
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following NEW packages will be installed:
  vsftpd
0 upgraded, 1 newly installed, 0 to remove and 85 not upgraded.
Need to get 115 kB of archives.
After this operation, 336 kB of additional disk space will be used.
Get:1 http://in.archive.ubuntu.com/ubuntu xenial/main amd64 vsftpd amd64 3.0.3-3ubuntu2 [115 kB]
Fetched 115 kB in 5s (19.4 kB/s)        
Preconfiguring packages ...
Selecting previously unselected package vsftpd.
(Reading database ... 208381 files and directories currently installed.)
Preparing to unpack .../vsftpd_3.0.3-3ubuntu2_amd64.deb ...
Unpacking vsftpd (3.0.3-3ubuntu2) ...
Processing triggers for systemd (229-4ubuntu7) ...
Processing triggers for ureadahead (0.100.0-19) ...
Processing triggers for man-db (2.7.5-1) ...
Setting up vsftpd (3.0.3-3ubuntu2) ...
Processing triggers for systemd (229-4ubuntu7) ...
Processing triggers for ureadahead (0.100.0-19) ...


Enable and check the status of the firewall by running the following command.

root@linuxhelp1:~# ufw enable 

Firewall is active and enabled on system startup

root@linuxhelp1:~# ufw status 
Status: active


Then open the following port in the firewall and check the status of the port.

root@linuxhelp1:~# ufw allow 20/tcp 
Rule added
Rule added (v6)
root@linuxhelp1:~# ufw allow 21/tcp 
Rule added
Rule added (v6)
root@linuxhelp1:~# ufw allow 990/tcp 
Rule added
Rule added (v6)
root@linuxhelp1:~# ufw allow 40000:50000/tcp 
Rule added
Rule added (v6)
root@linuxhelp1:~# ufw status 
Status: active

To                         Action      From
--                         ------      ----
20/tcp                     ALLOW       Anywhere                  
21/tcp                     ALLOW       Anywhere                  
990/tcp                    ALLOW       Anywhere                  
40000:50000/tcp            ALLOW       Anywhere                  
20/tcp (v6)                ALLOW       Anywhere (v6)             
21/tcp (v6)                ALLOW       Anywhere (v6)             
990/tcp (v6)               ALLOW       Anywhere (v6)             
40000:50000/tcp (v6)       ALLOW       Anywhere (v6)

To add new user

Create one new user and add a directory by using the following command.

root@linuxhelp1:~# adduser linuxhelp 
Adding user `linuxhelp'  ...
Adding new group `linuxhelp'  (1001) ...
Adding new user `linuxhelp'  (1001) with group `linuxhelp'  ...
Creating home directory `/home/linuxhelp'  ...
Copying files from `/etc/skel'  ...
Enter new UNIX password: 
Retype new UNIX password: 
passwd: password updated successfully
Changing the user information for linuxhelp
Enter the new value, or press ENTER for the default
    Full Name []: 
    Room Number []: 
    Work Phone []: 
    Home Phone []: 
    Other []: 
Is the information correct? [Y/n] y


Set the ownership for the added folder and restrict write permission for the directory by running the below command.

root@linuxhelp1:~# mkdir /home/linuxhelp/ftp
root@linuxhelp1:~# chown nobody:nogroup /home/linuxhelp/ftp
root@linuxhelp1:~# chmod a-w /home/linuxhelp/ftp 


After setting the permission, you can verify it.

root@linuxhelp1:~# ls -la /home/linuxhelp/ftp 
total 8
dr-xr-xr-x 2 nobody    nogroup   4096 Sep 20 15:44 .
drwxr-xr-x 3 linuxhelp linuxhelp 4096 Sep 20 15:44 ..


Now create a directory inside the FTP to uploaded files and assign ownership to the user.

root@linuxhelp1:~# mkdir /home/linuxhelp/ftp/files
root@linuxhelp1:~# chown linuxhelp:linuxhelp /home/linuxhelp/ftp/files/ 


List and check the permission of the files and directory.

root@linuxhelp1:~# ls -la /home/linuxhelp/ftp 
total 12
dr-xr-xr-x 3 nobody    nogroup   4096 Sep 20 15:50 .
drwxr-xr-x 3 linuxhelp linuxhelp 4096 Sep 20 15:44 ..
drwxr-xr-x 2 linuxhelp linuxhelp 4096 Sep 20 15:50 files

Then add text file inside the linuxhelp/ftp/files directory

root@linuxhelp1:~# echo " vsftpd test file"  | sudo tee /home/linuxhelp/ftp/files/test.txt 
vsftpd test file


Open the Vsftpd.conf file and start configure FTP access as shown below.

root@linuxhelp1:~# vim /etc/vsftpd.conf 
#
# Allow anonymous FTP? (Disabled by default).
anonymous_enable=NO
#
# Uncomment this to allow local users to log in.
local_enable=YES
#


Remove the write access by uncommenting the following line.

write_enable=YES


Also uncomment the chroot to prevent the user from accessing the files outside the directory.

# You may restrict local users to their home directories.  See the FAQ for
# the possible risks in this before using chroot_local_user or
# chroot_list_enable below.
chroot_local_user=YES


Then add a name to the user_sub_token to set permission for the user.

user_sub_token=$linuxhelp
local_root=/home/$linuxhelp/ftp


Limit the range of ports as shown below to pick up enough connections that are available.

pasv_min_port=40000
pasv_max_port=50000


If you want to permit only FTP access, then do the following.

userlist_enable=YES
userlist_file=/etc/vsftpd.userlist
userlist_deny=NO


Give NO for userlist deny option to allow the user for FTP access.

Once its done, save and exit the file.


Now lets add the user to the Vsftpd user list by running the following command.

root@linuxhelp1:~# echo " linuxhelp"  | sudo tee -a /etc/vsftpd.userlist 
linuxhelp

root@linuxhelp1:~# cat /etc/vsftpd.userlist 
linuxhelp


Restart the vsftpd service, by running the following command.

root@linuxhelp1:~# systemctl restart vsftpd 

To test the FTP access

As we have configured access permission for linuxhelp, all the IP' s other than Linuxhelp should be denied. Lets call from an anonymous IP to connect via FTP.

root@linuxhelp1:~# ftp -p 192.168.5.151 
Connected to 192.168.5.151.
220 (vsFTPd 3.0.3)
Name (192.168.5.151:root): anonymous
530 Permission denied.
Login failed.


It denied, now lets try the same scenario through sudo user.

root@linuxhelp1:~# ftp -p 192.168.5.151 
Connected to 192.168.5.151.
220 (vsFTPd 3.0.3)
Name (192.168.5.151:root): sudo_linuxhelp
530 Permission denied.
Login failed.


Sudo user is denied too. Now lets try to access FTP for linuxhelp user.

root@linuxhelp1:~# ftp -p 192.168.5.151 
Connected to 192.168.5.151.
220 (vsFTPd 3.0.3)
Name (192.168.5.151:root): linuxhelp
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> 


We have sucessfully verified our configuration.

To transfer a Test file

Run the following command to change files directory and use get command to transfer the test file.

ftp>  cd files
250 Directory successfully changed.
ftp>  get test.txt
local: test.txt remote: test.txt
227 Entering Passive Mode (192,168,5,151,170,239).
150 Opening BINARY mode data connection for test.txt (17 bytes).
226 Transfer complete.
17 bytes received in 0.01 secs (1.6517 kB/s)


Now lets try to upload the file with a new name to test write permissions.

ftp>  put test.txt upload.txt
local: test.txt remote: upload.txt
227 Entering Passive Mode (192,168,5,151,194,42).
150 Ok to send data.
226 Transfer complete.
17 bytes sent in 0.00 secs (404.9162 kB/s)

To transfer files securely

FTP does not encrypt any data while transferring, so in order to include user credentials, create SSL certificates for vsftpd by using openssl command.

root@linuxhelp1:~# sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/ssl/private/vsftpd.pem -out /etc/ssl/private/vsftpd.pem 
Generating a 2048 bit RSA private key
......................+++
.........+++
writing new private key to ' /etc/ssl/private/vsftpd.pem' 
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter ' .' , the field will be left blank.
-----
Country Name (2 letter code) [AU]:IN
State or Province Name (full name) [Some-State]:TN
Locality Name (eg, city) []:Tamil Nadu
Organization Name (eg, company) [Internet Widgits Pty Ltd]:linuxhelp
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:
Email Address []:


Explanations
openssl - is used to create a new certificate
-days flag - for certificate validity

Add a private 2048-bit RSA key.
-keyout and -out flags - to the same value so that the private key and the certificate will be located in the same file.

Then use the below command to open the vsftpd configuration file and add the security certificate below the old one.

root@linuxhelp1:~# vim /etc/vsftpd.conf 
#rsa_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
#rsa_private_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
rsa_cert_file=/etc/ssl/private/vsftpd.pem
rsa_private_key_file=/etc/ssl/private/vsftpd.pem
Enable the ssl_enable as yes

ssl_enable=YES


Add the following lines to explicitly deny anonymous connections over SSL and also to allow SSL for both data transfer and logins.

allow_anon_ssl=NO
force_local_data_ssl=YES
force_local_logins_ssl=YES


Then configure the server to use TLS by appending the below lines to it.

ssl_tlsv1=YES
ssl_sslv2=NO
ssl_sslv3=NO


Add the below lines for high encryption cipher suites. Its key length is equal to or greater than 128 bits.

require_ssl_reuse=NO
ssl_ciphers=HIGH

Save and exit the file.


Then restart the server to make the changes apply.

root@linuxhelp1:~# systemctl restart vsftpd 


Now lets test our configuration by connecting through an anonymous IP.

root@linuxhelp1:~# ftp -p 192.168.5.151 
Connected to 192.168.5.151.
220 (vsFTPd 3.0.3)
Name (192.168.5.151:root): linuxhelp
530 Non-anonymous sessions must use encryption.
Login failed.
421 Service not available, remote server has closed connection

To test TLS with FILEZILLA

Lets verify whether we can connect using a client that supports TLS through Filezilla.

Hit " Ctrl+s" and click on New site.

Fill all the necessary details and click on connect.

Enter the password in the prompt window and click OK.

Read the certificate details and click OK.

Now we have successfully connected to the FTP server.

To disable the shell access

To increase the security, disable the FTP user and create a custom shell. This in turn will limit the access of a compromised account to files accessible by FTP.
First, create a file called ftponly in the bin directory and paste the below code into it.

root@linuxhelp1:~# vim /bin/ftponly 
#!/bin/sh
echo " This account is limited to FTP access only." 


Change the permissions to make the file executable.

root@linuxhelp1:~# chmod a+x /bin/ftponly 


Open the list of valid shells.

root@linuxhelp1:~# vim /etc/shells 


Add the following lines to the bottom of the file.

# /etc/shells: valid login shells
/bin/sh
/bin/dash
/bin/bash
/bin/rbash
/bin/ftponly


Update the user' s shell with the following command.

root@linuxhelp1:~# usermod linuxhelp -s /bin/ftponly 


Now try logging in as linuxhelp user and see the restricted message, since it is made limited.

root@linuxhelp1:~# ssh linuxhelp@192.168.5.151 
linuxhelp@192.168.5.151' s password:
Welcome to Ubuntu 16.04.1 LTS (GNU/Linux 4.4.0-38-generic x86_64)

* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage

71 packages can be updated.
0 updates are security updates.

Last login: Tue Sep 20 17:48:37 2016 from 192.168.5.151
This account is limited to FTP access only.
Connection to 192.168.5.151 closed.
FAQ
Q
Does vsftpd support IP-based access control?
A
Yes. vsftpd can integrate with tcp_wrappers (if built with this support).
It is enabled with the setting "tcp_wrappers=YES"
Q
Does vsftpd support hiding or denying certain files?
A
Yes. Look at the hide_file and deny_file options in the manual page.
Q
Can I restrict users to their home directories?
A
Yes. You are probably after the setting:
chroot_local_user=YES
Q
Why don't symlinks work with chroot_local_user=YES?
A
This is a consequence of how chroot() security works. As alternatives,
look into hard links, or if you have a modern Linux, see the powerful
"mount --bind".
Q
I'm using Solaris / Veritas and vsftpd is hanging?
A
Suspected bug with the Solaris / Veritas combination. With vsftpd-1.2.3
there is a possible workaround: no_log_lock=YES in your vsftpd.conf.5.