ProFTPD module mod_proxy



The purpose of the mod_proxy module is to provide FTP proxying capabilities in proftpd, both reverse (or "gateway") proxying and forward proxying.

Installation instructions are discussed here. Note that mod_proxy requires ProFTPD 1.3.6rc2 or later. Detailed notes on best practices for using this module are here.

This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/).

This product includes cryptographic software written by Eric Young (eay@cryptsoft.com).

The most current version of mod_proxy can be found at:

  https://github.com/Castaglia/proftpd-mod_proxy.git

Author

Please contact TJ Saunders <tj at castaglia.org> with any questions, concerns, or suggestions regarding this module.

Thanks

2015-08-24: Thanks to Michael Toth <mtoth at queldor.net> for helping test multiple iterations of mod_proxy with IIS servers.

Directives


ProxyDataTransferPolicy

Syntax: ProxyDataTransferPolicy client|active|passive|pasv|epsv|port|eprt
Default: ProxyDataTransferPolicy client
Context: server config, <VirtualHost>, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc1 and later

The ProxyDataTransferPolicy directive configures the data transfer policy that mod_proxy uses when performing data transfers (e.g. file uploads/downloads, directory listings) with the backend/destination server.

The currently supported policies are:


ProxyDatastore

Syntax: ProxyDatastore type [info]
Default: ProxyDatastore SQLite
Context: server config
Module: mod_proxy
Compatibility: 1.3.6rc1 and later

The ProxyDatastore directive configures the type of datastore that mod_proxy uses for persistence. The currently supported datastore types are:

Note that the Redis type also requires the info parameter, namely a prefix for all of the Redis keys. This prefix must be different/unique among all of your mod_proxy servers using that Redis server/cluster; the prefix is used to keep all of the data for this server separate from all other servers. For example:

  <IfModule mod_proxy.c>

    ...
    <IfModule mod_redis.c>
      # Use our IP address as our prefix
      ProxyDatastore Redis 1.2.3.4.
    </IfModule>
  </IfModule>


ProxyDirectoryListPolicy

Syntax: ProxyDirectoryListPolicy client|"LIST" [opt1 ...]
Default: ProxyDirectoryListPolicy client
Context: server config, <VirtualHost>, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc1 and later

The ProxyDirectoryListPolicy directive configures the directory list policy that mod_proxy uses when performing directory lists with the backend/destination server.

The currently supported policies are:

You may also provide options; the currently implemented options are:


ProxyEngine

Syntax: ProxyEngine on|off
Default: None
Context: server config, <VirtualHost>, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc1 and later

The ProxyEngine directive toggles the support for proxying by mod_proxy. This is usually used inside a <VirtualHost> section to enable proxying of FTP sessions for a particular virtual host. By default mod_proxy is disabled for both the main server and all configured virtual hosts.


ProxyForwardEnabled

Syntax: ProxyForwardEnabled on|off
Default: None
Context: <Class>
Module: mod_proxy
Compatibility: 1.3.6rc2 and later

The ProxyForwardEnabled directive determines whether a client can use mod_proxy for forward proxying, based on that client's class.

By default, mod_proxy rejects any forward proxy request from any client, with the exception of clients connecting from RFC 1918 addresses:

  192.168.0.0/16
  172.16.0.0/12
  10.0.0.0/8
This is done as a security measure: open/unrestricted proxy servers are dangerous both to your network and to the Internet at large. Thus to make it possible for clients to use your server for forward proxying, they must be explicitly enabled to do so.

Example:

  <Class forward-proxy>
    From 1.2.3.4/12

    # Allow clients from this class to use FTP forward proxying
    ProxyForwardEnabled on
  </Class>

See also: ProxyForwardTo


ProxyForwardMethod

Syntax: ProxyForwardMethod method
Default: None
Context: server config, <VirtualHost>, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc1 and later

The ProxyForwardMethod directive configures the method that clients can use for requesting forward proxying. Some methods require that the client authenticate to the proxy first, and then separately authenticate to the destination server; these methods differ on just when the client specifies the destination server. Other methods do not require proxy authentication. There are many variations on a theme with these methods.

The currently supported methods are:

Configuring the FTP client's proxy settings to match the above methods varies greatly, depending on the FTP client.


ProxyForwardTo

Syntax: ProxyForwardTo [!]pattern [flags]
Default: None
Context: server config, <VirtualHost>, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc1 and later

The ProxyForwardTo directive is used to restrict which hosts/domains can be requested for forward proxying. The destination host/port for forward proxying must match the configured pattern regular expression, or the forward proxying request will fail.

The optional flags parameter, if present, modifies how the given pattern will be evaludated. The supported flags are:

ProxyForwardTo limits the destination hosts to which clients can request forward proxying; by contrast, ProxyForwardEnabled controls forward proxying based on where clients connect from.

Example:

  # Limit forward proxying to specific host and port
  ProxyForwardTo ^ftp.example.com:21$


ProxyLog

Syntax: ProxyLog path|"none"
Default: None
Context: server config, <VirtualHost>, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc1 and later

The ProxyLog directive is used to specify a log file for mod_proxy's reporting on a per-server basis. The path parameter given must be the full path to the file to use for logging.

Note that this path must not be to a world-writable directory and, unless AllowLogSymlinks is explicitly set to on (generally a bad idea), the path must not be a symbolic link.


ProxyOptions

Syntax: ProxyOptions opt1 ...
Default: None
Context: server config, <VirtualHost>, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc1 and later

The ProxyOptions directive is used to configure various optional behavior of mod_proxy. For example:

  ProxyOptions UseProxyProtocolV1

The currently implemented options are:


ProxyRetryCount

Syntax: ProxyRetryCount count
Default: ProxyRetryCount 5
Context: server config, <VirtualHost>, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc1 and later

The ProxyRetryCount directive configures the number of times mod_proxy will attempt to connect to the backend/destination server. The default is 5 attempts.


ProxyReverseConnectPolicy

Syntax: ProxyReverseConnectPolicy policy
Default: RoundRobin
Context: server config, <VirtualHost>, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc1 and later

The ProxyReverseConnectPolicy directive configures the policy that mod_proxy will use for selecting the backend server when reverse proxying.

The currently supported policies are:


ProxyReverseServers

Syntax: ProxyReverseServers servers
Default: None
Context: server config, <VirtualHost>, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc1 and later

The ProxyReverseServers directive configures the list of servers to be used as the backend servers for reverse proxying.

