FTP Load-Balanced through haproxy

By Tait Clarridge, Fri 14 September 2012, Category Linux

ftp, haproxy

I was asked to explore the possibility of having haproxy balance connections between multiple backend FTP servers. Luckily there is a way to do this without having to play with DNAT on the proxy server and instead setting it up with multiple backends in haproxy.

First you will need to setup a few FTP servers. I chose VSFTP (which can be installed on CentOS via "yum install vsftpd")

As far as I know, this will only work properly with ftp passive mode. For that you can make the following vsftpd config

[tait@foxtrot-tango-papa01 ~]$ cat /etc/vsftpd/vsftpd.conf
anonymous_enable=NO
local_enable=YES
write_enable=YES
local_umask=022
dirmessage_enable=YES
xferlog_enable=YES
connect_from_port_20=NO
xferlog_file=/var/log/xferlog
xferlog_std_format=YES
pam_service_name=vsftpd

# This is a user whitelist we use
userlist_enable=YES
userlist_deny=NO
userlist_file=/etc/vsftpd/user_list
tcp_wrappers=YES
pasv_enable=YES
pasv_promiscuous=NO
port_enable=YES
port_promiscious=NO

# Added listen address for internal only
listen=YES
# If you use this method, change the listen_address for each server (duh)
listen_address=10.0.0.10

# These are the ports to use for PASV mode
# It is important that these port numbers are unique across each of your backend servers
pasv_min_port=10000
pasv_max_port=10250

So basically for each server you should be creating a new port range to use with passive ftp. My configuration has the following:

foxtrot-tango-papa01: 10001 -> 10250 foxtrot-tango-papa02: 10251 -> 10500 foxtrot-tango-papa03: 10501 -> 10750

Ensure that your configuration works on each node and try sample ftp connections to each of your servers before we proceed to configuring and using haproxy for the frontend.

Download and install haproxy, you can either do this by source or through a 3rd party repository.

This is what my config (very basic) looks like.

[tait@ftp-proxy01]$ cat /etc/haproxy/haproxy.cfg
# HAPROXY Config for FTP
# my apologies for the spacing
global
    log 127.0.0.1 local0 info
    chroot /var/lib/haproxy
    user haproxy
    group haproxy
    maxconn 2000

defaults
    log global
    mode tcp
    option tcplog
    retries 3

# This is for the initial connection and control traffic
frontend foxtrot-tango-papa-control
    bind *:21
    default_backend ftp_server_pool

# Each of these frontends represent a server and its corresponding PASV ports we set
frontend foxtrot-tango-papa01
    bind *:10001-10250
    default_backend foxtrot_tango_papa01

frontend foxtrot-tango-papa02
    bind *:10251-10500
    default_backend foxtrot_tango_papa02

frontend foxtrot-tango-papa03
    bind *:10501-10750
    default_backend foxtrot_tango_papa03

# Global backend for the ftp control traffic to find a server
backend ftp_server_pool
    server foxtrot-tango-papa01 10.0.0.10 check port 21 inter 10s rise 1 fall 2
    server foxtrot-tango-papa02 10.0.0.11 check port 21 inter 10s rise 1 fall 2
    server foxtrot-tango-papa03 10.0.0.12 check port 21 inter 10s rise 1 fall 2

# Backends for each of our FTP servers
backend foxtrot_tango_papa01
    server foxtrot-tango-papa01 10.0.0.10 check port 21 inter 10s rise 1 fall 2

backend foxtrot_tango_papa02
    server foxtrot-tango-papa02 10.0.0.11 check port 21 inter 10s rise 1 fall 2

backend foxtrot_tango_papa03
    server foxtrot-tango-papa03 10.0.0.12 check port 21 inter 10s rise 1 fall 2

Now you should be able to start haproxy (ignore warnings or take care of them as you need to... like I said, very basic config) and ftp to it.

Be warned, this configuration makes haproxy bind to EVERY passive port listed, but you should be able to ftp to the haproxy IP and transfer files to and from your FTP server pool.

Leave a comment if you require any help, but as a basic config this should work.