Skip to content

Instantly share code, notes, and snippets.

@theycallmeS
Last active August 29, 2015 14:13
Show Gist options
  • Save theycallmeS/21a0433f473e1e38767b to your computer and use it in GitHub Desktop.
Save theycallmeS/21a0433f473e1e38767b to your computer and use it in GitHub Desktop.
Debian 7 vsftpd configuration for webserver directories

How to configure directory accessible by both FTP user and a webserver running under Debian?

In order to do this, we will need three things:

  1. Configure vsftpd to work with separate user configurations
  2. Set correct permissions for directories accessible via FTP
  3. Turn off SSH access for FTP users

You can also jump to working production configuration attached below.

Abstract

Suppose we have a webserver running under application user, and one of its directories should be accessible via FTP for external users to upload/change some of the files. That means maintaining proper permissions, chrooting users to directories other than their home, and dealing with some of the vsftpd nuances.

vsftpd configuration

First, we will need to allow external vsftpd configurations, so we can configure every user separately. Add the following lines to the /etc/vsftpd.conf:

# Turn off anonymous access
anonymous_enable=NO

# Enable separate list of allowed users
userlist_enable=YES

# Switch userlist to whitelisting mode (so every listed user is allowed)
userlist_deny=NO

# Set location of userlist file
userlist_file=/etc/vsftpd/ftpusers

# Specify directory for separate user configs
user_config_dir=/etc/vsftpd/userconf/

Next, we will enable chroot jails, so users cannot access anything outside specified path:

# 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

At last, we will add user configurations, and set allowed list. /etc/vsftpd/ftpusers contains line by line usernames of allowed guys:

ftpuser1
ftpuser2

Directory /etc/vsftpd/userconf/ contains separate config files for each user:

application@localhost:~$ ls -l /etc/vsftpd/userconf/
-rw-r--r-- 1 root root 105 Jan 13 18:46 ftpuser1
-rw-r--r-- 1 root root 105 Jan 13 18:47 ftpuser2

Each file contains user-specific settings, such as path to the accessible directory:

# Put this file in /etc/vsftpd/userconf/
local_root=/application/path/to/some/dir/

Configuring persmissions and groups

We have to reach several permission-related goals:

  • files written by application to FTP dir writable and readable by our FTP users
  • files under written by users to FTP dir writable and readable by application user
  • other files in the filesystem should be read-only on inaccessible by FTP users

All uploaded files will be owned by specific FTP user who uploaded them, having 0775 (rwxrwxrw-) permissions. For group ownership we will create separate usergroup, which will be assigned to application as a way to access uploaded files.

Every FTP user will belong to that group, too. Let's create our first user and make assignments:

$ adduser ftpuser1
$ groupadd ftpusers
$ usermod -G ftpusers ftpuser1

Now we will application user to the group too:

$ usermod -a -G ftpusers application

Let's now set proper directory ownership and permissions, so it will be accessible both to application and our FTP users:

$ chown -R application:ftpusers /application/path/to/some/dir/
$ chmod -R 0775 /application/path/to/some/dir/

We will also need to make sure files created under that directory all preserve their group ownership. To do this, set the setgid flag on parent directory - its group assignment will 'stick' to childs then. Check dat s:

$ chmod -R g+s /application/path/to/some/dir/
$ cd /application/path/to/some/ && ls -l
drwxrwsr-x 2 application ftpusers 4096 Jan 13 19:06 dir

vsftpd uses another security trick - it uses umask to reset default permissions on all uploaded files. Default umask is 077, and target permission will be a result of removing all permission bits in places marked by 1s in umask. For example, file permission 775 and umask 057 equate to the following result:

775 (rwxrwxr-x) = 111 111 101
057             = 000 101 111
---
result          = 111 010 000 (750, or rwxr-x---)  

Default umask 077 will clear group and other permissions completely, so let's set more mild restrictions in /etc/vsftpd.conf:

# Set umask for uploaded file permissions
local_umask=002

We can also set general permissions for files uploaded via FTP, to make sure owners and group owners have equal rights:

