Installing Pure-FTPd

Distribution specific, roughly:

root@host # emerge -pv pure-ftpd

These are the packages that would be merged, in order:

Calculating dependencies ... done!
[ebuild  N    ] net-ftp/pure-ftpd-1.0.21-r1  USE="-anondel -anonperm -anonren \
  -anonres -caps -charconv ldap -mysql -noiplog pam -paranoidmsg postgres \
  (-selinux) ssl vchroot -xinetd" 0 kB

# Or
user@host $ sudo aptitude install pure-ftpd

Adjust USE flags as necessary, mysql and postgres can be useful for account data storage. The vchroot option is very cool.

Preparing Firewall

root@host # iptables -A INPUT -p tcp -m tcp --dport 20:21 -j ACCEPT

Distribution specific methods to perisist your firewall state/rules, do that now.

Configuring Pure-FTPd

Pure-FTPd runs with strictly command line options, no configuration file. On Gentoo these are kept in the usual place, conf.d; Ubuntu see below. Edit /etc/conf.d/pure-ftpd to start, setting parameters as necessary, here is an OK version.

# This limits accounts to only what is in the Pure-FTPd database
AUTH="-lpuredb:/etc/pureftpd.pdb"

# Post Upload Processor
UPLOADSCRIPT="/opt/edoceo/sbin/ftp-post-upload.sh"

# 

MISC_OTHER="--chrooteveryone --noanonymous --dontresolve --nochmod -p 20000:20099 --prohibitdotfileswrite --customerproof --tls=1"

Add Users

This setup changes ownership of files to a common FTP user and make a vchroot jail for them to work in

# mkdir /home/$user
# chown -R $user:ftp /home/$user
# pure-pw useradd $user -u www-data -g www-data -d /var/ftp

Pure-FTPd Upload Script

Here is a basic starter script for an email notification and moving the uploaded file to a private location.

#!/bin/bash
#
# Post Upload script for client-ftp space
# Use lots of quotes
#
# :mode=shellscript:
#

# Set by Pure-FTPd
# $UPLOAD_SIZE, $UPLOAD_PERMS, $UPLOAD_UID, $UPLOAD_GID, $UPLOAD_USER, $UPLOAD_GROUP, $UPLOAD_VUSER

ftp_file="$1"
ftp_file_name=$(basename "$ftp_file")
ftp_file_dest="/tmp/upload-$ftp_file_name"
ftp_notify="user@domain.tld"

out_file=$(tempfile)

cat <<EOF > $out_file
Subject: File Upload Notification

The user: '$UPLOAD_VUSER'
Uploaded: '$ftp_file_name'
Stored @: '$ftp_file_dest'

Literally:
EOF

# Move (and show output)
mv -v "$ftp_file" "$ftp_file_dest" >> $out_file 2>&1

# show debug?
# set >> $out_file

# Send Notice
cat $out_file | /usr/sbin/sendmail "$ftp_notify"

rm $out_file

Pure-FTPd + SSL/TLS

Pure-FTPd can be enabled with SSL/TLS security, so that connections can (or must) be encrypted. Simply create a PEM format file and then start Pure-FTPd with --tls=1. The path to this file is compiled into Pure-FTPd, typically /etc/ssl/private/pure-ftpd.pem

# create the PEM file
root@host # cat /etc/ssl/server.key /etc/ssl/server.crt > /etc/ssl/private/pure-ftpd.pem

# Configure --tls=#
root@host # grep MISC /etc/conf.d/pure-ftpd
MISC_OTHER="-A -E -H -R -x -Z --tls=1"

Then restart /etc/init.d/pure-ftpd restart, when connecting the banner should present something like the following.

