Clustering recommendations
There are many ways to run a cluster of self-hosted instances. This page is the decision guide: which implementations fit which protocols, and what each one trades away. The examples reference AWS services, but every other cloud has equivalents.
Two things this page does not cover:
- How to configure each setup - the
-publicipflag, DNS records and sticky sessions are covered step by step in Load balancing. - Network appliances (F5, NetScaler and friends) that ship their own FTP-aware proxying - if you have one, use its tooling.
Start with the protocol decision
A self-hosted instance is three servers bundled into one process:
- SFTP server (port 22)
- FTP + explicit FTPS server (port 21)
- Implicit FTPS server (port 990)
Decide first whether your users need SFTP only, FTP/FTPS only, or both - some implementations work well for SFTP but cannot carry FTP at all.
The difference comes from the protocols themselves. SFTP runs over a single SSH connection, which any TCP load balancer can carry. FTP uses multiple connections per session: the client authenticates on the control connection, and each listing or transfer opens a new data connection to a passive port - and both must reach the same server. (More background: Passive vs active FTP.)
What you are trading off
No implementation wins everywhere. Weigh each against:
- Downtime window when an instance fails
- Load-balancing precision - how evenly load actually spreads
- SFTP client support
- FTP client support
- Implementation cost
- Scalability - how easily the cluster grows and shrinks
Which implementations fit your protocols
| You need | Workable implementations |
|---|---|
| SFTP only (port 22) | DNS round robin · network load balancer (plain) |
| FTP/FTPS only (ports 21/990) | DNS round robin · NLB for initial connections · NLB with sticky IPs |
| Both | The FTP row - each of those carries SFTP too; just open port 22 alongside the FTP ports |
The one combination to avoid: a plain network load balancer (no sticky IPs) in front of FTP - data connections land on the wrong server and transfers fail.
DNS round robin with healthchecks
Run each instance with its own static IP address and put them all in one DNS record with a low TTL (10-60 seconds). A DNS healthcheck (Route 53 or similar, TCP probing each instance) removes a failed instance's record so new clients stop landing on it.
Clients resolve the name and talk directly to one server for every connection - which is exactly why this works for FTP: control and data connections naturally reach the same instance.
| Outcome | Rating |
|---|---|
| Downtime window on failure | Medium to low - clients ride out the DNS TTL before reaching a healthy server |
| Load-balancing precision | Medium to low - DNS answers are random, not load-aware |
| SFTP client support | High |
| FTP client support | High |
| Implementation cost | Low |
| Scalability | High to medium - works in an auto-scaling group with some scripting to manage the records |
Network load balancer (plain)
An HTTP load balancer will not carry raw TCP, but a network load balancer will. It gives your users one stable IP; every connection is routed to a backend instance and all data flows through that long-lived connection.
SFTP only. Without sticky sessions an FTP data connection can land on a different instance than its control connection.
| Outcome | Rating |
|---|---|
| Downtime window on failure | Low - the NLB stops routing to a dead instance immediately |
| Load-balancing precision | High |
| SFTP client support | High |
| FTP client support | Not supported |
| Implementation cost | Low to medium |
| Scalability | High - auto-scaling groups plug straight in |
Network load balancer with sticky IPs
The same NLB, with stickiness by client IP: one client always reaches the same backend instance, so FTP control and data connections line up.
| Outcome | Rating |
|---|---|
| Downtime window on failure | Low to medium - routing heals immediately, but in-flight FTP sessions on the dead instance must reconnect |
| Load-balancing precision | Medium to low - sticky IPs mean some instances accumulate more load over time |
| SFTP client support | High |
| FTP client support | High |
| Implementation cost | Low to medium |
| Scalability | High |
Network load balancer for initial connections
The NLB carries only the control connection; passive data connections go
directly to the instance's own public IP. The instance advertises its own
address in the passive response (the -publicip flag - see
Load balancing):
1.1.1.1 (load balancer IP)
/ \
2.2.2.1 (server 1) 2.2.2.2 (server 2)
The client connects and authenticates via 1.1.1.1, requests a file, and the
server answers "connect to 2.2.2.1:50001 for the data" - the client fetches
the file directly from the instance that holds its session.
| Outcome | Rating |
|---|---|
| Downtime window on failure | Low - the NLB stops routing to a dead instance immediately |
| Load-balancing precision | High |
| SFTP client support | High |
| FTP client support | High to medium - a few clients refuse a data IP that differs from the control IP |
| Implementation cost | Low to medium |
| Scalability | High |
That last row is the trade: it is the most precise FTP-capable setup, but ageing FTP clients that insist the data connection go to the same address as the control connection cannot use it.
What DocEvent itself runs
Our cloud clusters run Dockerized in AWS ECS behind a mix of NLB for initial connections and DNS round robin:
- The NLB gives customers a stable static IP for connections and lets us scale out as demand rises; passive data connections go directly to the instances' own addresses.
- For customers whose older FTP clients cannot handle separate connection and data addresses, we also publish a round-robin DNS hostname that goes straight to the instances.
That split is visible in the static IP addresses page: the "connection" addresses are the balancer, the "data" addresses are the instances.
Unsure which fits your network? Ask us - this is a conversation we have often.