How to setup virtual users for vsftpd with access to a specific sub directory?
With a bit of playing around I've managed to come up with a semi solution (not perfect but good enough)
using 2707974 answer and information I've gained else where I've been able to get what I need.
First you need vsftp and PAM installed
apt-get install vsftpd libpam-pwdfile
Edit /etc/vsftpd.conf
nano /etc/vsftpd.conf
then paste in the following
listen=YES
anonymous_enable=NO
local_enable=YES
write_enable=YES
local_umask=022
local_root=/var/www
chroot_local_user=YES
allow_writeable_chroot=YES
hide_ids=YES
#virutal user settings
user_config_dir=/etc/vsftpd_user_conf
guest_enable=YES
virtual_use_local_privs=YES
pam_service_name=vsftpd
nopriv_user=vsftpd
guest_username=vsftpd
Edit to your exact needs the most important bit for virtual users is everything after the virtual user settings comment
Creating User
You can either use a database or htpasswd
I found htpasswd
faster and easier to use.
make a directory to store your users
mkdir /etc/vsftpd
htpasswd -cd /etc/vsftpd/ftpd.passwd user1
adding additional users just omit the -c
htpasswd -d /etc/vsftpd/ftpd.passwd user2
I've only managed to get it to work using CRYPT which limits to 8 chars to use more than 8 chars use openssl to generate a compatible hash and pipe directly into htpasswd
htpasswd -c -p -b /etc/vsftpd/ftpd.passwd user1 $(openssl passwd -1 -noverify password)
Once your users are created you can now change your PAM config file
nano /etc/pam.d/vsftpd
and remove everything inside this file and replace with the following
auth required pam_pwdfile.so pwdfile /etc/vsftpd/ftpd.passwd
account required pam_permit.so
This will enable login for your virtual users defined in /etc/vsftpd/ftpd.passwd
and will disable local users
Next we need to add a user for these virtual users to use. These users will not have access to the shell and will be called vsftpd
useradd --home /home/vsftpd --gid nogroup -m --shell /bin/false vsftpd
the user must match guest_username=vsftpd
in the vsftpd conf file
Defining Directory Access
The important line here is the following
user_config_dir=/etc/vsftpd_user_conf
this means that when user1
logs in it will look for the following file
/etc/vsftpd_user_conf/user1
this file the same as the vsftpd.conf
so you can define a new local_root
going back to the question we want user1
to only have access to var/www/website_name1/sub_folder1
, so we need to create the vsftpd_user_conf
folder:
mkdir /etc/vsftpd_user_conf
Now create the user file:
nano /etc/vsftpd_user_conf/user1
and enter the following line
local_root=/var/www/website_name1/sub_folder1
Now restart vsftp
service vsftpd restart
you should now be able to login as user1 who will only be able to see
var/www/website_name1/sub_folder1
and any folder and file inside it.
That's it you can now add as many users as you want and limit their access to whatever folder you wish.
important to remember if you do not create a user conf file it will default to the var/www folder as root (in the example above)
If the subfolder is intended to be modifiable by the user, it might be necesary to change the owner of the shared subfolder:
chown vsftpd:nogroup /var/www/website_name1/sub_folder1
Try with this manual. Maybe will work for You.
How to do it
Install vsftpd and a PAM library
Edit /etc/vsftpd.conf
and /etc/pam.d/vsftpd
Create user accouts with custom directories (in /var/www/ for example)
Set directories with the correct chmod
and chown
Create a admin user with full access to the server
- Install
vsftpd
(Very Secure FTP Deamon) andlibpam-pwdfile
to create virtual users
I wanted to create FTP users but I didn’t want to add local unix users (no shell access, no home directory and so on). A PAM (Pluggable Authentication Modules) will help you create virtual users.
sudo apt-get install vsftpd libpam-pwdfile
- Edit
vsftpd.conf
First you need to back up the original file
sudo mv /etc/vsftpd.conf /etc/vsftpd.conf.bak
Then create a new one
sudo vim /etc/vsftpd.conf
Copy and paste the following lines. The file should ONLY contain these lines:
listen=YES
anonymous_enable=NO
local_enable=YES
write_enable=YES
local_umask=022
nopriv_user=vsftpd
virtual_use_local_privs=YES
guest_enable=YES
user_sub_token=$USER
local_root=/var/www/$USER
chroot_local_user=YES
hide_ids=YES
guest_username=vsftpd
- Register virtual users
To register a user you use htpasswd
, so I assume you have apache2
working on your
server. Create a vsftpd
folder then put configuration files in it.
sudo mkdir /etc/vsftpd
then
sudo htpasswd -cd /etc/vsftpd/ftpd.passwd user1
-c means that we’ll create the file if it’s not existing yet -d forces MD5, you need it on ubuntu 12.04, just use it always
The command will prompt for a password.
If you want to add new users afterwards:
sudo htpasswd -d /etc/vsftpd/ftpd.passwd user2
- Configure PAM in
/etc/pam.d/vsftpd
Again, you need to back up the orignal file
sudo mv /etc/pam.d/vsftpd /etc/pam.d/vsftpd.bak
and create a new one
sudo vim /etc/pam.d/vsftpd
Copy and paste these 2 lines (this should be the only content). I insist only these 2 lines, I wasted a lot of time keeping the originals and just added these.
auth required pam_pwdfile.so pwdfile /etc/vsftpd/ftpd.passwd
account required pam_permit.so
- Create a local user without shell access
sudo useradd --home /home/vsftpd --gid nogroup -m --shell /bin/false vsftpd
You can check that it’s been created with the id command: id vsftpd. We define the user with the /bin/false shell because of the check_shell parameter (even if you don’t use it). When the end user connects to the FTP server, they will be used for rights and ownership:
chmod
and chown
.
- Restart
vsftpd
The common way is using init.d like all deamon
sudo /etc/init.d/vsftpd restart
sudo service vsftpd restart
- Create directories
According to configuration all users will be placed into this folder: /var/www/user1.
You need to create them with particular rights: the root folder cannot be writable!
/ [root = /var/www/user1] => 555
www [ /var/www/user1/www ] => 755
docs [ /var/www/user1/docs ] => 755
Note: the user cannot create files or folders in the root directory.
In vsftpd.conf
we have chroot_local_user=YES
so the user can’t see anything outside of his folder. To him, the server looks like this:
So just run these commands:
mkdir /var/www/user1`
chmod -w /var/www/user1
mkdir www/user1/www
chmod -R 755 /var/www/user1/www
chown -R vsftpd:nogroup /var/www/user1
The /var/www/user1
folder HAS TO exist or connection will fail.
Right now you can try to connect with your FTP
- Create an Admin user to access the entire server
To create an admin user we need to register a new user with htpasswd
.
Before we do so, I’ll advise you to check into the /etc/ftpusers
file that define certain users that are not allowed to connect with ftp. I think it’s only for local users and not virtual users but just in case don’t choose a name contained in this file.
sudo htpasswd -d /etc/vsftpd/ftpd.passwd theadmin
Now we need to add a new line into /etc/vsftpd.conf
chroot_list_enable=YES
This means that your user will be placed into their folder (as a jail) EXCEPT users in the /etc/
vsftpd.chroot_list
Let’s create this file and add our user, the file is a simple line containing “theadmin”. Add one user per line. That means you DON’T need to create a /var/www/theadmin
folder, the user will login and start in /home/vsftpd
.
Restart the server and you’re done !
In addition to the answers by @Avenyet and @2707974, you can use a more secure way to create the virtual users password file (/etc/vsftpd/ftpd.passwd
). In stead of using the htaccess
command you can use the mkpasswd
command from the whois
package (on Ubuntu at least). mkpasswd
doesn't update the password file for you like htaccess
, it only generates a password hash. So you will need to create and update the password file yourself.
Fortunately the password file syntax is very simple, it just consists of the username and password hash separated by a colon, and one line for each user. Example:
user1:6Gshac7jdk01U
This is the password foo
, with the basic crypt hashing.
Linux crypt supports better hashing algorithms than the basic des crypt used by htaccess
and the md5 used by the openssl passwd
command. Use mkpasswd -m help
to see a list of which algorithms your crypt
supports. On today's systems the best ones are SHA-256 or SHA-512. Unlike default des crypt hashing (which htaccess
also uses) these make use of all the characters in the password, and unlike des and openssl passwd
they have a configurable number of rounds.
The more rounds, the longer it takes to calculate the hash, and the more difficult it becomes to reverse the hash if an attacker gains access to the password hashes. For a server that is not on the public internet I would say to pick the number of rounds as high as possible but without the hashing taking noticeable time, so less than 0.1 second. If the server is on the internet, that might become a denial of service vector, as someone could try lots of logins with random passwords and use up CPU resources. If that is a risk for your configuration you should use a lower value.
The default for the SHA variants is 5000, which is pretty low. I'm using 100000 on my installation (which is not publicly accessible).
To generate such a hash, enter mkpasswd -m sha-512 -R 100000
. This will ask you to enter the password and print out the hash. Use the hash in the passwd file instead of the simple crypt hashes like this:
user1:$6$rounds=100000$HRZdUPD8$GVBmHg91rjNm.WlcMCcLp41Ewz6XXJ1ktKzS8Zmr8cmyVGR28URVY1A9N3Nz4W9zl6lDGjwVbz94N/JQVSGOh/
The type of hash and the number of rounds is embedded in the hash value, so crypt
can see what method to use to check a password. It is even possible to mix different types of hashes in a single passwd file. These passwd files can be used at /etc/vsftpd/ftpd.passwd
for the highest level of security crypt
currently has to offer. For the rest of the configuration I refer to the other answers.
(I'm still waiting for crypt
to support a better password hashing algorithm like scrypt or one of the Argon2 variants.)