ncftp ftp.server.tld
NcFTP 3.2.4 (Apr 07, 2010) by Mike Gleason (http://www.NcFTP.com/contact/).
Connecting to 169.123.123.123...
--------- Welcome to Pure-FTPd [privsep] [TLS] ----------
You are user number 1 of 30 allowed.
Local time is now 10:56. Server port: 21.
This is a private system - No anonymous login
IPv6 connections are also welcome on this server.
You will be disconnected after 5 minutes of inactivity.
Login authentication failed

Notice the [TLS] message in the banner.

Pure-FTPd on Ubuntu

After installing in the normal way settings in /etc/pure-ftpd/conf need to be set, they are one-line per file entries. They are mapped according to the file /usr/sbin/pure-ftpd-wrapper. Other settings are contained in /etc/default/pure-ftpd-common for UPLOADSCRIPT for example.

To create a similar configuration as above do the following:

cd /etc/pure-ftpd
echo yes > ./conf/ChrootEveryone
echo yes > ./conf/DontResolve
echo yes > ./conf/NoChmod
echo yes > ./conf/ProhibitDotFilesWrite
echo yes > ./conf/CustomerProof
echo '20000 20099' > ./conf/PassivePortRange
/etc/init.d/pure-ftpd restart

Configuring Authentication

On Ubuntu we like to change around the Auth settings, removing PAM and Unix auth and replacing it with just PurePW databases. First take a look at what's there, it's managed via symbolic links which are processed in order. If using multiple authentications (which I'd rather not) I like to put Pure first.

cd /etc/pure-ftpd/auth
ls -alh 
rm ./*
ln -s ../conf/PureDB ./50pure

Ubuntu Configuration Directives

'AllowAnonymousFXP' => ['-W'],
'AllowDotFiles' => ['-z'],
'AllowUserFXP' => ['-w'],
'AltLog' => ['-O %s', \&parse_string],
'AnonymousBandwidth' => ['-t %s', \&parse_number_1_2],
'AnonymousCanCreateDirs' => ['-M'],
'AnonymousCantUpload' => ['-i'],
'AnonymousOnly', => ['-e'],
'AnonymousRatio' => ['-q %d:%d', \&parse_number_2],
'AntiWarez' => ['-s'],
'AutoRename' => ['-r'],
'Bind' => ['-S %s', \&parse_string],
'BrokenClientsCompatibility' => ['-b'],
'CallUploadScript' => ['-o'],
'ChrootEveryone' => ['-A'],
'CreateHomeDir' => ['-j'],
'CustomerProof' => ['-Z'],
'Daemonize' => ['-B'],
'DisplayDotFiles' => ['-D'],
'DontResolve' => ['-H'],
'ForcePassiveIP' => ['-P %s', \&parse_string],
'FortunesFile' => ['-F %s', \&parse_filename],
'FSCharset' => ['-8 %s', \&parse_string],
'ClientCharset' => ['-9 %s', \&parse_string],
'IPV4Only' => ['-4'],
'IPV6Only' => ['-6'],
'KeepAllFiles' => ['-K'],
'LimitRecursion' => ['-L %d:%d', \&parse_number_2_unlimited],
'LogPID' => ['-1'],
'MaxClientsNumber' => ['-c %d', \&parse_number_1],
'MaxClientsPerIP' => ['-C %d', \&parse_number_1],
'MaxDiskUsage' => ['-k %d', \&parse_number_1],
'MaxIdleTime' => ['-I %d', \&parse_number_1],
'MaxLoad' => ['-m %d', \&parse_number_1],
'MinUID' => ['-u %d', \&parse_number_1],
'NATmode' => ['-N'],
'NoAnonymous' => ['-E'],
'NoChmod' => ['-R'],
'NoRename' => ['-G'],
'NoTruncate' => ['-0'],
'PassivePortRange' => ['-p %d:%d', \&parse_number_2],
'PerUserLimits' => ['-y %d:%d', \&parse_number_2],
'ProhibitDotFilesRead' => ['-X'],
'ProhibitDotFilesWrite' => ['-x'],
'Quota' => ['-n %d:%d', \&parse_number_2],
'SyslogFacility' => ['-f %s', \&parse_word, 99],
'TLS' => ['-Y %d', \&parse_number_1],
'TrustedGID' => ['-a %d', \&parse_number_1],
'TrustedIP' => ['-V %s', \&parse_ip],
'Umask' => ['-U %s:%s', \&parse_umask],
'UserBandwidth' => ['-T %s', \&parse_number_1_2],
'UserRatio' => ['-Q %d:%d', \&parse_number_2],
'VerboseLog' => ['-d'],

See Also