# Vsftpd Setup ## Contents - [Overview](#overview) - [Installation](#installation) - [Configuration Files](#configuration-files) - [Configuration Basics](#configuration-basics) - [TCP Wrappers](#tcp-wrappers) - [Login Banner](#login-banner) - [Directory Message](#directory-message) - [Logging](#logging) - [Local Users](#local-users) - [Chroot Security](#chroot-security) - [Access Control](#access-control) - [Anonymous FTP](#anonymous-ftp) - [Connection Restrictions](#connection-restrictions) - [SSL Connections](#ssl-connections) - [Active vs. Passive](#active-vs-passive) - [Virtual chroot Users](#virtual-chroot-users) - [vsftpd.conf](#vsftpdconf) - [PAM ftp](#pam-ftp) - [SELinux](#selinux) - [Adding a User](#adding-a-user) - [Reloading Users](#reloading-users) - [Updating a User](#updating-a-user) - [Removing a User](#removing-a-user) - [References](#references) ## Overview [vsftpd](https://security.appspot.com/vsftpd.html) is a GPL licensed FTP server for UNIX systems, including Linux. It is the default FTP server daemon as installed and taught by Red Hat, and as such enjoys the status of being the most popular FTP daemon in modern use with most Linux distributions. As a precursor, it's recommended to fully understand Active vs. Passive FTP mode: - This document will cover the basic installation and configuration of vsftpd; more options are available in the *vsftpd.conf* man page. ## Installation The vsftpd daemon is included in the core distribution repositories: ``` ## RHEL / CentOS yum -y install vsftpd service vsftpd start && chkconfig vsftpd on ## Debian / Ubuntu apt-get update && apt-get -y install vsftpd mkdir /etc/vsftpd /var/ftp ``` **NOTE**: on Ubuntu the _vsftpd_ service is controlled by Upstart; it's automatically started and enabled by default. On Debian the `insserv` command must be used to enable it. ## Configuration Files There's one key difference between the distributions: | **RHEL / CentOS** | **Debian / Ubuntu** | | ------------------------- | ------------------- | | `/etc/vsftpd/vsftpd.conf` | `/etc/vsftpd.conf` | | `/etc/vsftpd/ftpusers` | `/etc/ftpusers` | This also extends into the entire `/etc/vsftpd/` subdirectory and a default directory for anonymous users in `/var/ftp/` which are only present on a RHEL-style installations from the package install. The Ubuntu package comes with both a systemd and upstart service that are not present on Debian; creating an `/etc/vsftpd/` to work in on these distributions is preferred to allow for cross-distro compatibility in setup below. ## Configuration Basics All options refer to the `vsftpd.conf` configuration file and are detailed in the man page; other options exist than the ones listed herein. ### TCP Wrappers ``` # Disable TCP Wrappers tcp_wrappers=NO ``` ### Login Banner ``` # Set a direct banner (hide name, version, etc.) ftpd_banner=FTP server ready. # Overrides 'ftpd_banner' by specifying a filename banner_file=/etc/vsftpd/banner.txt ``` ### Directory Message ``` # Shown when changing into the directory message_file=.message dirmessage_enable=YES ``` ### Logging ``` # Log all uploads and downloads xferlog_enable=YES # Log all FTP commands log_ftp_protocol=YES xferlog_std_format=NO # Log transfers to both /var/log/xferlog and /var/log/vsftpd.log dual_log_enable=YES ``` ### Local Users ``` # Disable 'write' (upload) write_enable=NO # Disable local users local_enable=NO ``` ### Chroot Security By default users are **not** in a chroot upon login. ``` # Basic Local user login chroot to home directory chroot_local_user=YES chroot_list_enable=NO # Enable list of users ONLY to chroot chroot_local_user=NO chroot_list_enable=YES chroot_list_file=/etc/vsftpd/chroot_list # Enable list of users NOT to chroot chroot_local_user=YES chroot_list_enable=YES chroot_list_file=/etc/vsftpd/chroot_list ``` ### Access Control By default, User ACLs are enabled in `/etc/pam.d/vsftpd` using the `/etc/ftpusers` / `/etc/vsftpd/ftpusers` file: ``` auth required pam_listfile.so item=user sense=deny file=/etc/vsftpd/ftpusers onerr=succeed ``` To also allow manipulation by Group, a line can be added right below it using a (new) group file: ``` auth required pam_listfile.so item=group sense=deny file=/etc/vsftpd/ftpgroups onerr=succeed ``` Within `vsftpd.conf` are parameters determining how the ACLs are used: ``` # Should be configured already by upstream packagers pam_service_name=vsftpd # Enable list of users ONLY allowed to log in userlist_enable=YES userlist_deny=NO userlist_file=/etc/vsftpd/ftpusers # Enable list of users NEVER allowed to log in userlist_enable=YES userlist_deny=YES userlist_file=/etc/vsftpd/ftpusers ``` ### Anonymous FTP ``` # Enable anonymous FTP w/password (email address, usually) ftp_username=ftp anonymous_enable=YES anon_root=/var/ftp anon_max_rate=0 # bytes/second, 0 = unlimited anon_umask=077 # Enable only anon users who specify a certain email as password no_anon_password=NO secure_email_list_enable=YES email_password_file=/etc/vsftpd/email_passwords # Reverse the above, deny these emails when used as anon password deny_email_enable=YES banned_email_file=/etc/vsftpd/banned_emails # Allow anon users to upload/delete/etc. (requires write_enable=YES) anon_mkdir_write_enable=YES anon_other_write_enable=YES anon_upload_enable=YES anon_world_readable_only=YES chown_uploads=YES chown_username=ftp ``` ### Connection Restrictions ``` # Change limits and umask connect_timeout=60 # in seconds data_connection_timeout=300 idle_session_timeout=300 max_clients=2000 max_per_ip=10 max_login_fails=3 delay_failed_login=1 # in seconds local_max_rate=0 # bytes/second, 0 = unlimited local_umask=077 ``` It's preferred to use `iptables` to perform restrictions at the IP level; however, if required TCP Wrappers can be used: ``` # Enable TCP Wrappers tcp_wrappers=YES # Deny a subnet echo 'vsftpd:192.168.1.0/255.255.255.0:twist /bin/cat /etc/vsftpd/denied_message' >> /etc/hosts.deny ``` Using `iptables` is preferred. ### SSL Connections ``` # General SSL Options ssl_enable=YES ssl_request_cert=YES validate_cert=NO # breaks self-signed certs ca_certs_file=/path/to/ca-bundle.crt rsa_cert_file=/path/to/server.crt # can be a PEM rsa_private_key_file=/path/to/server.key # can be a PEM ssl_ciphers=HIGH:!ADH ssl_sslv2=NO ssl_sslv3=NO ssl_tlsv1=YES debug_ssl=NO # Always expect a SSL handshake (not normal - use TLS instead) implicit_ssl=NO # Force various SSL options require_cert=NO # client SSL cert, not server force_local_data_ssl=NO force_local_logins_ssl=NO require_ssl_reuse=YES strict_ssl_read_eof=NO strict_ssl_write_shutdown=NO # SSL options for Anonymous FTP allow_anon_ssl=YES force_anon_ssl=NO force_anon_data_ssl=NO force_anon_logins_ssl=NO force_local_data_ssl=NO ``` ## Active vs. Passive Configuration options exist to facilitate setting of Active ("PORT") and Passive ("PASV") FTP to work around various firewall restrictions. One of the most common techniques is to use the kernel netfilter modules `nf_nat_ftp` and `nf_conntrack_ftp` (aliased internally to `ip_nat_ftp` and `ip_conntrack_ftp` for compatibility) which will track the FTP connections and attempt to maintain a data connection to the client dynamically. ``` # RHEL / CentOS == /etc/sysconfig/iptables-config IPTABLES_MODULES="ip_nat_ftp ip_conntrack_ftp" # Debian / Ubuntu == /etc/modules ip_nat_ftp ip_conntrack_ftp ``` These can be loaded immediately using `modprobe` (`modprobe ip_nat_ftp ip_conntrack_ftp`) instead of rebooting. Additionally, vsftpd includes a number of variables which can also be used to set the behaviour of the static/dynamic ports used in either mode: ``` # Enable PORT (active) mode FTP and force 20 for data port_enable=YES connect_from_port_20=YES ftp_data_port=20 # Set a specific range of data ports in PASV (passive) mode pasv_enable=YES pasv_addr_resolve=NO pasv_min_port=23000 # 0 = use any port pasv_max_port=23100 # 0 = use any port ``` ## Virtual chroot Users This section is a description of the general method used in this article (but not exactly): - The scripts on that page can be used to perform a majority of this work, however those scripts are missing a few items outlined below based on using the ftp system user to own files rather than the virtual user - use those scripts with caution. The account user/pass are stored in a Berkeley DB format file, so the proper package must be installed to provide the `db_load` command: ``` ## RHEL / CentOS yum -y install db4-utils ## Debian / Ubuntu apt-get update && apt-get -y install db-util ``` ### vsftpd.conf The configuration can be built to use virtual users based on the `user_config_dir` variable combined with the others; the key settings for vsftpd.conf: ``` vsftpd.conf # These are in addition to any other normal config (SSL, etc.) anon_world_readable_only=NO anonymous_enable=NO chroot_local_user=YES guest_enable=YES guest_username=ftp hide_ids=YES local_enable=YES nopriv_user=ftp pam_service_name=ftp user_config_dir=/etc/vsftpd/users userlist_enable=YES userlist_file=/etc/vsftpd/denied_users anon_umask=022 local_umask=022 dirlist_enable=NO download_enable=NO virtual_use_local_privs=YES ``` Create the core virtual chroot parent directory as listed above: ``` mkdir -p /var/ftp/virtual_users ``` Create the plain text file to store user/pass information imported to a DB: ``` # This is the input to create a DB hash file # - for ultimate security it would not be left on the server touch /etc/vsftpd/accounts.tmp chmod 0600 /etc/vsftpd/accounts.tmp ``` ### PAM ftp The above config specifies an alternate PAM configuration; create the file `/etc/pam.d/ftp` with the required config to use an alternate database: ``` /etc/pam.d/ftp auth required pam_userdb.so db=/etc/vsftpd/accounts account required pam_userdb.so db=/etc/vsftpd/accounts ``` ### SELinux If required, enable SELinux anonymous writes: ``` setsebool -P allow_ftpd_anon_write 1 ``` ### Adding a User First, the core login config for a user has to be created under the directory outlined by `user_config_dir` which matches the login name. The name _testuser_ will be used as an example: ``` /etc/vsftpd/users/testuser dirlist_enable=YES download_enable=YES local_root=/var/ftp/virtual_users/testuser write_enable=YES ``` Next, add the user to the core denied users specified by `userlist_file` above: ``` echo "testuser" >> /etc/vsftpd/denied_users ``` Create their system level user and chown their virtual user to _ftp_ instead due to the `virtual_use_local_privs` setting above: ``` useradd -d /var/ftp/virtual_users/testuser -s /sbin/nologin testuser chmod 0750 /var/ftp/virtual_users/testuser chown ftp:ftp /var/ftp/virtual_users/testuser # If SELinux is active chcon -t public_content_rw_t /var/ftp/virtual_users/testuser ``` Add their account/password to the text DB import file and create the DB: ``` echo "testuser" >> /etc/vsftpd/accounts.tmp echo "testpass" >> /etc/vsftpd/accounts.tmp db_load -T -t hash -f /etc/vsftpd/accounts.tmp /etc/vsftpd/accounts.db.new mv -f /etc/vsftpd/accounts.db.new /etc/vsftpd/accounts.db chmod 0600 /etc/vsftpd/accounts.db ``` ### Reloading Users The daemon needs reloaded after user changes: ``` service vsftpd reload ``` ### Updating a User The Update process is changing the same info used during Add: 1. Use `usermod` to alter the system user info as needed 2. Update the user/pass in `/etc/vsftpd/accounts.tmp` and rebuild `/etc/vsftpd/accounts.db` Typically in this scenario the password is being updated. ### Removing a User The process is an exact reverse of the Add process: 1. Remove the 2 lines in `/etc/vsftpd/accounts.tmp` for their user/pass and rebuild `/etc/vsftpd/accounts.db` 2. Remove the user from the system using `userdel` 3. Remove the user from `/etc/vsftpd/denied_users` 4. Remove the user config from `/etc/vsftpd/users/` directory Parts of the steps can be left – for example, if the content of the old `$HOME` directory is to be preserved, do not run userdel. ## References - -