Each server must be configured as a URL. Only the "ftp" and "ftps" schemes are currently supported. If not specified, the port will be 21. IPv6 addresses must be enclosed within square brackets. Thus, for example, the following are all valid URLs:

  ftp://ftp1.example.com:2121
  ftp://1.2.3.4
  ftp://[::ffff:6.7.8.9]:2121
  ftps://ftp2.example.com
  ftps://ftp3.example.com:990
And using them all in the configuration would look like:
  ProxyReverseServers ftp://ftp1.example.com:2121 ftps://1.2.3.4 ftp://[::ffff:6.7.8.9]:2121

The backend servers can also be discovered via DNS SRV or TXT records, using SRV/TXT URL scheme variants, e.g.:

  # Discover backend addresses via DNS SRV records
  ftp+srv://_ftp._tcp.castaglia.org

  # Discover backend addresses via DNS TXT records (which must be an FTP URL)
  ftp+txt://castaglia.org
These SRV/TXT URL scheme variations also apply to FTPS URLs. Note that any explicit port numbers provided in URLs using these SRV/TXT scheme variants will be ignored; the actual port numbers to use will be discovered from the SRV and TXT DNS records.

The backend servers can also be contained in a list in a JSON file, e.g.:

[
  "ftp://ftp1.example.com:2121",
  "ftp://[::ffff:6.7.8.9]:2121"
]
You then only need to configure the path to that JSON file:
  ProxyReverseServers file:/path/to/backends.json

Note that mod_proxy has strict requirements for the permissions on ProxyReverseServers files. The configured file must not be world-writable, since that would allow any user on the system to modify the file, directing proxied connections anywhere else. If a world-writable ProxyReverseServers file is found, you will see the following error message logged:

  unable to use world-writable ProxyReverseServers '/opt/proxy/reverse.json' (perms 0666): Operation not permitted
In addition, the directory containing the ProxyReverseServers file cannot be world-writable, either. Even if the file itself is not world-writable, being in a world-writable directory means that any user on the system can delete that file, and write a new file. When a world-writable directory is found, the following error is logged:
  unable to use ProxyReverseServers '/opt/proxy/reverse.json' from world-writable directory '/opt/proxy' (perms 0777): Operation not permitted

The backend servers can also be provided from an external SQL database, queried by mod_proxy via SQLNamedQuery. For example, assuming a schema such as this:

  CREATE TABLE proxy_user_servers (
    user_name TEXT,
    url TEXT
  );

  CREATE INDEX proxy_user_servers_name_idx ON proxy_user_servers (user_name);
where url contains URLs, e.g. "ftp://1.2.3.4:21". Then you would configure mod_proxy to query for those per-user backend URLs using ProxyReverseServers like this:
  <IfModule mod_sql.c>
    ...
    SQLNamedQuery get-user-servers SELECT "url FROM proxy_user_servers WHERE user_name = %{0}"
  </IfModule>

  ProxyRole reverse
  ProxyReverseConnectPolicy PerUser
  ProxyReverseServers sql:/get-user-servers

Given that mod_proxy uses SQLite, does that mean that the table used for storing these per-user URLs must be SQLite? No. The use of SQLNamedQuery means that any database, supported by mod_sql, can be used.


ProxyRole

Syntax: ProxyRole role
Default: None
Context: server config, <VirtualHost>, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc1 and later

The ProxyRole directive configures whether mod_proxy will perform forward or reverse proxying. The list of supported roles are thus:

Note that the ProxyRole directive is required for mod_proxy to function. If this directive is not configured, connections to mod_proxy will fail.


ProxySFTPCiphers

Syntax: ProxySFTPCiphers algo1 ...
Default: None
Context: server config, <VirtualHost>, <Global>
Module: mod_proxy
Compatibility: 1.3.8rc3 and later

The ProxySFTPCiphers directive is used to specify the list of cipher algorithms that mod_proxy should use when connecting to backend SSH servers. The current list of supported cipher algorithms is, in the default order of preference:

By default, all of the above cipher algorithms are presented to the server, in the above order, during the key exchange.

The "none" cipher (i.e. no encryption) will not be presented to the server by default; any sites which wish to use "none" will have to explicitly configure it via ProxySFTPCiphers.

Note that CTR mode ciphers (e.g. the aes128-ctr, aes192-ctr, and aes256-ctr ciphers) are recommended. Any CBC mode cipher allows for the possibility of an attack which causes several bits of plaintext to be leaked; the attack is described here. This attack is on the SSH2 protocol design itself; any SSH2 implementation which conforms to the RFCs will have this weakness.

In general, there is no need to use this directive unless only one specific cipher must be used.


ProxySFTPCompression

Syntax: ProxySFTPCompression on|off|delayed
Default: None
Context: server config, <VirtualHost>, <Global>
Module: mod_proxy
Compatibility: 1.3.8rc3 and later

The ProxySFTPCompression directive enables the use of zlib compression of the payload of SSH2 packets. This can make for smaller packets, but require more CPU time to compress/uncompress the data.

The delayed parameter tells mod_proxy to support a custom extension used by OpenSSH, where compression is not actually enabled until after the client has successfully authenticated.


ProxySFTPDigests

Syntax: ProxySFTPDigests algo1 ...
Default: None
Context: server config, <VirtualHost>, <Global>
Module: mod_proxy
Compatibility: 1.3.8rc3 and later

The ProxySFTPDigests directive is used to specify the list of MAC digest algorithms that mod_proxy should use when connecting to backend SSH servers. The current list of supported MAC algorithms is:

By default, all of the above MAC algorithms are presented to the server, in the above order, during the key exchange. Note that some algorithms (e.g. the SHA256 and SHA512 algorithms) may not be supported by the version of OpenSSL used; this will be automatically detected.

The following list of algorithms are supported, but not presented to servers by default. These algorithms must be explicitly configured via ProxySFTPDigests to be available for use by servers:

The "none" MAC (i.e. no MAC) will not be presented to the server by default; any sites which wish to use "none" will have to explicitly configure it via ProxySFTPDigests.

In general, there is no need to use this directive unless only one specific MAC algorithm must be used.


ProxySFTPHostKey

Syntax: ProxySFTPHostKey file|agent:/path
Default: None
Context: server config, <VirtualHost>, <Global>
Module: mod_proxy
Compatibility: 1.3.8rc3 and later

