— Article — № 005

005 —Tooling

FTP is not dead: when SFTP is overkill and FTPS is just right

A Friday hotfix on a Magento 1 site, no SSH, no port 22 open, and the question gets suddenly real. SFTP is not always the answer, and FTPS is not the compromise it gets framed as.

Brass weighing scale on bone-coloured paper, one pan empty, the other holding an envelope sealed with red wax.
Hero · staged still№ 005

The Friday hotfix scene

A Dutch agency we work with hit this last month. 16:40 on a Friday, a Magento 1 site on a shared Hetzner package, checkout swallowing orders for ninety minutes. The engineer who knew the codebase was on a train, tethered, opening Transmit and watching the spinner. The host offered FTP and FTPS. No SSH. No SFTP. No port 22.

The question was not which protocol is best. The question was which one the box would actually accept and which one a tethered laptop in a tunnel would survive. That is most of the FTP versus FTPS versus SFTP debate, once you strip out the LinkedIn certainty. The protocols solve overlapping problems, the boxes you inherit dictate which problem you actually have, and the wrong default wastes a billable hour.

What SFTP actually buys you

SFTP is not a flavour of FTP. It is the SSH File Transfer Protocol, a separate spec that happens to share three letters. It rides inside an SSH session on port 22, uses a single channel for control and data, and inherits SSH's key authentication, known_hosts pinning, and tunnelling. On any server you fully control, it is the right default.

The catch is “any server you fully control”. A long tail of WordPress, Joomla, and Magento installs lives on packages where the hosting provider does not hand out shell accounts. Some offer SFTP via a forced internal-sftp setup with no shell. Many do not. The legacy site you are paid to keep alive may simply not have port 22 open to you, and asking the host's first-line support to enable it is its own afternoon.

The other catch is that SFTP is chatty over high latency. Every read and write is a request-response over the SSH channel. On a 200ms link with a thousand small files, you feel it. Passive-mode FTP and FTPS can saturate the data channel with a single sustained transfer; SFTP, by design, cannot.

Where FTPS earns its keep

FTPS is FTP plus TLS, standardised in RFC 4217. It comes in two shapes that matter at the firewall.

Explicit FTPS starts on the normal control port 21 in plaintext, then issues AUTH TLS and upgrades. Implicit FTPS starts encrypted from the first byte on port 990. Explicit is what almost every modern shared host actually offers. Implicit is deprecated, but still appears on older Plesk and DirectAdmin boxes.

The case for FTPS is unromantic. Your host already runs vsftpd or Pure-FTPd. The credential database, the chroot rules, the per-user quota, the directory permissions all exist. Turning on TLS is a config flag and a certificate. A typical vsftpd block on the server side looks like this:

listen=YES
ssl_enable=YES
force_local_data_ssl=YES
force_local_logins_ssl=YES
ssl_tlsv1_2=YES
ssl_sslv2=NO
ssl_sslv3=NO
require_ssl_reuse=NO
rsa_cert_file=/etc/ssl/private/vsftpd.pem
rsa_private_key_file=/etc/ssl/private/vsftpd.key
pasv_min_port=40000
pasv_max_port=40100

The pasv_min_port and pasv_max_port pair is the part that bites. FTP and FTPS use a separate data channel that the server picks at random within that range. Your firewall has to allow the range, and your NAT has to know how to translate it. Get it wrong and you see 425 Can't open data connection on every LIST, and the client appears to “connect fine but never list files”. That is not your TLS config; that is the data channel.

From the client side, a quick sanity check is one line of curl:

curl -v --ssl-reqd --user me:secret \
  ftp://ftp.example.com/wp-content/themes/

If that walks the directory, the TLS path is healthy. If it hangs after PASV, the passive range is blocked somewhere between you and the disk.

Active versus passive, briefly

Active FTP, where the server connects back to the client on a data port, is dead for anyone behind NAT, which is everyone. Force passive in the client and force the passive port range on the server. Anything else is a story you tell support at 17:00 on a Friday.

When plain FTP is still defensible

Plain FTP over port 21 sends credentials in clear. On the open internet, that is indefensible. Inside a private VPC, on a build agent dropping artifacts onto an internal mirror that nothing outside the subnet can reach, it is fine and sometimes preferable because the firewall config is one rule and the throughput is unencrypted line speed. We do not recommend it, we have seen it justified twice in five years, and both times the operator could draw the network on a napkin.

If your “FTP” is exposed to the public internet and not wrapped in TLS or SSH, treat it as a P1. The control channel passes the password in cleartext on the first USER/PASS exchange. Anyone on the path sees it.

The decision in two lines

If you control the box, give yourself SFTP and a chrooted user. The Match block below pinned to a group is the minimum:

Match Group sftponly
    ChrootDirectory /var/sftp/%u
    ForceCommand internal-sftp
    AllowTcpForwarding no
    X11Forwarding no
    PasswordAuthentication no

If you do not control the box, and the host already runs FTP, turn on explicit FTPS, pin the passive port range, force TLS 1.2 or 1.3, and stop. FTPS is not a compromise in that scenario. It is the protocol that matches the infrastructure you actually have, and it ships the same bytes through the same TLS that your HTTPS does.

The protocol is not the interesting decision. What is interesting is whether your editor knows the file's version history, whether your save is two clicks from undo, and whether the next person who opens that legacy site a year from now can see who changed what. When we built Pier we ran into this exact thing, roughly a third of the boxes our customers connect to do not have SSH at all. The fix that mattered was not making FTPS faster but making every save reversible with one keystroke, so the protocol underneath stops being the scary part of the job.

The smallest thing you can do today: open your hosting panel, find the FTP user, and check whether TLS is enforced on login. If it is not, flip the toggle. If the panel does not expose the toggle, the support email writes itself.

— Questions —

Is FTPS more secure than SFTP?

Both are strong when configured correctly. The practical question is which one your server actually exposes and whether the passive data port range is reachable from your network.

Does FTPS need a certificate?

Yes. The server needs an X.509 certificate. A Let's Encrypt cert on the FTP service is straightforward; self-signed works if the client trusts it, but it creates warnings every time.

Why does my FTPS client connect but never list files?

Almost always the passive data channel. The control connection on port 21 is fine, but the data ports the server hands back are blocked at a firewall or NAT between you and the host.

Can I run SFTP without giving the user a shell?

Yes. Use a Match block in sshd_config with ForceCommand internal-sftp and ChrootDirectory. The user gets file transfer only, no shell login and no port forwarding.