Pure-FTPd is a free (BSD), secure, production-quality and standard-conformant FTP server. It doesn’t provide useless bells and whistles, but focuses on efficiency and ease of use. It provides simple answers to common needs, plus unique useful features for personal users as well as hosting providers.
The goal of this post is to replace an existing ProFTPd installation on one of our Debian Stable (Sarge) systems with a fully-functional Pure-FTPd installation. The MySQL database used for ProFTPd user management should remain unchanged to keep customers happy.
Installation
Debian comes with a number of different Pure-FTPd packages. As we want MySQL support, we install the pure-ftpd-mysql package. There is one problem with the package, though: It removes our existing ProFTPd packages. That means you should probably test deployment of Pure-FTPd on one of your test boxes first, before rolling it out on your production server.
apt-get install pure-ftpd-mysql
When asked, choose standalone mode. As Pure-FTPd is started automatically after the installation of the packkage, you may want to stop it until you have configured everything according to you needs.
/etc/init.d/pure-ftpd-mysql stop
Basic configuration
Have a look at the PureFTPd configuration directory. Configuration is stored in /etc/pure-ftpd/conf and each file represents one configuration option. The name of the file is the name of the configuration option and the first line of the file is the setting of the configuration option. You want to delete the PureDB file as we don’t need that one and edit the PAMAuthentication file to say no. That disables PAM authentication. Have a look at your system configuration and edit the MinUID file if you require user ids beyond 1000.
MySQL database and configuration
I will now show you the structure of our existing MySQL database for ProFTPd. Yours may be different. If you don’t have a MySQL database you can keep the standard layout proposed by Pure-FTPd documentation (see /usr/share/doc/pure-ftpd-mysql/). Our database structure looks something like this:
CREATE TABLE `users` (
`id` int(10) unsigned NOT NULL auto_increment,
`username` varchar(150) NOT NULL default '',
`uid` smallint(5) unsigned NOT NULL default '1003',
`gid` smallint(5) unsigned NOT NULL default '1502',
`groupname` varchar(20) NOT NULL default 'ftp',
`password` varchar(15) NOT NULL default '',
`shell` varchar(15) NOT NULL default '/bin/false',
`homedir` text NOT NULL,
`status` int(2) NOT NULL default '1',
`added` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `username` (`username`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=17 ;
We will now edit the Pure-FTPd MySQL configuration file so that we can reuse the layout of this database. Open the file /etc/pure-ftpd/db/mysql.conf.
MYSQLUser your_username
MYSQLPassword your_password
MYSQLDatabase your_database
# how passwords are stored. in our case: crypt
MYSQLCrypt crypt
MYSQLGetPW SELECT password FROM users WHERE username='\L' AND status='1'
MYSQLGetUID SELECT uid FROM users WHERE username='\L' AND status='1'
MYSQLGetGID SELECT gid FROM users WHERE username='\L' AND status='1'
MYSQLGetDir SELECT homedir FROM users WHERE username='\L' AND status='1'
This should get you going. We basically use the format proposed by the Pure-FTPd documentation. Only the names of the fields are adapted to fit our existing database layout. Checking the status field in every query to the database enpowers you to disable certain FTP accounts without deleting the account information from the database. This might be useful for security reasons or if you are a hosting provider and you want to put some pressure on customers that do not pay their bills.
As you might have guessed, you only need the fields username, password, uid, gid and homedir for Pure-FTPd to work. status is not really neccessary, but is quite useful for day-to-day administration. So is the added field. Both the groupname and the shell fields, however, might be dropped from the database entirely after a successul migration.
Advanced MySQL options
You might want to add fields to implemet virtual quota or bandwidth restrictions. Those features are well documented by Pure-FTPd and are not discussed in this post.
Advanced configuration
You might want to evaluate some other configuration options.
If you want Pure-FTPd to listen to a specific IP address only, create a file called Bind in the configuration directory containing the IP address in question followed by a comma and the port Pure-FTPd should use, for example 192.168.0.1,21 for the IP address 192.168.0.1 and the port 21.
For security reasons, you probably also want to chroot each user to its home directory. To accomplish this, create a file called ChrootEveryone with the content yes.
If you are a webhosting provider, consider setting the option CustomerProof to yes. This prevents your users from making bad chmod commands, that would deny access to files or directories to themselves. Also consider setting DisplayDotFiles to yes to display dot files at all times, regardless of the ls command issued by the client.
If you want to display a message at connection time, create a file called FortunesFile containing the path to the file, that contains the contents to be displayed.
Useful options to prevent denial of service attacks (DoS) include MaxClientsPerIP to limit the number of clients that can be connected from one IP address at the same time and MaxDiskUsage that defines a maximum percentage of used disk space on your hard drive beyond which further uploads are denied automatically.
Possible problems
You might experience problems, if you use special characters in your usernames. For example, # is not allowed and access is denied without a log message stating why. If you are on a test server and the MySQL log is enabled, you can see that in those cases, where a username contains illegal characters, Pure-FTPd does not try to fetch data from the database, but otherwise you can’t tell. See Pure-FTPd documentation for a list of characters that are not allowed in usernames.
Ready, set, go!
You can now start your server and test everything to death.
/etc/init.d/pure-ftpd-mysql start