The ProxySFTPHostKey directive configures the path to a host key file. The mod_proxy module uses the keys thus configured for "hostbased" user authentication to backend SSH servers.

You can use either an RSA key, a DSA key, and/or ECDSA keys. These could be the exact same host key files as used by your SSH server, e.g.:

  <IfModule mod_sftp.c>
    ...
    SFTPHostKey /etc/ssh_host_dsa_key
    SFTPHostKey /etc/ssh_host_rsa_key
    SFTPHostKey /etc/ssh_host_ecdsa_key
    SFTPHostKey /etc/ssh_host_ed25519_key
  </IfModule>

  <IfModule mod_proxy.c>
    ProxyEngine on
    ..
    ProxySFTPHostKey /etc/ssh_host_dsa_key
    ProxySFTPHostKey /etc/ssh_host_rsa_key
    ProxySFTPHostKey /etc/ssh_host_ecdsa_key
    ProxySFTPHostKey /etc/ssh_host_ed25519_key
  </IfModule>

The ProxySFTPHostKey directive can also be used to load host keys from an SSH agent such as OpenSSH's ssh-agent. For example:

  # Load all of the keys from the ssh-agent configured for proxy use
  ProxySFTPHostKey agent:%{env:SSH_AUTH_SOCK}
Using an SSH agent for storing host keys allows for configurations where the host keys are not stored on files on the server system, e.g. the keys can be loaded into the SSH agent from a PKCS#11 token.


ProxySFTPKeyExchanges

Syntax: ProxySFTPKeyExchanges algo1 ...
Default: None
Context: server config, <VirtualHost>, <Global>
Module: mod_proxy
Compatibility: 1.3.8rc3 and later

The ProxySFTPKeyExchanges directive is used to specify the list of key exchange algorithms that mod_proxy should use when connecting to backend SSH servers. The current list of supported key exchange algorithms is:

By default, all of the above key exchange algorithms except diffie-hellman-group1-sha1 are presented to the server, in the above order, during the key exchange.

Note that the diffie-hellman-group1-sha1 key exchange algorithm uses a weak hardcoded Diffie-Hellman group, and thus is not enabled by default. To enable this key exchange algorithm, you must configure the ProxySFTPKeyExchanges list to explicitly include this algorithm, or use the following in your configuration:

  ProxySFTPOptions AllowWeakDH

In general, there is no need to use this directive unless only one specific key exchange algorithm must be used.


ProxySFTPOptions

Syntax: ProxySFTPOptions opt1 ...
Default: None
Context: server config, <VirtualHost>, <Global>
Module: mod_proxy
Compatibility: 1.3.8rc3 and later

The ProxySFTPOptions directive is used to configure various optional SSH-specific behavior of mod_proxy.

For example:

  ProxySFTPOptions AllowWeakDH

The currently implemented options are:


ProxySFTPPassPhraseProvider

Syntax: ProxySFTPPassPhraseProvider path
Default: None
Context: server config, <VirtualHost>, <Global>
Module: mod_proxy
Compatibility: 1.3.8rc3 and later

The ProxySFTPPassPhraseProvider directive is used to specify an external program which will be called, when mod_proxy starts up, for each encrypted ProxySFTPHostKey file. The program will be invoked with two command-line arguments, passed on stdin to the program:

  servername:portnumber file
where servername:portnumber indicates the server using that encrypted certificate key, and file indicates the host key file in question. The program then must print the corresponding passphrase for the key to stdout.

The intent is that this external program can perform any security checks necessary, to make sure that the system is not compromised by an attacker, and only when these checks pass successfully will the passphrase be provided. These security checks, and the way the passphrase is determined, can be as complex as you like.

Example:

  ProxySFTPPassPhraseProvider /etc/ftpd/proxy/get-ssh-passphrase


ProxySFTPServerAlive

Syntax: ProxySFTPServerAlive count interval
Default: None
Context: server config, <VirtualHost>, <Global>
Module: mod_proxy
Compatibility: 1.3.8rc3 and later

The ProxySFTPServerAlive directive configures mod_proxy to send messages to a server, through the encrypted channel, to request a response from the server. If count server alive messages are sent without receiving any response messages from the server, the client will disconnect. The interval indicates how much time, in seconds, that mod_proxy waits for data from the server before sending a server alive message.

For example, using:

  ProxySFTPServerAlive 3 15
will cause an unresponsive server to be disconnected after approximately 45 seconds.


ProxySFTPServerMatch

Syntax: ProxySFTPServerMatch pattern key1 val1 ...
Default: None
Context: server config, <VirtualHost>, <Global>
Module: mod_proxy
Compatibility: 1.3.8rc3 and later

The ProxySFTPServerMatch directive is used to tune some of the SSH2/SFTP values based on the connected server, for better interoperability with those servers. The pattern parameter specifies a POSIX regular expression which will be matched against the connected server's SSH version banner. If the server's banner version matches pattern, then the configured keys/values are used for that session.

The currently supported SSH2/SFTP keys which can be tuned via ProxySFTPServerMatch are:


ProxySFTPVerifyServer

Syntax: ProxySFTPVerifyServer on|off
Default: ProxySFTPVerifyServer off
Context: server config, <VirtualHost>, <Global>
Module: mod_proxy
Compatibility: 1.3.8rc3 and later

The ProxySFTPVerifyServer directive tells mod_proxy whether to verify whether the host keys presented by backend SSH servers have changed.

When mod_proxy connects to a backend SSH server for the very first time, its hostkey will be recorded. The next time mod_proxy connects, the hostkey presented will be compared to the previously recorded hostkey. When ProxySFTPVerifyServer is on, any hostkey mismatches will be logged.


ProxySourceAddress

Syntax: ProxySourceAddress address
Default: None
Context: server config, <VirtualHost>, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc1 and later

The ProxySourceAddress directive configures the address (or device name) of a network interface on the host machine, to be used when connecting to the backend/destination server. This directive is most useful on a multi-homed (or DMZ) host; frontend connections can be received on one network interface, and the backend connections can use a different network interface. Imagine e.g. separate WAN/LAN interfaces on a proxying host.


ProxyTables

Syntax: ProxyTables table-info
Default: None
Context: server config
Module: mod_proxy
Compatibility: 1.3.6rc1 and later

The ProxyTables directive is used to specify a directory that mod_proxy will use for storing its database files; these files are used for tracking the various load balancing/healthcheck statistics used for proxying.

Note that the ProxyTables directive is required for mod_proxy to function. If this directive is not configured, connections to mod_proxy will fail.


