Why ftp Still Ships in Your Linux Box (And What It’s For in 2026)
Try which ftp on a fresh Debian 12 install. It’s there. Ask why — and you’ll get the same short answer every sysadmin gives:
“It’s shipped because /usr/bin/ftp(1) is in POSIX. Nobody actually uses it anymore. We use SSH for everything.”
That’s almost right. Almost. Because if you ever plug in an old NAS, talk to an embedded industrial controller, or sit behind a corporate proxy that only allows legacy protocols, you’ll run into ftp one way or another. And when you do, the man page is unforgiving.
Here’s what ftp(1) is actually for, what it’s bad at, and where you should use something else.
What ftp Actually Is
ftp is a portable file transfer client built on the FTP protocol (RFC 959, originally 1985). It supports two transfer modes — ASCII and binary — over two channels of communication, and it speaks in plain text on both of them.
Two things make FTP a problem in 2026:
- No encryption. Every byte — your username, your password, your file contents — is on the wire in cleartext. Anyone with packet capture on the network has your credentials.
- Two connection model that confuses NAT and firewalls. FTP opens one connection for commands and a separate connection for each data transfer. Modern network edges (NAT, stateful firewalls, cloud load balancers) handle this very badly. It’s why we say “FTP breaks the moment it crosses a router.”
So why does it still ship?
Because some devices only do FTP. Old backup appliances, medical equipment, CNC controllers, IPMI firmware updaters, cheap IP cameras — they expose FTP and only FTP. When you have to talk to them, you open your terminal and run ftp.
The Two Connection Model (the bit that trips everyone up)
FTP uses port 21 for commands (the control channel) and then opens a separate ephemeral port for each file transfer (the data channel). The two modes differ in how that data port gets opened:
Active mode is the older style. The server connects back to the client on a high port for data transfer. This works in 1990 when both sides were directly addressable on the open internet. In 2026, the client’s high port is behind NAT, so the connection simply fails. You’ll see 425 Can't open data connection and wonder what happened.
Passive mode (the default in modern clients) is the fix. The server says to the client “connect to me on this port” and the client initiates the connection. The data flow goes outbound from the client’s perspective — same direction as the command channel — so NAT works fine.
You toggle it inside ftp(1):
ftp> passive
Passive mode on.
ftp> passive
Passive mode off.If you’re stuck behind a corporate firewall that aggressively blocks outbound connections, passive is your friend. If you’re behind a NAT that’s strict about connection tracking, passive is still probably your friend — try it first.
Active mode has essentially one legitimate use in 2026: debugging old FTP daemons that don’t support PASV. Skip it otherwise.
Connecting and Authenticating
The straightforward case:
$ ftp 192.168.1.100
Connected to 192.168.1.100.
220 (vsFTPd 3.0.5)
Name (192.168.1.100:you): your_user
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
ftp>That ftp> prompt is the gateway to a small interpreter. You get one command per line. You can pipe commands in via stdin; this is the trick that makes ftp scriptable.
Anonymous servers (public mirrors, distro ISO sites, archives) accept the username anonymous and any password (conventionally your email address, but no server actually validates it):
$ ftp ftp.kernel.org
Name: anonymous
Password: guest@example.comSome modern sites reject this. Debian disabled anonymous FTP entirely in 2017. So did Red Hat. If you’re maintaining an FTP server in 2026, anonymous probably isn’t a fit for most use cases; if you’re a client, you mostly won’t see it.
The Eight Commands You’ll Actually Use
Modern ftp(1) has around 60 commands, of which you actually need eight. The rest is vim-style verbosity that mostly only old admins remember.
| Command | What it does |
|---|---|
ls / cd |
List directory / change directory on remote |
lcd |
Change directory on local machine |
get <file> |
Download one file |
put <file> |
Upload one file |
mget <glob> |
Download files matching a pattern |
mput <glob> |
Upload files matching a pattern |
binary |
Switch transfer mode to binary (8-bit clean — for compressed files, executables, images) |
prompt |
Toggle confirmation for mget/mput (set prompt off to skip asking) |
delete <remote> |
Delete file on remote |
bye |
Quit |
mget and mput glob through shell expansion on the remote side. The classic gotcha: a Chinese user’s mugshot comment on mget *.pdf returning NLST doesn't support wildcard — that’s because the server’s NLST command (the ftp equivalent of ls) doesn’t do globs. You need a server that supports the more capable MLSD, or you fetch ls /path/ first, manually pick the filenames, and feed them back.
ASCII mode is the default and it lies to you. ASCII mode will mangle binary files (PDFs, .tar.gz, anything compressed) — there’s a famous class of bug where a downloaded tarball is “only slightly corrupt” because line endings got translated. Run binary before any transfer of compressed files, executables, or images. Run it once per session. The cost is zero.
What To Use Instead
The honest list:
- For anything sensitive:
sftp. SFTP is the SSH-based file transfer protocol. All traffic is encrypted. Username/password go over the encrypted channel. Server identification is via SSH host keys. If your target has SSH at all, use SFTP. Tools:sftp(OpenSSH),lftp, Nautilus, Cyberduck. - For local-to-local copying:
scporrsync. scp is fine for a one-shot copy. rsync is the right answer for anything you might run twice — it does delta transfer and survives interrupts. - For automation that needs to “look like FTP” to a legacy endpoint:
curl ftp://works.wget ftp://works.lftpis the best when you need scripting — its scripting syntax is several light-years ahead of ftp(1). - If you’re starting a new server: don’t run FTP. Run SFTP via OpenSSH daemon, or
lftpserver, or SMB if your clients are Windows. The number of FTP daemons in production that genuinely cannot be replaced by SFTP is small and shrinking.
The FAQ that brought you here — “I just want to grab one file from this ancient device” — usually ends with running ftp(1), picking binary mode, get-ing the file, and bye-ing out, all in two minutes. Fine for that. Not fine for anything else.
When ftp(1) Is Actually Fine
Symmetric counter-examples where ftp(1) still earns its keep:
- Pulling firmware blobs from a vendor’s FTP-only update server. Some embedded vendors still ship updates that way; you turn ftp loose, grab the .bin, exit.
- Testing an FTP-only network share. When you’re debugging someone else’s infrastructure and the gear only does FTP, ftp(1) is a perfectly good diagnostic client.
- Recovering from “OpenSSL is broken” days where SSH and even TLS libraries were broken for months. ftp’s plain-text simplicity means it kept working when crypto libraries were on fire. (This happened. It will happen again.)
- Interacting with industrial CNC, lab equipment, or medical imaging gear. The protocol stack on those is rarely updated. They will speak FTP for the rest of their operational life.
In each of those cases, the meta-advice is the same: do it once, get your file, and disconnect. Don’t make it part of your daily workflow.
Hardening: If You Really Must Run an FTP Server
Three dos and three don’ts.
Do:
- Use
vsftpdor ProFTPd, not the ancientwu-ftpd. Patched recently enough to handle today’s internet. - Run it on a non-default port if you’re paranoid. Doesn’t really help against a determined attacker but reduces drive-by scans.
- Force chroot’d local users if your client base is fixed. Stops users from browsing outside their home directory.
Don’t:
- Don’t send credentials over plain FTP without TLS. If you must expose FTP, at least demand FTPS (FTP-over-TLS, RFC 4217) — same protocol, but with a TLS wrapper on the control channel. Every modern FTP server supports it, and clients like
lftpmake FTPS one config line. - Don’t run it with anonymous mode unless the data is genuinely meant to be public. Old config templates enable anonymous by default; turn it off if you don’t need it.
- Don’t expose FTP to the internet. If you must expose file transfer, expose FTPS or SFTP. FTP will be brute-forced within hours of being public.
Closing
ftp(1) is a tool that exists, has a place, and should not be your default. Open your terminal, type ftp once, get what you came for, type bye. Move on with your life.
If you find yourself reaching for it daily, that’s a signal your infrastructure is a decade behind — and the fix is protocol migration, not better FTP arguments.
Resources:
Comments