Can I load balance FTP; what happens to the data channel?
Short answer
Yes, with passive FTP. FTP uses two connections: the control channel (21) for commands and a separate data channel for file transfer. TR7 does not read or rewrite FTP commands; for this reason, the control port and the server's passive data port range are published together in the same vService, and the two connections of the same client are sent to the same server with persistence: in an L7 TCP vService, the range is written in the frontend Port field, Use Frontend Port is turned on in the Backend Service and Hash persistence is selected; in a Network vService, Port Range and L4 Persistence are turned on. On the FTP server, the passive port range is fixed and the address announced in the PASV response is set to the vService address. Active FTP is not recommended.
Problem: Why Does the Data Channel Break?
In passive FTP, the client first connects to port 21; the server announces an IP address and a data port with the PASV response, and the client opens a second connection to this address. Two problems arise: if the server announces its own internal IP, the client cannot establish the data connection; if the data connection lands on a different server than the control connection, that server does not recognize this transfer. Since TR7 does not rewrite the PASV and PORT commands, these two conditions are met with the server and vService configuration.
Solution: Two Methods
In both methods, the FTP server is prepared in the same way (the panel below); the difference is the vService type.
| Your situation | Suitable method |
|---|---|
| The health check result should be reflected in the distribution; rules and TCP Logs should be used | Method 1: L7 TCP vService |
| Packet-level distribution is enough; the health check result not being reflected in the distribution is acceptable | Method 2: Network vService, Port range |
vsftpd is used in the example; the vService address is written in place of 203.0.113.80, and the range to be published in the vService in place of 50000-50100. The settings are added to the vsftpd configuration file (vsftpd.conf) and the service is restarted (vsftpd.conf). On other FTP servers, the same two settings (passive range, the address announced in PASV) are made with their own configuration names.
pasv_enable=YES
pasv_min_port=50000
pasv_max_port=50100
pasv_address=203.0.113.80The same range on every server
All FTP servers use the same passive range; TR7 sends the data connection to the same port on the server.
Method 1: L7 TCP vService Recommended
- How it works 21 and the passive range are listened on in the same vService; each connection goes to the same port on the Backend Service, and Hash persistence keeps the two connections on the same server based on the client IP.
- Where it is opened vService → Frontend 21 and passive range; Backend Service → Use Frontend Port; vService → Details → LB Algorithm → Persistence: Hash
- Requirement A fixed passive port range on the FTP server and a PASV setting that announces the vService address
- vService type L7 TCP
- Backend Service side Required: the passive range and the PASV address are set as in the panel above.
Step-by-Step Configuration
On each FTP server, the passive port range is fixed (e.g. 50000-50100) and the address to be announced in the PASV response is set to the vService's IP (the panel above). This setting is made on the FTP server, not on TR7.
On the Load Balancer → Profiles → Health Checks screen, the Add button is clicked (how to add).
Name is entered, FTP is selected as the Check Type, and the required FTP User and FTP Password fields are filled in.
The Add button at the bottom of the form is clicked.
On the Load Balancer → Backend Services screen, the Add button is clicked (How is a Backend Service added; which information is required?).
Backend Service Name and Address (e.g. 192.0.2.100:21) are entered; in the Health Check field, the profile created in steps 2–4 is selected.
In the Details section of the same form, Use Frontend Port is turned on; in this way, the data connection goes to the same data port on the server.
The Add button (Edit for an existing Backend Service) at the bottom of the form is clicked. Steps 5–8 are repeated for each FTP server.
The Load Balancer → Load Balancer vService List → Add steps are followed; Name is entered and L7 TCP is selected as the Type.
Two rows with the same IP are added to the Frontend table: port 21 / TCP and port 50000-50100 / TCP. The start of the range must be smaller than its end. If the IP is not in the list, it is first added with Network → Interfaces → Actions → Add IP (Why can't I type the Frontend IP manually; what should I do to use an IP that is not in the list (e.g. IPv6) on a vService?).
In the Default Backend Services table, the Backend Services added in steps 5–8 are selected.
The Details switch at the top right of the form is turned on; in the LB Algorithm box, Hash is selected as the Persistence and Client IP Address is selected in the Hash Key field.
The Save button is clicked. In a cluster setup, the change is also transferred to the peer device with the default auto-sync; if Manual Sync Mode is on, it is sent manually with Synchronize.
Verification
curl -v ftp://203.0.113.80/ --user kullanici:parola227 Entering Passive Mode (203,0,113,80,…) · directory listingMethod 2: Network vService, Port Range
- How it works The destination address of the packets arriving at the control and data ports is translated to the Backend Service, and the port is preserved. L4 persistence sends all connections of the same client to the same server.
- Where it is opened vService → Type: Network → Port Range → Details → L4 Persistence
- Requirement The FTP server settings in Method 1; accepting that the health check result will not be reflected in the distribution
- vService type Network (TCP - L4)
- Backend Service side The passive range and the PASV address are set. While port range is on, the LB mode is not applied and traffic is routed through TR7; if no SNAT IP has been selected, the servers' return traffic must pass through TR7.
Step-by-Step Configuration
Steps 1–6 and 8 of Method 1 are applied; since in a Network vService the port the client came to is used instead of the Backend Service's port, Use Frontend Port is not required. The Route Table field of the Backend Services must be the same as the route table of the vService.
The Load Balancer → Load Balancer vService List → Add steps are followed; Name is entered and Network is selected as the Type.
TCP - L4 is selected as the Protocol and the Port Range switch is turned on.
The 21 and 50000-50100 rows with the same IP are added to the Frontend table.
In the Default Backend Services table, the Backend Services are selected. If the return traffic does not pass through TR7, SNAT is selected in the LB Mode field and the SNAT IP is specified; while Port range is on, only the use of the SNAT IP as the source address is applied.
The Details switch at the top right of the form is turned on; in the LB Algorithm box, L4 Persistence is turned on (the duration comes as 5 minutes). The algorithm stays Round-Robin or Weighted Round-Robin.
The Save button is clicked. In a Network vService, each save restarts the vService; the change is made at a low-traffic time. In a cluster setup, the change is also transferred to the peer device with the default auto-sync.
Verification
curl -v ftp://203.0.113.80/ --user kullanici:parolaDirectory listingCommon Mistakes
- Not turning on Use Frontend Port (Method 1). The data connection goes to the server's port 21 and the transfer fails.
- Not turning on persistence. The data connection lands on a different server than the control connection.
- Leaving the PASV address as the server's internal IP. The client cannot establish the data connection; the listing or the download hangs.
- Using active FTP. In active FTP, the server connects to the client itself and TR7 does not manage this connection through the vService; passive FTP is used.
- Relying on the health check in Method 2. While port range is on, the health check result is not reflected in the distribution; a failed server continues to receive connections.
How it is done in the documentation
