Set up a FTP server (pure-ftpd-mysql)

There are multiple reasons I recommend using pure-ftpd-mysql as ftp service: can authenticate both physical and virtual (read from database) users. It’s highly but easily configurable.


apt-get install pure-ftpd-mysql

The configuration files are found at /etc/pure-ftpd.

By default, pure-ftpd authenticates only users that has an uid 1000 or over. Thus root cannot authenticate (having uid of 0). By default, when the system was installed, a user was created and this has the uid of 1000, so you can authenticate with this user: go to an another computer (over LAN) and try to connect via a FTP client.

To authenticate virtual users, first you need to set up  the following:

  • have access to MYSQL tables via ip, username and password
  • create a table that has the following important fields: username, password (encoded as md5, sha1, crypt or password) and an optional field ftp_enabled that is 1 if the user’s FTP access it’s enabled.

Edit the /etc/pure-ftpd/db/mysql.conf file and uncomment/change the following lines:

  • MYSQLServer ip-address (leave if localhost)
  • MYSQLPort port (leave 3306 if not changed)
  • MYSQLUser mysql_username
  • MYSQLPassword mysql_password
  • MYSQLDatabase mysql_database_name
  • MYSQLCrypt crypt (md5, sha1, crypt or password)
  • MYSQLGetPW SELECT `ftp_password` FROM `users` WHERE `username`=”\L” AND `ftp_enabled`>0 AND `account_status`=0
  • MYSQLGetDir SELECT CONCAT(‘/var/ftp/’, LPAD(`id`, 8, ‘0’)) FROM `users` WHERE `username`=”\L”

Note on the last setting: pure-ftpd-mysql will create automatically a separate directory for each authenticated user in /var/ftp. The lpad function just pads the username with zeroes up to 8 characters. Obviously you can have anything here to name the user’s directory.

Important settings

To add startup options for the FTP service, go to /etc/pure-ftpd/conf and create files named as the options in the documentation. Be careful, the documentation lists the options lowercase, but the configuration files needs to be named with capitalized words (would be nice to write the documentation correctly…). The files contain the respective options as text (yes, no, 1, 500, etc.)

The following config files that have importance:

  •  AllowDotFiles – yes|no; Allow anonymous users to read files/directories starting with dot (hidden)
  • CreateHomeDir – yes; It’s important to automatically create the home dir for virtual users
  • CustomerProof – yes; Prevents your users against making bad ‘chmod’ commands, that would deny access to files/directories to themselves.
  • DontResolve – yes; Prevent reverse DNS lookup. Useful to speed up the FTP connection (if the main DNS server is down or unreachable, the FTP connection slows down to crawl).
  • MaxClientsNumber – XXX; Adjust this number according to the server capacity and number of expected clients.
  • MaxClientsPerIP – X;
  • MaxIdleTime – XX; In minutes.
  • NoAnonymus – yes|no; Allow/deny anonymous authentication.
  • NoChmod – yes|no; Allow/deny the chmod command.
  • PAMAuthentication – yes|no; Allow/deny authentication of physical users.
  • PerUserLimits – X Y; X – max connections with the same username, Y – max anonymous connections.

To apply the settings, restart the server

/etc/init.d/pure-ftpd-mysql restart

If there are errors upon startup, you need to check the configuration file names or their content.

You may read the full documentation at

2 thoughts on “Set up a FTP server (pure-ftpd-mysql)

    1. Theoretically it’s possible, but I didn’t tested…
      The steps:
      1. Create a table `ratios` with some IP address fragments and their respective limits and user id’s.
      2. Using pure MySQL, find and read the appropriate record from `ratios`, based on the IP and user.

      From the /etc/pure-ftpd/db/mysql.conf file:

      # In the following directives, parts of the strings are replaced at
      # run-time before performing queries :
      # L is replaced by the login of the user trying to authenticate.
      # I is replaced by the IP address the user connected to.
      # P is replaced by the port number the user connected to.
      # R is replaced by the IP address the user connected from.
      # D is replaced by the remote IP address, as a long decimal number.
      # Very complex queries can be performed using these substitution strings,
      # especially for virtual hosting.
      # Optional : ratios. The server has to be compiled with ratio support.
      # MySQLGetRatioUL SELECT ULRatio FROM users WHERE User="L"
      # MySQLGetRatioDL SELECT DLRatio FROM users WHERE User="L"

      Playing with the MySQL’s string functions, the location of the user may be determined from the R (IP-address) and L (user’s login name), and the appropriate record can be read, returning the scalar value of the upload and/or download ratio.

      Although undocumented, I guess, null values for MySQLGetRatioUL & MySQLGetRatioDL means ‘no limit’.

Leave a Reply

Your email address will not be published. Required fields are marked *