Understanding the FTP Protocol
FTP (File Transfer Protocol) is a standard network protocol used to transfer files between a client and a server on a computer network. Built on a client-server model, FTP uses separate control and data connections, making it one of the oldest and most widely used protocols still in operation today. Originally defined in RFC 114 (1971) and refined in RFC 959 (1985), it remains a foundational technology for web hosting, backup systems, and file sharing infrastructures.
How FTP Works: Control and Data Connections
Unlike HTTP which sends requests and responses over a single connection, FTP uses two distinct TCP connections:
- Control Connection (port 21): Handles authentication and commands like
LIST,GET,PUT. This connection stays open throughout the session. - Data Connection (dynamic port): Transfers file data and directory listings. This connection is established and torn down for each transfer.
FTP operates in two modes: Active and Passive. In active mode, the server initiates the data connection back to the client (usually from port 20 to a client-defined port). In passive mode, the client initiates both connections, which works better with firewalls and NAT. The client sends the PASV command to request passive mode, and the server replies with an IP and port number for the data channel.
A typical FTP session sequence looks like this (simplified):
Client: opens control connection to server:21
Server: 220 Welcome to FTP service
Client: USER username
Server: 331 Password required
Client: PASS password
Server: 230 User logged in
Client: PASV
Server: 227 Entering Passive Mode (192,168,1,100,14,42)
Client: connects to data port 14*256+42 = 3626
Client: LIST
Server: 150 Opening data connection
Server: sends directory listing over data connection
Server: 226 Transfer complete
Client: QUIT
Server: 221 Goodbye
Why FTP Matters
🚀 Deploy your AI agent in 10 minutes
Managed Hermes hosting. Zero DevOps. 100M tokens/mo included.
Try it free →Despite its age, FTP remains relevant due to its simplicity, wide support, and efficiency in handling large file transfers. It is deeply embedded in legacy systems, industrial automation, and web hosting control panels. Developers often encounter FTP when building deployment pipelines, backup scripts, or integrating with third-party file repositories.
Legacy and Ubiquity
FTP is supported by nearly every operating system and network library. It has been a backbone for web publishing since the early days of the internet—many shared hosting providers still offer FTP access as the primary way to upload website files. Its command‑response model is easy to automate, making it a natural fit for batch processing and scheduled transfers.
Use Cases: File Transfer, Backup, Web Deployment
- Web deployment – uploading HTML, CSS, JavaScript, and media assets to a remote server.
- Automated backup – pushing database dumps or log archives to a central FTP repository.
- Data exchange – exchanging EDI documents, CSV exports, or binary blobs between business partners.
- Firmware updates – distributing firmware images to embedded devices that include an FTP client.
How to Use FTP: A Developer's Guide
Connecting to an FTP Server via Command Line
Most operating systems ship with a command-line FTP client. Below is a typical interactive session, demonstrating login, navigation, and file transfer.
# Connect to the server
ftp ftp.example.com
# Login prompts (or use direct command)
ftp> open ftp.example.com
Name: john_doe
Password: ********
230 User john_doe logged in.
# List directory contents
ftp> ls
200 PORT command successful.
150 Opening ASCII mode data connection.
-rw-r--r-- 1 owner group 1024 Apr 01 12:00 readme.txt
drwxr-xr-x 2 owner group 4096 Apr 01 12:00 uploads
226 Transfer complete.
# Change directory and download a file
ftp> cd uploads
ftp> get backup.tar.gz
200 PORT command successful.
150 Opening BINARY mode data connection.
226 Transfer complete. 1048576 bytes sent.
# Upload a file
ftp> put myfile.txt
200 PORT command successful.
150 Opening BINARY mode data connection.
226 Transfer complete. 512 bytes sent.
# Close the connection
ftp> quit
221 Goodbye.
FTP Commands and Responses Reference
The protocol defines over 50 commands. Here are the most commonly used ones for development and scripting:
USER– sends username for authentication.PASS– sends password.PWD– print working directory on the server.CWD– change working directory.LIST/NLST– list directory contents (full vs. simple names).RETR– retrieve (download) a file.STOR– store (upload) a file.DELE– delete a file.RMD/MKD– remove / create directory.PASV– enter passive mode.TYPE– set transfer type:A(ASCII) orI(binary).QUIT– disconnect gracefully.
FTP servers respond with three-digit numeric codes, where the first digit indicates success (2xx), error (5xx), or intermediate status (1xx, 3xx). For example:
230 User logged in. (success)
550 Permission denied. (error)
227 Entering Passive Mode. (ready for data connection)
Using FTP in Python with ftplib
Python’s standard library ftplib provides a robust FTP client. The example below demonstrates connecting, listing files, downloading a binary file, and uploading content—all with passive mode enabled by default (since Python 3.x).
from ftplib import FTP
import os
# Connection parameters
FTP_HOST = "ftp.example.com"
FTP_USER = "john_doe"
FTP_PASS = "secret123"
REMOTE_DIR = "/public_uploads"
LOCAL_FILE = "report.pdf"
UPLOAD_FILE = "newdata.csv"
def perform_ftp_operations():
# Connect and login
ftp = FTP(FTP_HOST)
ftp.login(FTP_USER, FTP_PASS)
# Switch to passive mode (explicit, though default in most implementations)
ftp.set_pasv(True)
# Navigate to remote directory
ftp.cwd(REMOTE_DIR)
# List files and sizes
print("Remote files:")
ftp.retrlines('LIST')
# Download a file in binary mode
with open(LOCAL_FILE, 'wb') as f:
ftp.retrbinary(f'RETR {LOCAL_FILE}', f.write)
print(f"Downloaded {LOCAL_FILE}")
# Upload a file
with open(UPLOAD_FILE, 'rb') as f:
ftp.storbinary(f'STOR {os.path.basename(UPLOAD_FILE)}', f)
print(f"Uploaded {UPLOAD_FILE}")
# Clean disconnect
ftp.quit()
print("Connection closed.")
if __name__ == "__main__":
perform_ftp_operations()
Note: retrbinary and storbinary use binary transfer mode (TYPE I) which is essential for images, archives, and PDFs to avoid corruption. For plain text files, you can use retrlines or storlines.
Active vs Passive Mode in Practice
Active mode requires the client to open a listening port for the data connection and send its IP/port via the PORT command. This often fails when the client is behind a firewall or NAT. Passive mode (PASV) flips the direction: the server opens a port and shares it with the client, which then connects. Most modern clients default to passive mode.
To force passive mode in the command-line client, you usually just issue passive before any transfer. In Python, you can call ftp.set_pasv(True). If you encounter timeouts or "Cannot connect to data connection" errors, switching to passive mode almost always resolves them.
Secure Alternatives: FTPS and SFTP
Plain FTP transmits credentials and data in cleartext, making it unsuitable for sensitive information over untrusted networks. Two secure alternatives exist:
- FTPS (FTP Secure) – adds TLS/SSL encryption to the FTP control and data channels. It uses the
AUTH TLScommand and typically runs over port 990 (implicit) or port 21 (explicit). - SFTP (SSH File Transfer Protocol) – completely different protocol based on SSH, running on port 22. It encrypts both authentication and data, and supports advanced features like resuming transfers and file permissions.
When security is a requirement, prefer SFTP or FTPS. However, for internal networks, legacy systems, or anonymous public archives, standard FTP is still widely employed.
Best Practices for FTP Development
- Always use passive mode – it simplifies firewall traversal and avoids connection issues in NATed environments.
- Set binary transfer type explicitly – prevent corruption of non-text files by sending
TYPE IbeforeRETRorSTOR. - Handle connection errors gracefully – implement retries with exponential backoff for transient network failures.
- Close connections explicitly – call
quit()instead of relying on garbage collection; it sends the proper shutdown sequence. - Never hard-code credentials – use environment variables, configuration files, or secret management services.
- Validate server responses – check numeric codes to distinguish between “file not found” (550) and “permission denied” (553).
- Use secure channels for sensitive data – upgrade to FTPS or SFTP when handling personal information, financial data, or credentials.
- Limit anonymous access – if you run an FTP server, disable anonymous write permissions and enforce strong passwords.
- Monitor directory listings – avoid parsing raw LIST output when possible; use
NLSTfor machine-readable file names, or rely on libraries that abstract parsing. - Log and audit transfers – maintain a record of successful and failed transfers for compliance and debugging.
Conclusion
FTP remains a practical, no-frills protocol for moving files across networks. Its dual‑connection design, simple command set, and widespread library support make it easy to integrate into development workflows, automation scripts, and legacy systems. By understanding active/passive modes, choosing binary transfers, handling error codes, and opting for encrypted alternatives when needed, you can build reliable and secure file transfer solutions. This reference guide equips you with both the conceptual foundation and the hands‑on code examples to work with FTP confidently in any modern development environment.