ProFTPD Quotas

A busy FTP server handles hundreds to thousands of files belonging to hundreds to thousands of users. There is not an infinite capacity on the disks of the server, however, and eventually those files will take up too much space. Thus many sites have a pressing need to set limits on just how much can be stored on the server by their users.

Most Unix systems have support for OS- or fileystem-level quotas. These have the advantage of being transparent to applications like proftpd, which means that the applications need not worry about maintaining and enforcing quotas. The kernel/filesystem will handle that. One disadvantage these OS-level quotas have, though, is that they are strictly tied to OS and/or filesystem, and not all Unix kernels and filesystems are the same. They also rely on each user having their own separate user ID. In the case of virtual users for proftpd, it is possible for many users to have the same user ID, which causes problems for these traditional Unix quotas.

For these reasons, the mod_quotatab module was developed for ProFTPD. This module, being part of the application, applies to all the Unix kernels and filesystems which support ProFTPD, and easily handles virtual users. The mod_quotatab documentation covers how to configure proftpd for quotas.

Note: This howto is a work-in-progress. Please contact me with suggestions, questions, requests, etc for what you would like to see covered here. Thanks!

Example Configuration
Here is an example mod_quotatab configuration for supporting quotas via file tables and SQL tables. This is an example only.

    QuotaEngine on
    QuotaLog /var/log/ftpd/quota.log

    # For more information on using files for storing the limit and tally
    # table quota data, please see the mod_quotatab_file documentation:
      QuotaLimitTable file:/etc/ftpd/ftpquota.limittab
      QuotaTallyTable file:/etc/ftpd/ftpquota.tallytab

    # For more information on using a SQL database for storing the limit and
    # tally table quota data, please see the mod_quotatab_file documentation:
      SQLNamedQuery get-quota-limit SELECT "* FROM quotalimits WHERE name = '%{0}' AND quota_type = '%{1}'"
      SQLNamedQuery get-quota-tally SELECT "* FROM quotatallies WHERE name = '%{0}' AND quota_type = '%{1}'"
      SQLNamedQuery update-quota-tally UPDATE "bytes_in_used = \
              bytes_in_used + %{0}, bytes_out_used = bytes_out_used + %{1}, \
              bytes_xfer_used = bytes_xfer_used + %{2}, \
              files_in_used = files_in_used + %{3}, \
              files_out_used = files_out_used + %{4}, \
              files_xfer_used = files_xfer_used + %{5} \
              WHERE name = '%{6}' AND quota_type = '%{7}'" quotatallies
      SQLNamedQuery insert-quota-tally INSERT "%{0}, %{1}, %{2}, %{3}, %{4}, %{5}, %{6}, %{7}" quotatallies

      QuotaLock /var/lock/ftpd.quotatab.lock
      QuotaLimitTable sql:/get-quota-limit
      QuotaTallyTable sql:/get-quota-tally/update-quota-tally/insert-quota-tally

Frequently Asked Questions

Question: How do I set the disk space limit for a user?
Answer: The short answer is to use the "upload bytes limit" setting.

It's true that the various limits maintained by mod_quotatab, for either bytes or files (or both), are confusing. When designing the module, I anticipated administrators wanting to limit download as well as upload transfers; in reality, most administrators wish to limit the disk space for their users. The bytes uploaded limit doubles as the disk space limit, for there is no effective difference between them; any bytes uploaded via FTP are automatically stored on disk.

Question: mod_quotatab only tracks changes made using proftpd, and my users can add/remove files other ways. What am I supposed to do?
Answer: As the mod_quotatab documentation states, the module was designed only to track changes done via FTP; it made implementation of quotas simpler.

This question is also often posed as "Why can't mod_quotatab just calculate the amount of space used by a user?" The module could do this, but there are some considerations with this kind of approach.

The primary consideration is the time cost of having to recurse a directory. If the directory is relatively small, the time needed is small. For very large/deep directories, however, the time needed to do the scan could be long, possibly long enough for users to notice and complain. Another complication is the disk space used by a given user is not confined to their home directory. Many sites have home directories for users, and have a shared directory that all users can use. Somehow mod_quotatab would need to know to scan these shared directories.

This feature has been requested enough, though, that I am planning on adding the capability to mod_quotatab at some point in the future, as it is clearly useful for administrators.

Question: If mod_quotatab does not automatically scan for disk space usage, how will it know about my existing users?
Answer: By default, mod_quotatab indeed knows nothing about what disk space is already occupied by your users; the tally table starts out blank.

To help address this, there is a Perl script:
which will display the number of bytes owned by a given user (or group) within a list of directories. The parameters needed for running are documented here.

Once you've run to find out the current usage for your users, you can enter those numbers into your tally table. Unfortunately cannot read your proftpd.conf file to know whether you are using a file- or SQL-based tally table, so it cannot automatically update your tally table.

Question: How can I set a default quota for all of my users?
Answer: Unfortunately, there is no way currently to do this. The mod_quotatab module was designed such that the administrator would have to explicitly create limits for every user.

However, a mod_quotatab_default module could be written to provide default quotas. I simply do not know if this would be desirable enough to users for writing the module.

Question: What is a "tally table"?
Answer: Tally tables, and limit tables, are covered in the mod_quotatab documentation.

Question: How do I construct the limit and tally files for file-based quotas?
Answer: There is a Perl script called ftpquota which can create the necessary files. This script can also be found under the contrib/ directory of the proftpd source distribution.

Question: Is there a SQL script for the SQL quota tables used by mod_quotatab_sql?
Answer: No. However, the mod_quotatab_sql documentation contains example schema for the necessary tables.

Question: How do I set a limit on the size of a directory?
Answer: Currently, you cannot.

Traditional Unix quotas are implemented in terms of ownership: the thing that counts is not where a file is located on the filesystem, but which user and/or group owns the file. Asking about directory quotas assumes a different basis for quotas, based on location rather than ownership (such quotas are often called tree-based quotas). The mod_quotatab module followed the example of traditional Unix quotas, but I have started designing how location-based quotas might be implemented.

Question: Why isn't mod_quotatab updating my tally table?
Answer: It depends.

One possibility is that the per session flag in the limit in effect is set to true, which means that the limits will only be applied to this session. When this happens, mod_quotatab will not update the tally table.

If this is not the case, then consider looking in the QuotaLog file for more information.

Question: How can users see their current quota?
Answer: There are two ways to show the current quota to users. There is the SITE QUOTA command. And there are certain Display variables that are supported by the mod_quotatab module.

Question: What if I want to set limits on the size of individual files being transferred?
Answer: For this, you do not need the mod_quotatab module. ProFTPD has the MaxRetrieveFileSize and MaxStoreFileSize directives.

Question: Why do I see the following error?

  QuotaLimitTable: unsupported table source type: 'sql'
Answer: The mod_quotatab module acts as a general quota managing front-end; it relies on other backend modules to handle the specifics of storage formats. Every backend module (e.g. mod_quotatab_file, mod_quotatab_sql, mod_quotatab_ldap) registers a supported table type with the main mod_quotatab module. The error above indicates that the mod_quotatab_sql module has not been compiled/loaded into proftpd.