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
Please contact TJ Saunders <tj at castaglia.org> with any questions, concerns, or suggestions regarding this module.
2015-08-24: Thanks to Michael Toth <mtoth at queldor.net>
for helping test multiple iterations of mod_proxy with IIS
servers.
<VirtualHost>, <Global>
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:
client
This policy indicates that mod_proxy will use whatever
the connected client uses. Thus if the client sends PORT,
mod_proxy will send PORT to the
backend/destination server.
This is the recommended policy in most cases.
active
Regardless of the commands sent by the client, mod_proxy
will use only active data transfers (i.e. using
PORT commands) with the backend/destination server.
passive
Regardless of the commands sent by the client, mod_proxy
will use only passive data transfers (i.e. using
PASV commands) with the backend/destination server.
PASV
Regardless of the commands sent by the client, mod_proxy
will use only PASV commands with the backend/destination
server.
PORT
Regardless of the commands sent by the client, mod_proxy
will use only PORT commands with the backend/destination
server.
EPSV
Regardless of the commands sent by the client, mod_proxy
will use only EPSV commands with the backend/destination
server.
EPRT
Regardless of the commands sent by the client, mod_proxy
will use only EPRT commands with the backend/destination
server.
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>
<VirtualHost>, <Global>
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:
client
This policy indicates that mod_proxy will use whatever
the connected client uses. Thus if the client sends MLSD,
mod_proxy will send MLSD to the
backend/destination server.
This is the recommended policy in most cases.
LIST
This policy instructs mod_proxy to use the LIST
command with the backend/destination server, regardless of the command
used by the client. The mod_proxy module then handles any
reformatting of the LIST response into the response needed
by the client. For example, if the client sends MLSD but the
backend/destination server does not support this command,
mod_proxy will send LIST instead, and translate
the backend format into the client-requested format.
The current implementation of this policy handles LIST-<MLSD
translations only.
UseSlink
Use this option to have mod_proxy use the broken
"OS.unix=slink" syntax, preferred by FTP clients such as FileZilla, for
indicating symlinks, rather than the more correct "OS.unix=symlink"
syntax. See
Bug#3318 for
a more detailed discussion.
<VirtualHost>, <Global>
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.
<Class>
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/8This 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
<VirtualHost>, <Global>
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:
proxyuser,user@host
This method indicates that proxy authentication is required. The
client first authenticates to the proxy via USER/PASS commands:
USER proxy-user PASS proxy-passwdThen the client authenticates again, this time including the address (and optionally port) of the destination server as part of the second
USER command:
USER real-user@ftp.example.com PASS real-passwdThe
mod_proxy module will remove the destination address
portion of the second USER command before proxying it to
the destination server.
proxyuser@host,user
This method indicates that proxy authentication is required. The
client first authenticates to the proxy via USER/PASS commands;
note that the destination address (and optionally port) is included as part
of the first USER command:
USER proxy-user@ftp.example.com PASS proxy-passwdThen the client authenticates again, this time sending the
USER/PASS commands to authenticate to the destination server:
USER real-user PASS real-passwd
user@host
This methods indicates that no proxy authentication is used. The
client indicates the destination address (and optionally port) of the
server as part of the USER command:
USER real-user@ftp.example.com PASS real-passwdThe
mod_proxy module will remove the destination address
portion of the USER command before proxying it to the
destination server.
user@sni
This methods indicates that no proxy authentication is used. The client indicates the destination address (and optionally port) of the server as part of a TLS SNI (Server Name Indication) portion of a TLS session:
AUTH TLS handshake with SNI USER real-user PASS real-passwd
Configuring the FTP client's proxy settings to match the above methods varies greatly, depending on the FTP client.
<VirtualHost>, <Global>
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$
<VirtualHost>, <Global>
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.
<VirtualHost>, <Global>
The ProxyOptions directive is used to configure various optional
behavior of mod_proxy. For example:
ProxyOptions UseProxyProtocolV1
The currently implemented options are:
ShowFeatures
When reverse proxying, mod_proxy defaults to not responding to
the FTP FEAT command, which is used to determine the supported
features/capabilities of the FTP server; this is done to prevent leaking
of information about internal FTP servers to the outside world. However,
some clients rely on the FEAT data. For such clients/use
cases, use this option to tell mod_proxy to proxy the
FEAT command/response to the backend server.
UseDirectDataTransfers
The mod_proxy module will, by default, proxy all data transfers
through the proxy server. Some sites may wish to have the FTP data
transfers occur directly between the frontend client and the backend server,
to avoid the latency/overhead of the proxying. Use this option to
enable these direct data transfers (akin to Direct Server
Return, or DSR), for both forward and reverse proxy roles:
# Enable data transfers directly from frontend client to/from backend server
ProxyOptions UseDirectDataTransfers
UseProxyProtocolV1
When mod_proxy connects to the backend/destination server,
use the PROXY V1 protocol, sending the human-readable PROXY
command to the destination server. This allows backend servers to implement
access controls/logging, based on the IP address of the connecting client.
The mod_proxy_protocol
ProFTPD module can be used to handle the PROXY command on
the receiving side, i.e. when using proftpd as the
backend/destination server.
Note: do not use this option unless the backend server
does support the PROXY V1 protocol. Otherwise, the
PROXY protocol message will only confuse the backend server,
possibly leading to connection/login failures.
UseProxyProtocolV2
When mod_proxy connects to the backend/destination server,
use the PROXY V2 protocol, sending a binary-encoded "PROXY" command
to the destination server. This allows backend servers to implement
access controls/logging, based on the IP address of the connecting client.
The mod_proxy_protocol
ProFTPD module can be used to handle the "PROXY" command on the receiving
side, i.e. when using proftpd as the
backend/destination server.
Note: do not use this option unless the backend server
does support the PROXY V2 protocol. Otherwise, the
"PROXY" protocol message will only confuse the backend server, possibly
leading to connection/login failures.
UseProxyProtocolV2TLVs
When mod_proxy is configured to use the PROXY protocol V2,
via the UseProxyProtocolV2 option, this option tells
mod_proxy to send additional data as Type/Length/Value (TLV).
These TLVs include:
mod_unique_id is present/used)
Note: use of the UseProxyProtocolV2 option is also
required for the TLVs to be sent.
UseReverseProxyAuth
When reverse proxying, mod_proxy delegates user authentication
to the selected backend server. However, there are some sites which need
to centralize user authentication in the proxy; use this option to require
proxy authentication for such cases. Note that this option
only pertains to reverse proxy connections; proxy authentication
when forward proxying is determined by the ProxyForwardMethod
directive.
<VirtualHost>, <Global>
The ProxyRetryCount directive configures the number of times
mod_proxy will attempt to connect to the backend/destination
server. The default is 5 attempts.
<VirtualHost>, <Global>
The ProxyReverseConnectPolicy directive configures the
policy that mod_proxy will use for selecting the backend
server when reverse proxying.
The currently supported policies are:
LeastConns
Select the backend server with the lowest number of proxied connections.
LeastResponseTime
Select the backend server with the least response time; this is determined based on the connect time to the backend server, and its number of current connections.
PerGroup
Select a backend server based on the primary group of the authenticated
USER name used by the connecting client; any future
connections using that same USER name will be routed to the
same backend server.
Note: use of this ProxyReverseConnectPolicy also
requires use of the UseReverseProxyAuth
ProxyOption, as authenticating the given USER
name is required for discovering the primary group of that user.
PerHost
Select a backend server based on the IP address of the connecting client; any future connections from that IP address will be routed to the same backend server.
PerUser
Select a backend server based on the USER name used by the
connecting client; any future connections using that same USER
name will be routed to the same backend server.
Random
Randomly select any of the backend servers.
RoundRobin
Select the next backend server in the list.
Shuffle
Similar to the Random policy, except the selection happens
from the not-yet-chosen backend servers. This means that all
backend servers will eventually be used evenly, just in a random order.
<VirtualHost>, <Global>
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:990And 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.orgThese
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 permittedIn 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.
<VirtualHost>, <Global>
The ProxyRole directive configures whether mod_proxy
will perform forward or reverse proxying. The list of supported roles
are thus:
forward
Perform forward proxying.
reverse
Perform reverse proxying.
Note that the ProxyRole directive is required
for mod_proxy to function. If this directive is not configured,
connections to mod_proxy will fail.
<VirtualHost>, <Global>
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:
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.
<VirtualHost>, <Global>
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.
<VirtualHost>, <Global>
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:
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.
<VirtualHost>, <Global>
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.
<VirtualHost>, <Global>
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:
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.
<VirtualHost>, <Global>
The ProxySFTPOptions directive is used to configure various
optional SSH-specific behavior of mod_proxy.
For example:
ProxySFTPOptions AllowWeakDH
The currently implemented options are:
AllowWeakDH
The mod_proxy module will not use Diffie-Hellman groups of less
than 2048 bits, due to weaknesses
that can downgrade the security of an SSH session. If for any reason
your SFTP/SCP servers require smaller Diffie-Hellman groups, then
use this option.
NoExtensionNegotiation
By default, mod_proxy will offer/support the SSH extension
negotiation, defined by
RFC 8308. Use this
option to disable support for extension negotiations.
NoHostkeyRotation
By default, mod_proxy will offer/support the OpenSSH
hostkey rotation extensions, "hostkeys-00@openssh.com" and
"hostkeys-prove-00@openssh.com". Use this option to disable support for
these custom OpenSSH extensions.
NoStrictKex
By default, mod_proxy will honor/support the OpenSSH
"strict KEX" mode extension, "kex-strict-c-v00@openssh.com" and
"kex-strict-s-v00@openssh.com". Use this option to disable support for
these custom OpenSSH extensions.
OldProtocolCompat
Older servers identity their protocol versions as "1.99", rather than as
"2.0". By default, mod_proxy will refuse to handle connections
to such servers. To enable compatibility with these servers (which
tend to be derived from ssh.com/Tectia code), use this option.
Note that this option automatically enables the
PessimisticKexinit ProxySFTPOption as well.
PessimisticKexinit
As described here, the mod_proxy
module tries to reduce the connection latency by optimistically sending
the KEXINIT key exchange message. However, some SSH servers
cannot handle this behavior. Use this option to disable the optimistic
sending of the KEXINIT message.
<VirtualHost>, <Global>
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 filewhere
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
<VirtualHost>, <Global>
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 15will cause an unresponsive server to be disconnected after approximately 45 seconds.
<VirtualHost>, <Global>
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:
<VirtualHost>, <Global>
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.
<VirtualHost>, <Global>
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.
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.
<VirtualHost>, <Global>
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
<VirtualHost>, <Global>
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.
<VirtualHost>, <Global>
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
<VirtualHost>, <Global>
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/
<VirtualHost>, <Global>
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
<VirtualHost>, <Global>
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/
<VirtualHost>, <Global>
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
<VirtualHost>, <Global>
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.
<VirtualHost>, <Global>
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
<VirtualHost>, <Global>
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:
Use of SSL/TLS is required; backend servers which do not support SSL/TLS or which fail the SSL/TLS handshake will cause the proxied session to be closed.
Use of SSL/TLS is disabled; backend servers which do support SSL/TLS will be ignored, and only FTP will be used.
Use of SSL/TLS will be automatically used if the backend server
supports SSL/TLS (via AUTH TLS in its FEAT
response). If the SSL/TLS handshake fails, the backend connection will
proceed using plain FTP.
Note: this is the default behavior in mod_proxy.
Use of SSL/TLS to the backend server will attempt to match the SSL/TLS usage of the frontend client. Thus if the frontend client uses explicit FTPS, then explicit FTPS will be attempted with the backend; similarly for implicit FTPS. And if the frontent client does not use FTPS, then SSL/TLS will not be used for the backend connection.
<VirtualHost>, <Global>
The ProxyTLSOptions directive is used to configure various
optional SSL/TLS behavior of mod_proxy.
Example:
ProxyTLSOptions EnableDiags
The currently implemented options are:
AllowWeakSecurity
Sets the cryptographic security level to "zero", meaning that any/all ciphers and key sizes are permitted. This option allows for the best interoperability with any FTPS server, but is not recommended. Use only when necessary.
EnableDiags
Sets callbacks in the OpenSSL library such that a lot of
SSL/TLS protcol information is logged to the
ProxyLog file. This option is
very useful when debugging strange interactions with FTPS servers.
NoSessionCache
By default, when using SSL/TLS, mod_proxy will cache
the negotiated SSL sessions in its local database, for reuse in enabling
SSL session resumption in future connections to those hosts. Use this
option to disable use of session caching if/when needed.
NoSessionTickets
By default, when using SSL/TLS, mod_proxy will cache
any session tickets
offered by the server in its local database, for reuse in enabling
SSL session resumption in future connections to those hosts. Use this
option to disable use of session tickets if/when needed.
<VirtualHost>, <Global>
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.keyThe 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 -hexNote 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
<VirtualHost>, <Global>
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 -SSLv3Using 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.
<VirtualHost>, <Global>
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.
<VirtualHost>, <Global>
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:
client
This policy indicates that mod_proxy will use whatever
the connected client uses. Thus if the client sends PROT C,
mod_proxy will send PROT C to the
backend/destination server.
required
Regardless of the commands sent by the client, mod_proxy
will use only protected TLS data transfers (i.e. using
PROT P commands) with the backend/destination server.
This is the recommended policy in most cases.
clear
Regardless of the commands sent by the client, mod_proxy
will use only clear (i.e. unprotected) data
transfers (i.e. using PROT C commands) with the
backend/destination server.
<VirtualHost>, <Global>
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.
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:
mod_tls) for FTP servers which do not support FTPS
TransferLog, ExtendedLog, etc) for FTP servers which do not provide such versatile logging
mod_snmp) for FTP servers which do not have such features
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:
LeastConns
Random
RoundRobin
Shuffle
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:
PerGroup
PerHost
PerUser
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.cWhy 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 serverEach 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:20This 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:
%{note:mod_proxy.backend-ip}: IP address of the backend/proxied server
%{note:mod_proxy.backend-port}: Port of the backend/proxied server
%{note:mod_proxy.backend-url}: URL to the backend/proxied server
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/proxymay 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:
MODE Z support
See the GitHub issues page for current bugs and feature requests, and to report issues.
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.
ProxyReverseConnectPolicy PerHostand would like to configure different pools of backend servers for different incoming clients. How do I do this?
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?
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,useror 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.
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.gzafter 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 installNote:
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.