ProxyTimeoutConnect

Syntax: ProxyTimeoutConnect timeout
Default: ProxyTimeoutConnect 5sec
Context: server config, <VirtualHost>, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc1 and later

The ProxyTimeoutConnect directive configures the amount of time that mod_proxy will wait for the backend/destination server to accept a TCP connection, before giving up.

Note that if there are many different backend/destination servers to try (due to e.g. ProxyRetryCount), and if those backend servers are slow, the connecting client might itself see connection timeouts to mod_proxy. To guard against such slow backend servers, a more aggressively short timeout can be used:

  ProxyTimeoutConnect 1sec


ProxyTimeoutLinger

Syntax: ProxyTimeoutLinger timeout
Default: ProxyTimeoutLinger 3sec
Context: server config, <VirtualHost>, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc1 and later

The ProxyTimeoutLinger directive configures the amount of time that mod_proxy will wait (lingering), after receiving all of the data on the data transfer connection to the backend server, for the explicit "end of transfer" response from the backend server, before giving up.


ProxyTLSCACertificateFile

Syntax: ProxyTLSCACertificateFile path
Default: None
Context: server config, <VirtualHost>, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc2 and later

The ProxyTLSCACertificateFile directive configures one file where you can assemble the certificates of Certification Authorities (CA) which will be used to verify the servers' certificates. Such a file is merely the concatenation of the various PEM-encoded CA certificates. This directive can be used in addition to, or as an alternative for, ProxyTLSCACertificatePath.

Example:

  ProxyTLSCACertificateFile /etc/ftpd/cacerts.pem

Note that the location of CA certificates is required for mod_proxy's TLS support; verification of server certificates is required for secure connections to backend/destination servers. For this reason, mod_proxy ships with its own default ProxyTLSCACertificateFile, which is generated using libcurl's mk-ca-bundle.pl script:

  $ lib/mk-ca-bundle.pl -u cacerts.pem


ProxyTLSCACertificatePath

Syntax: ProxyTLSCACertificatePath directory
Default: None
Context: server config, <VirtualHost>, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc2 and later

The ProxyTLSCACertificatePath directive sets the directory for the certificates of Certification Authorities (CAs); these are used to verify the server certificates presented. This directive may be used in addition to, or as alternative for, ProxyTLSCACertificateFile.

The files in the configured directory have to be PEM-encoded, and are accessed through hash filenames. This means one cannot simply place the CA certificates there: one also has to create symbolic links named hash-value.N. The c_rehash utility that comes with OpenSSL can be used to create the necessary symlinks.

Example:

  ProxyTLSCACertificatePath /etc/ftpd/cacerts/


ProxyTLSCARevocationFile

Syntax: ProxyTLSCACertificateFile path
Default: None
Context: server config, <VirtualHost>, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc2 and later

The ProxyTLSCARevocationFile directive configures one file that can contain the Certificate Revocation Lists (CRL) of Certification Authorities (CA); these CRLs are used during the verification of server certificates. Such a file is merely the concatenation of the various PEM-encoded CRL files. This directive can be used in addition to, or as an alternative for, ProxyTLSCARevocationPath.

Example:

  ProxyTLSCARevocationFile /etc/ftpd/cacrls.pem


ProxyTLSCARevocationPath

Syntax: ProxyTLSCARevocationPath directory
Default: None
Context: server config, <VirtualHost>, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc2 and later

The ProxyTLSCARevocationPath directive sets the directory for the Certificate Revocation Lists (CRL) of Certification Authorities (CAs); these are used during the verification of server certificates. This directive may be used in addition to, or as alternative for, ProxyTLSCARevocationFile.

The files in the configured directory have to be PEM-encoded, and are accessed through hash filenames. This means one cannot simply place the CRLs there: one also has to create symbolic links named hash-value.N. The c_rehash utility that comes with OpenSSL can be used to create the necessary symlinks.

Example:

  ProxyTLSCARevocationPath /etc/ftpd/cacrls/


ProxyTLSCertificateFile

Syntax: ProxyTLSCertificateFile path
Default: None
Context: server config, <VirtualHost>, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc2 and later

The ProxyTLSCertificateFile directive points to the PEM-encoded file containing the client certificate file, and optionally also the corresponding private key. Note that this directive is only needed for backend/target FTPS servers which require client authentication.

Example:

  ProxyTLSCertificateFile /etc/ftpd/client-cert.pem


ProxyTLSCertificateKeyFile

Syntax: ProxyTLSCertificateKeyFile path
Default: None
Context: server config, <VirtualHost>, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc2 and later

The ProxyTLSCertificateKeyFile directive points to the PEM-encoded file containing the client certificate file, and optionally also

The ProxyTLSCertificateKeyFile directive points to the PEM-encoded private key file for the client certificate indicated by ProxyTLSCertificateFile. If the private key is not combined with the certificate in the ProxyTLSCertificateFile, use this additional directive to point to the file with the standalone private key. When ProxyTLSCertificateFile is used and the file contains both the certificate and the private key, this directive need not be used. However, this practice is strongly discouraged. Instead we recommend you to separate the certificate and the private key.


ProxyTLSCipherSuite

Syntax: ProxyTLSCipherSuite [protocol] cipher-list
Default: ProxyTLSCipherSuite DEFAULT:!ADH:!EXPORT:!DES
Context: server config, <VirtualHost>, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc2 and later

The ProxyTLSCipherSuite directive configures the list of acceptable SSL/TLS ciphersuites to use for backend SSL/TLS connections. The syntax is that of the OpenSSL ciphers command, e.g.:

  $ openssl ciphers -v <cipher-list>
may be used to list all of the ciphers and the order described by a specific <cipher-list>.

If the SSL library supports TLSv1.3 (e.g. OpenSSL-1.1.1 and later), the protocol specifier "TLSv1.3" can be used to configure the cipher suites for that protocol:

  # Configure TLSv1.3 ciphersuites
  ProxyTLSCipherSuite TLSv1.3 TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256


ProxyTLSEngine

Syntax: ProxyTLSEngine on|off|auto|MatchClient
Default: ProxyTLSEngine auto
Context: server config, <VirtualHost>, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc2 and later

The ProxyTLSEngine directive configures the use of SSL/TLS for backend FTP connections. Note that SSL/TLS support requires the presence/use of the mod_tls ProFTPD module.

The supported values are:


ProxyTLSOptions

Syntax: ProxyTLSOptions options
Default: None
Context: server config, <VirtualHost>, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc2 and later

The ProxyTLSOptions directive is used to configure various optional SSL/TLS behavior of mod_proxy.

Example:

  ProxyTLSOptions EnableDiags

The currently implemented options are:


ProxyTLSPreSharedKey

Syntax: ProxyTLSPreSharedKey identity key-info
Default: None
Context: server config, <VirtualHost>, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc2 and later

The ProxyTLSPreSharedKey directive is used to configure a pre-shared key (PSK), for use in TLS-PSK ciphersuites. Each PSK has an identity (a string/name used by clients to request the use of that PSK), and the actual key data. The key data may be encoded in different ways; the ProxyTLSPreSharedKey directive requires that the data be hex-encoded, as indicated in the key-info parameter.

The key-info parameter is comprised of the type of encoding used for the key data, and the full path to the key file. Only "hex" encoding is supported right now. Thus an example ProxyTLSPreSharedKey directive would be:

  ProxyTLSPreSharedKey MyPSK hex:/path/to/psk.key
The configured file cannot be world-readable or world-writable; the mod_proxy module will skip/ignore such insecure permissions.

To generate this shared key (which is just a randomly generated bit of data), you can use:

  $ openssl rand 160 -out /path/to/identity.key -hex
Note that ProxyTLSPreSharedKey requires at least 20 bytes of key data. Having generated the random key data, tell mod_proxy to use it via:
  ProxyTLSPreSharedKey identity hex:/path/to/identity.key


ProxyTLSProtocol

Syntax: ProxyTLSProtocol protocols
Default: ProxyTLSProtocol TLSv1 TLSv1.1 TLSv1.2
Context: server config, <VirtualHost>, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc2 and later

The ProxyTLSProtocol directive is used to configure the SSL/TLS protocol versions that mod_proxy should use when establishing SSL/TLS sessions to backend servers.

The allowed protocols are:

SSLv3 Use only SSLv3
TLSv1 Use only TLSv1
TLSv1.1 Use only TLSv1.1
TLSv1.2 Use only TLSv1.2

To support both SSLv3 and TLSv1, simply list both parameters for the ProxyTLSProtocol directive, e.g.:

  ProxyTLSProtocol SSLv3 TLSv1

The ProxyTLSProtocol directive can also be used in a different manner, to add or subtract protocol support. For example, to enable all protocols except SSLv3, you can use:

  ProxyTLSProtocol ALL -SSLv3
Using the directive in this manner requires that "ALL" be the first parameter, and that all protocols have either a + (add) or - (subtract) prefix. "ALL" will always be expanded to all of the supported SSL/TLS protocols known by mod_proxy and supported by OpenSSL.


ProxyTLSTimeoutHandshake

Syntax: ProxyTLSTimeoutHandshake timeout
Default: ProxyTLSTimeoutHandshake 30sec
Context: server config, <VirtualHost>, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc2 and later

The ProxyTLSTimeoutHandshake directive configures the maximum number of seconds for mod_proxy to complete an SSL/TLS handshake. If set to zero, mod_proxy will wait forever for a handshake to complete. The default is 30 seconds.


ProxyTLSTransferProtectionPolicy

Syntax: ProxyTLSTransferProtectionPolicy client|required|clear
Default: ProxyTLSTransferProtectionPolicy required
Context: server config, <VirtualHost>, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc1 and later

The ProxyTLSTransferProtectionPolicy directive configures the data transfer protection policy, when using SSL/TLS, that mod_proxy uses when performing data transfers (e.g. file uploads/downloads, directory listings) with the backend/destination server.

The currently supported policies are:


ProxyTLSVerifyServer

Syntax: ProxyTLSVerifyServer on|off
Default: ProxyTLSVerifyServer on
Context: server config, <VirtualHost>, <Global>
Module: mod_proxy
Compatibility: 1.3.6rc2 and later

The ProxyTLSVerifyServer directive configures how mod_proxy handles certificates presented by servers. If off, the module will accept any server certificate and establish an SSL/TLS session, but will not verify the certificate. If on, the module will verify a server's certificate and, furthermore, will fail all SSL handshake attempts unless the server presents a valid certificate.


Usage

Benefits of Proxying
The benefits of using a module like mod_proxy depend mostly on the type of proxying, forward or reverse, that mod_proxy is configured to perform. There are some benefit, however, that the module can bring, regardless of the type of proxying:

When using mod_proxy for proxying, all data transfers (e.g. file uploads/downloads, directory listings, etc) pass through mod_proxy; data transfers do not occur directly between the "frontend" clients and the "backend" servers. This happens so that clients are completely unaware of the network structure for the backend servers; this is especially important when reverse proxying, where it means that the client sees mod_proxy as the real FTP server.

Forward Proxying
One of the most common benefits of a forward proxy is having controlled access, by clients within an internal LAN, to outside servers. FTP makes this sort of thing notoriously difficult for firewalls/routers due to its multi-TCP connection nature; this, in turn, makes proxying of FTP more difficult. But mod_proxy makes this possible; it understands FTP, and thus provides the access control needed for such use cases.

When using mod_proxy as a forward proxy, FTP clients which can only perform active data transfers can use mod_proxy as a way to use passive data transfers with the destination FTP server.

Similarly, FTP clients which do not support IPv6 can proxy through mod_proxy to reach a destination FTP server with an IPv6 address; mod_proxy handles IPv4 and IPv6 addresses transparently.

Reverse Proxying
Just as mod_proxy can aid naive/legacy FTP clients via forward proxying, mod_proxy can similarly front legacy FTP servers. For example, mod_proxy can sit in front of FTP servers which do not handle IPv6 addresses, and provide this functionality transparently to IPv6-capable FTP clients.

When performing reverse proxying, mod_proxy can also perform load balancing in various ways. The common methods of "round robin" and "least connections" are implemented; mod_proxy also provides "sticky session" load balancing of clients as well.

Handling of Proxied Sessions
Once a proxied session has authenticated with the backend/destination server, the mod_proxy module automatically chroots itself to a subdirectory of the ProxyTables directory, after which all root privileges are permanently dropped.

Forward Proxy Configuration
Before discussing example forward proxy configurations for mod_proxy, it is very important to understand the consequences of providing forward proxy capabilities.

Important Security Considerations
A forward proxy can be used by any client to have the proxy connect to any arbitrary host, while hiding the client's true identity. Malicious behavior, hacking or denial-of-service attempts, etc will appear to be coming from your proxy; this is dangerous for your network, and for the Internet at large. Think of the damage that has been done, and continues to happen, due to open/unrestricted proxies/relays such as open DNS or SMTP/email proxies.

This is the reason that mod_proxy does not allow just any client to use its forward proxy capabilities by default; instead, only clients connecting from the LAN are allowed by default. Allowing trusted outside clients is done using the ProxyForwardEnabled directive. Even allowing internal clients to use your forward proxy can be troublesome, depending on the destination hosts selected by the clients. To ensure that your clients are using the forward proxy to connect only to the hosts allowed, you can use the ProxyForwardTo directive to configure a regular expression-based whitelist of allowed destination/target hosts; this is strongly recommended.

With all that said, here's an example mod_proxy configuration for supporting forward proxying:

  <IfModule mod_proxy.c>
    ProxyEngine on
    ProxyLog /path/to/proxy.log
    ProxyTables /var/ftp/proxy

    ProxyRole forward
    ProxyForwardMethod user@host
    ProxyForwardTo ^ftp\.example\.com\:21$ [NC]
  </IfModule>
If the configured ProxyForwardTo pattern is not met, the following will be logged in the ProxyLog:
mod_proxy/0.7[16151]: host/port 'server.example.org:2121' did not match ProxyForwardTo ^ftp\.example\.com\:21$, rejecting

Reverse Proxy Configuration
Reverse proxies (also known as "gateways") are often used to provide access to FTP resources, located with internal networks, to the outside world. The reverse proxy can perform load balancing, provide functionality that the internal servers may not be able to do, and even perform things like caching.

Access control for reverse proxies is less critical than for forward proxies because clients can only reach, via the reverse proxy, the backend servers that the reverse proxy has been configured to use; the clients do not get to choose arbitrary hosts for the reverse proxy to use.

Here's an example mod_proxy configuration for supporting reverse proxying:

  <IfModule mod_proxy.c>
    ProxyEngine on
    ProxyLog /path/to/proxy.log
    ProxyTables /var/ftp/proxy

    ProxyRole reverse
    ProxyReverseConnectPolicy RoundRobin
    ProxyReverseServers ftp://ftp-backend1.example.com:2121 ftp://ftp-backend2.example.com:2121 ...
  </IfModule>

Here's an example mod_proxy configuration for reverse proxying, with lookup of per-user backend servers:

  <IfModule mod_proxy.c>
    ProxyEngine on
    ProxyLog /path/to/proxy.log
    ProxyTables /var/ftp/proxy

    ProxyRole reverse
    ProxyReverseConnectPolicy PerUser

    # We need to provide a pool of backend servers as a fallback
    ProxyReverseServers ftp://ftp-backend1.example.com:2121 ftp://ftp-backend2.example.com:2121 ...

    # Look up per-user backend servers from user-specific JSON files
    ProxyReverseServers file:/var/ftp/proxy/backends/%U.json
  </IfModule>
Similarly, you can use a per-group lookup for the backend servers when reverse proxying:
  <IfModule mod_proxy.c>
    ProxyEngine on
    ProxyLog /path/to/proxy.log
    ProxyTables /var/ftp/proxy

    ProxyRole reverse
    ProxyReverseConnectPolicy PerGroup
    ProxyOptions UseReverseProxyAuth

    # We need to provide a pool of backend servers as a fallback
    ProxyReverseServers ftp://ftp-backend1.example.com:2121 ftp://ftp-backend2.example.com:2121 ...

    # Look up per-group backend servers from group-specific JSON files
    ProxyReverseServers file:/var/ftp/proxy/backends/%g.json
  </IfModule>

In order to support FTP over SSL/TLS (FTPS) connections from clients when reverse proxying, simply include your normal mod_tls configuration with the same <VirtualHost> configuration with your mod_proxy configuration.

For FTPS support to the backend servers, your reverse proxy configuration would look something like this:

  <IfModule mod_proxy.c>
    ProxyEngine on
    ProxyLog /path/to/proxy.log
    ProxyTables /var/ftp/proxy

    ProxyRole reverse
    ProxyReverseConnectPolicy RoundRobin
    ProxyReverseServers ftp://ftp-backend1.example.com:2121 ftp://ftp-backend2.example.com:2121 ...

    # Use FTPS when supported/available by the backend server
    ProxyTLSEngine auto

    # List of trusted root CAs
    ProxyTLSCACertificateFile /etc/ftpd/cacerts.pem
  </IfModule>
In fact, mod_proxy comes with a default ProxyTLSCACertificateFile (comprised of the root CAs that most browsers use/trust), and the default ProxyTLSEngine value is auto. This means that, by default, mod_proxy will try to use FTPS for backend connections automatically (assuming that ProFTPD is built with OpenSSL support using the --enable-openssl configure option).

Load Balancing versus Session Stickiness
For reverse proxy configurations, there is a choice between load balancing and sticky session ProxyReverseConnectPolicy parameters; these parameters determine the selection of the backend server that will handle the incoming connection.

Which should you use, and why?

All of the balancing policies are able to select the backend server when the FTP client connects to the proxy, before sending any commands. Most of the "sticky" policies, on the other hand, require more knowledge about the user (e.g. USER name, HOST name, SSL session ID) before the backend server can be determined, thus backend server selection is delayed until that information is obtained.

Balancing is best when all of your backend severs are identical with regard to the content they have, and when it does not matter which server handles a particular client. Maybe all of your backend servers use a shared filesystem via NFS or similar, thus directory listings will be the same for a user no matter which backend server is used, and uploading files to one server means that those files can be downloaded/seen by the other servers. Balancing policies are also best when all of your backend servers have similar processing power (memory, CPU, network, disk), so that all backend servers are equally capable of providing the same service to the connecting client.

The balancing policies are:

Stickiness is best when your backend servers are not identical, and some users/clients should only ever go to the same set of backend servers. Thus the user/client needs to be "sticky" to a given backend server.

The sticky policies are:

Implicit FTPS Support
The mod_proxy module includes support for using implicit FTPS with backend servers, both when forward and reverse proxying. Note that implicit FTPS support requires the presence/use of the mod_tls ProFTPD module.

In order to use implicit FTPS for a reverse proxy server, the URI syntax must be used in a ProxyReverseServers directive; the scheme must be "ftps" and the port must be explicitly specified as 990, thus: ProxyReverseServers ftps://ftp.example.com:990

When forward proxying, the client must request the destination server and specify a port of 990, e.g.: USER user@ftp.example.com:990

Note that there is an additional wrinkle/caveat for implicit FTPS support when your mod_proxy installation uses shared/DSO modules. You must ensure, in a list of LoadModule directives, that mod_proxy appears before mod_tls:

  # Make sure that mod_tls appears after mod_proxy in the list of loaded
  # modules
  LoadModule mod_proxy.c
  LoadModule mod_tls.c
Why does this matter?

A lot of things happen when a client connects, via TCP, to the server (in this case, to a server configured to be a proxy). ProFTPD publishes this "on connect" event to all of the modules, in "module load order". The last module loaded will be the first module to receive this event; this means "module loader order" is the reverse order of your LoadModule directives.

What we want is for the mod_tls module to handle the "on connect" event first, so that it handles the implicit TLS handshake. In doing so, the mod_tls module will record some internal session state showing that a TLS handshake occurred. The mod_proxy module looks for the internal session state that mod_tls sets, and will Do The Right Thing if it sees that a TLS session is in effect.

On the other hand, if mod_proxy appears after mod_tls in the LoadModule list, then it is the mod_proxy module which handles the "on connect" event before mod_tls does. mod_proxy looks for the session state to see if a TLS session is in effect, does not find the session state, and then attempts to proxy things like the backend banner to the client. The frontend client is expecting TLS handshake bytes, not plaintext text bytes from the banner, and thus the frontend client will see a TLS error.

SFTP/SCP Support
The mod_proxy module now supports reverse proxying (but not forward proxying) of SFTP/SCP sessions.

To support a reverse proxy configuration for SFTP/SCP sessions, specify the sftp scheme in your ProxyReverseServers URIs, like so:

  <IfModule mod_proxy.c>
    ProxyEngine on
    ProxyLog /path/to/proxy.log
    ProxyTables /var/ftp/proxy

    ProxyRole reverse
    ProxyReverseConnectPolicy RoundRobin
    ProxyReverseServers sftp://ssh-backend1.example.com:2222 sftp://ssh-backend2.example.com ...
  </IfModule>

When proxying SSH connections like this, there will be two separate SSH sessions:

  frontend client --- (SSH session #1) --> proxy --- (SSH session #2) --> backend server
Each SSH session creates a unique session ID, as a hash of client- and server-provided values known as H. This is important for some types of authentication, as we see later.

Proxying of SSH connections is more complex than proxying of FTP/FTPS connections, especially when it comes to authentication. FTP supports simple password-based authentication, whereas SSH supports multiple different authentication mechanisms. And two authentication mechanisms, in particular, require a slightly more sophisticated mod_proxy configuration: "hostbased" and "publickey".

When the frontend SSH client requests the "keyboard-interactive" or "password" authentication mechanisms, then mod_proxy can handle the client using the above configuration as-is. For the "hostbased" and "publickey" authentication mechanisms, mod_proxy needs to do a little more work -- and it requires support on the backend servers for "hostbased" authentication.

Let's consider the common "publickey" use case (the frontend "hostbased" case is quite similar). The frontend client has a public/private key pair; mod_proxy has no knowledge or access to that frontend private key (by design). The frontend client performs the "publickey" authentication by hashing several types of data, then encrypts that hash with its private key; the server (mod_proxy in this case) then hashes the same data, and decrypts the client-sent value with the client's public key. The complication is that one of the types of data included in these hashes is the unique session ID known as H mentioned above. The H values for the SSH connections (from the frontend client to the proxy, and separately from the proxy to the backend server) will be different. And since mod_proxy has no access to the frontend private key, it cannot forge or change H (and this is a good thing). But it does mean that mod_proxy cannot simply proxy the "publickey" authentication request as is, from frontend client to backend server.

Instead, for these authentication mechanisms, mod_proxy will use a different authentication mechanism, specifically "hostbased" authentication, to the backend server. This makes sense, right? The backend server trusts that the proxy is doing proper handling of all frontend clients, thus backend server can trust the entire proxy host, not just individual clients proxied by that host. In order support these backend "hostbased" authentication requests, mod_proxy will need to know its private key to use for such things, via ProxySFTPHostKey; this can actually the same private key used by the SFTPHostKey directive (or be a different private key, depending on your needs). It also requires that the backend servers be configured to trust the corresponding public key; for mod_sftp, this would be done using its SFTPAuthorizedHostKeys directive.

The SFTP/SCP support in mod_proxy also properly supports the PerUser, PerGroup ProxyReverseConnectPolicy values, subject the same caveats. This means that mod_proxy can proxy different frontend SSH users to different backend servers (and even rewrite/change the user name via the mod_rewrite module); just like for FTP/FTPS sessions, you can configure the per-user lookup of backend servers using SQL queries, JSON files, etc.

Logging
The mod_proxy module supports different forms of logging. The main module logging is done via the ProxyLog directive. For debugging purposes, the module also uses trace logging, via the module-specific channels:

Thus for trace logging, to aid in debugging, you would use the following in your proftpd.conf:

  TraceLog /path/to/proxy-trace.log
  Trace proxy:20
This trace logging can generate large files; it is intended for debugging use only, and should be removed from any production configuration.

Logging Notes
The following is a list of notes, logging variables that can be used in custom LogFormats and/or custom SQL statements:

SELinux
If using the mod_proxy module on an SELinux-enabled system, you may need the following to allow for proper operations of proxying. For example, using the following mod_proxy configuration:

  ProxyTables /var/ftp/proxy
may require that you run:
  $ semanage fcontext --add --type public_content_rw_t '/var/ftp/proxy(/.*)?'
  $ setsebool -P ftpd_anon_write=1
  $ setsebool -P nis_enabled=1

Suggested Future Features
The following lists the features I hope to add to mod_proxy, according to need, demand, inclination, and time:

See the GitHub issues page for current bugs and feature requests, and to report issues.

Frequently Asked Questions

Question: I have heard a lot about both "round robin" and "least conns" for load balancing. Which is better for FTP connections?
Answer: There is not an easy answer to this, because it really comes down to the type of traffic that your FTP servers will see.

If your FTP sessions tend to be long-lived (e.g. on the order of minutes to hours), then using ProxyReverseConnectPolicy LeastConns will tend to provide the best distribution of those sessions across your pool of backend servers. The assumption here is that new connections arrive infrequently relative to the number of existing connections.

On the other hand, if your FTP sessions tend to be shorter (e.g. minutes at most), then using ProxyReverseConnectPolicy RoundRobin might provide a more even distribution of connections across your pool of backend servers.

Question: I am using:

  ProxyReverseConnectPolicy PerHost
and would like to configure different pools of backend servers for different incoming clients. How do I do this?
Answer: The best way to achieve this would be to use classes and mod_ifsession's <IfClass> sections. For example:
  <Class proxied-clients>
  </Class>

  ProxyRole reverse
  ProxyReverseConnectPolicy PerHost

  <IfClass proxied-clients>
    ProxyReverseServers ftp://ftp-special1.example.com:2121 ftp://ftp-special2.example.com:2121 ...
  </IfClass>

  # Don't forget to configure the backend server pool for clients coming
  # from other networks!
  <IfClass !proxied-clients>
    ProxyReverseServers ftp://ftp-backend1.example.com:2121 ftp://ftp-backend2.example.com:2121 ...
  </IfClass>

Question: Does mod_proxy support SSL/TLS connections, i.e. FTPS?
Answer: Short answer: yes.

The long answer is the mod_proxy supports FTPS connections both on the frontend, from connecting clients, and on the backend, to backend servers. This means that all of the following flows are supported:

  client --- FTPS ---> proxy --- FTP ---> server
  client --- FTP ---> proxy --- FTPS ---> server
  client --- FTPS ---> proxy --- FTPS ---> server

Thus mod_proxy's FTPS support is suited for reverse proxy configurations, where mod_proxy can be used to provide SSL/TLS capabilities to old/legacy FTP servers which do not implement it. The mod_proxy module is also suited for forward proxy configurations, where the FTPS support can be used to provide SSL/TLS capabilities to old/legacy FTP clients which do not implement it.

Question: I want to use mod_proxy for reverse proxying. I want to centralize all of my user authentication in mod_proxy, and I want to use different user credentials when logging in to the backend servers. Can mod_proxy do all of this?
Answer: Yes.

There are a couple of key parts of your mod_proxy configuration to pay attention to, for achieving the above.

  <IfModule mod_proxy.c>
    ProxyEngine on
    ProxyLog /path/to/proxy.log
    ProxyTables /var/ftp/proxy

    ProxyRole reverse

    # Make sure to authenticate in the proxy itself
    ProxyOptions UseReverseProxyAuth

    ProxyReverseConnectPolicy ...

    # Include the username/passwords to use for the backend servers
    # in the URLs.
    ProxyReverseServers ftp://user1:password1@ftp-backend1.example.com:2121 ftp://user2:password2@ftp-backend2.example.com:2121 ...
  </IfModule>
When a URL uses the "username:password" syntax for including the credentials to use for that connection, mod_proxy will use those URI credentials when logging in to that backend server.

Question: I have configured mod_proxy to block the LIST command for one group of users, like so:

  <Limit LIST>
    DenyGroup somegroup
  </Limit>
But this <Limit> is not working. Is this a bug?
Answer: No, it is not a bug. It is, unfortunately, expected behavior.

The <Limit> mechanism works on the authenticated user/group names. And in many cases, it is not mod_proxy which authenticates the user, it is the backend server. Thus it is the backend server which knows the groups to which the authenticated user belongs; mod_proxy only knows that the USER name was successfully authenticated by the backend user. Thus group-based limits cannot be honored.

However, if proxy auth is enabled, then group-based limits will work. This means using either the following when forward proxying:

  ProxyRole forward

  # Either of these two methods result in proxy auth
  ProxyForwardMethod proxyuser,user@host
  ProxyForwardMethod proxyuser@host,user
or this, when reverse proxying:
  ProxyRole reverse
  ProxyOptions UseReverseProxyAuth

Question: Can mod_proxy be configured as a reverse proxy, and to select the backend server based on the client certificate used by the frontend FTPS client?
Answer: Yes, but it requires the use of a custom SQL query.

The idea here is to define a SQL query which looks up the backend server to use, based on information in the frontend FTPS client certificate. Since the mod_proxy module already uses SQLite, you should be able to use the mod_sql_sqlite module if needed. The SQL table schema might look like:

  CREATE TABLE proxy_backends (
    common_name TEXT PRIMARY KEY,
    url TEXT
  );
  <IfModule mod_tls.c>
    ...
    # Tell mod_tls to export environment variables containing various
    # certificate fields, for use by e.g. mod_sql.
    TLSOptions StdEnvVars
    ...
  </IfModule>

  <IfModule mod_sql.c>
    ...
    # Use the TLS_CLIENT_S_DN_CN environment variable (for the CommonName of
    # the Subject section of the frontend FTPS client certificate) provided
    # by mod_tls in our selection.
    SQLNamedQuery get-user-servers SELECT "url FROM proxy_backends WHERE common_name = '%{env:TLS_CLIENT_S_DN_CN}'"
    ...
  </IfModule>

  <IfModule mod_proxy.c>
    ...
    ProxyRole reverse
    ProxyReverseConnectPolicy PerUser

    # Use a named SQL query to lookup the backend server to use.  Note that
    # the name used here is the name of our SQLNamedQuery defined above.
    ProxyReverseServers sql:/get-user-servers
    ...
  </IfModule>
Note that the mod_tls module provides many other environment variables for other fields of the certificate; using a field other than CommonName is also quite doable, depending on your needs.


Installation

To install mod_proxy, go to the third-party module area in the proftpd source code and unpack the mod_proxy source tarball:
  $ cd proftpd-dir/contrib/
  $ tar zxvf /path/to/mod_proxy-version.tar.gz
after unpacking the latest proftpd-1.3.x source code. For including mod_proxy as a statically linked module:
  $ ./configure --with-modules=mod_proxy:...
To build mod_proxy as a DSO module:
  $ ./configure --enable-dso --with-shared=mod_proxy:...
Then follow the usual steps:
  $ make
  $ make install
Note: mod_proxy uses the SQLite library; thus the sqlite3 development library/headers must be installed for building mod_proxy.

It is highly recommended that SQLite 3.8.5 or later be used. Problems have been reported with mod_proxy when SQLite 3.6.20 is used; these problems disappeared once SQLite was upgraded to a newer version. Note: mod_proxy uses the OpenSSL library, so its development library/header files must be installed for building mod_proxy.


© Copyright 2015-2025 TJ Saunders
All Rights Reserved