# Set default permissions for uploaded files
file_open_mode=0775

This will remove write ability for other users, and preserve full permissions for owner and group.

Dealing with writable root problem

Using settings above, users will be chrooted inside specified directory. However, as of vsftpd version 3 and above, you are now required to make that directory non-writable by user who accesses it. That was designed with /home chroots in mind, but in our case we clearly don't want that behavior. Two best options to avoid this (and you can find more all around the internet):

  1. For systems with fresh vsftpd in repositories, we can simply set the following option in /etc/vsftpd.conf:
allow_writeable_chroot=YES
  1. For Debian Wheezy, which uses vsftpd version 2 with backported writable_root check, we will have to chroot our user to directory above target, so path:
    local_root=/application/path/to/some/dir/
    becomes:
    local_root=/application/path/to/some/

This is obviously a very limited solution, and alternatives (such as backporting option from p.1 to Wheeezy) can be found using links above. However, it works for some of the cases, and proved itself to be the easiest solution. You can further restrict everything that user sees inside /application/path/to/some/ directory using ownership and group permissions.

Additional SSH configuration

Make sure FTP users do not have access via SSH. The best way to do it (ensuring future changes among users wont accidentally allow unwanted access) is to whitelist several, and disable the rest. Set the following parameter in the /etc/ssh/sshd_config:

AllowUsers application
# Example configuration file for /etc/vsftpd.conf
# Read more at https://gist.github.com/theycallmeS/21a0433f473e1e38767b/
#
# The default compiled in settings are fairly paranoid. This sample file
# loosens things up a bit, to make the ftp daemon more usable.
# Please see vsftpd.conf.5 for all compiled in defaults.
#
# READ THIS: This example file is NOT an exhaustive list of vsftpd options.
# Please read the vsftpd.conf.5 manual page to get a full idea of vsftpd's
# capabilities.
#
#
# Run standalone? vsftpd can run either from an inetd or as a standalone
# daemon started from an initscript.
listen=YES
#
# Run standalone with IPv6?
# Like the listen parameter, except vsftpd will listen on an IPv6 socket
# instead of an IPv4 one. This parameter and the listen parameter are mutually
# exclusive.
#listen_ipv6=YES
#
# Allow anonymous FTP? (Beware - allowed by default if you comment this out).
anonymous_enable=NO
#
# Uncomment this to allow local users to log in.
local_enable=YES
#
# Uncomment this to enable any form of FTP write command.
write_enable=YES
#
# Default umask for local users is 077. You may wish to change this to 022,
# if your users expect that (022 is used by most other ftpd's)
local_umask=002
#
# Activate directory messages - messages given to remote users when they
# go into a certain directory.
dirmessage_enable=YES
#
# If enabled, vsftpd will display directory listings with the time
# in your local time zone. The default is to display GMT. The
# times returned by the MDTM FTP command are also affected by this
# option.
use_localtime=YES
#
# Activate logging of uploads/downloads.
xferlog_enable=YES
#
# Make sure PORT transfer connections originate from port 20 (ftp-data).
connect_from_port_20=YES
#
# You may override where the log file goes if you like. The default is shown
# below.
#xferlog_file=/var/log/vsftpd.log
log_ftp_protocol=YES
#
# 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
#
# Customization
#
# Some of vsftpd's settings don't fit the filesystem layout by
# default.
#
# This option should be the name of a directory which is empty. Also, the
# directory should not be writable by the ftp user. This directory is used
# as a secure chroot() jail at times vsftpd does not require filesystem
# access.
secure_chroot_dir=/var/run/vsftpd/empty
#
# This string is the name of the PAM service vsftpd will use.
pam_service_name=vsftpd
#
# This option specifies the location of the RSA certificate to use for SSL
# encrypted connections.
rsa_cert_file=/etc/ssl/private/vsftpd.pem
#
# User we allow access to FTP
userlist_enable=YES
userlist_deny=NO
userlist_file=/etc/vsftpd/ftpusers
# Specify directory for user configs
user_config_dir=/etc/vsftpd/userconf/
application@localhost:~$
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment