Registry / http-networking / pyftpdlib

pyftpdlib

JSON →
library2.2.0pypypi✓ verified 87d ago

pyftpdlib is a very fast, scalable, and asynchronous Python FTP server library. It provides a high-level portable interface to easily write efficient FTP servers, being the most complete RFC-959 FTP server implementation available for Python. It supports FTPS (RFC-4217), IPv6 (RFC-2428), Unicode filenames (RFC-2640), and virtual users. The library is currently at version 2.2.0 and actively maintained.

pip install pyftpdlib
INSTALL
IMPORT
SIG · PYFTPDLIB
P
pyftpdlib
http-networkingpythonv2.2.0
Install
3.3s avg
Import
19ms
Disk
17MB
Pass rate
10/ 10
Env Coverage10 / 10
glibc
3.93.13
musl
3.93.13
Install & Compatibility
Where this runs
tested against v2.2.0 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
musl
py 3.103.920 runs
installs and imports cleanly · install 0.0s · import 0.017s · 18.4MB
glibc
py 3.103.920 runs
installs and imports cleanly · install 3.3s · import 0.013s · 19MB
17MB installed
● package 17MB
Code
Verified usage

Verified import paths — ran on the pinned version, not inferred.

DummyAuthorizer
from pyftpdlib.authorizers import DummyAuthorizer
FTPHandler
from pyftpdlib.handlers import FTPHandler
FTPServer
from pyftpdlib.servers import FTPServer
TLS_FTPHandler
from pyftpdlib.handlers import TLS_FTPHandler
Used for FTPS (FTP over TLS/SSL) servers, requires PyOpenSSL.
ThreadedFTPServer
from pyftpdlib.servers import ThreadedFTPServer
For a multi-threaded concurrency model, if the default async model is not suitable.

This quickstart sets up a basic FTP server with a virtual user (configurable via environment variables FTP_USER, FTP_PASS, FTP_HOME) and an anonymous read-only user. It listens on port 2121, sets connection limits, and configures basic logging. Remember to set `FTP_HOME` to a directory you wish to share, and `FTP_USER`/`FTP_PASS` for authenticated access.

import os import logging from pyftpdlib.authorizers import DummyAuthorizer from pyftpdlib.handlers import FTPHandler from pyftpdlib.servers import FTPServer def main(): # Setup a dummy authorizer for managing virtual users authorizer = DummyAuthorizer() # Add a user with read/write permissions ftp_user = os.environ.get('FTP_USER', 'user') ftp_pass = os.environ.get('FTP_PASS', '12345') home_dir = os.environ.get('FTP_HOME', os.getcwd()) authorizer.add_user(ftp_user, ftp_pass, home_dir, perm='elradfmwMT') # Add an anonymous user with read-only permissions authorizer.add_anonymous(home_dir) # Instantiate FTP handler class handler = FTPHandler handler.authorizer = authorizer # Define a customized banner handler.banner = "pyftpdlib based FTP server ready." # Specify a masquerade address and the range of ports for passive connections # Uncomment and configure if behind a NAT # handler.masquerade_address = '151.25.42.11' # handler.passive_ports = range(60000, 65535) # Instantiate FTP server class and listen on all interfaces, port 2121 address = ('', 2121) server = FTPServer(address, handler) # Set limits for connections server.max_cons = 256 server.max_cons_per_ip = 5 # Configure logging logging.basicConfig(level=logging.INFO, format='%(levelname)s:%(name)s:%(message)s') # Start ftp server print(f"Starting FTP server on {address[0] or '0.0.0.0'}:{address[1]} with user '{ftp_user}' and home '{home_dir}'") server.serve_forever() if __name__ == "__main__": main()
pyftpdlib --version
Debug
Known issues
breakingPython 2.7 support has been removed in pyftpdlib 2.0.0. Users requiring Python 2.7 compatibility must install version 1.5.10.
fix
Upgrade to Python 3.6+ or downgrade pyftpdlib to version 1.5.10: `pip install pyftpdlib==1.5.10`.
affects: >=2.0.0
gotchaAs an asynchronous library, pyftpdlib will block the entire server if any long-running, blocking operations (e.g., `time.sleep()`, heavy database queries, slow disk I/O) are executed in the main event loop.
fix
Delegate blocking tasks to separate threads or processes using Python's `threading` or `multiprocessing` modules, or ensure all I/O operations are non-blocking.
affects: All
gotchaWhen the FTP server is behind a Network Address Translator (NAT), clients may fail to establish passive data connections unless `FTPHandler.masquerade_address` and `handler.passive_ports` are explicitly configured.
fix
Set `handler.masquerade_address` to the server's public IP and `handler.passive_ports` to a range of TCP ports for data transfers. Ensure these ports are forwarded by your NAT device.
affects: All
breakingStarting with version 2.0.0, the default SSL/TLS method for `TLS_FTPHandler` was changed from `SSLv23_METHOD` to `TLS_SERVER_METHOD`, disabling older and insecure SSLv2/SSLv3 protocols. This may break compatibility with very old FTP clients.
fix
Ensure clients support TLSv1.0 or newer. If legacy compatibility is critical, review `PyOpenSSL` configuration or consider older `pyftpdlib` versions (not recommended for security).
affects: >=2.0.0
gotchaOn Python 3.14+, `MultiprocessFTPServer` may be broken on POSIX systems (excluding macOS) due to a change in the default `multiprocessing` method from 'fork' to 'forkserver'.
fix
Manually set the `multiprocessing` start method to 'fork' (e.g., `multiprocessing.set_start_method('fork', force=True)`) if using `MultiprocessFTPServer` on affected platforms.
affects: Python >=3.14, pyftpdlib >=2.0.0
Errors
Common errors & fixes
ImportError: cannot import name ftpserver
The `FTPServer` class is imported directly from the top-level `pyftpdlib` package or using a deprecated name, instead of its proper location within the `pyftpdlib.servers` submodule.
fix
Change the import statement to `from pyftpdlib.servers import FTPServer`.
OSError: [Errno 98] Address already in use
The specified port (e.g., 21 or 2121) for the FTP server is already occupied by another process, or a previous server instance did not shut down cleanly, leaving the port in a `TIME_WAIT` state.
fix
Before binding the socket, set the `socket.SO_REUSEADDR` option, choose a different port, or ensure no other process is using the desired port (e.g., using `netstat` to identify and terminate the occupying process). The `socket.SO_REUSEADDR` option can be set on the underlying socket of the FTPServer.
530 Login incorrect
The username or password provided by the FTP client does not match the credentials configured in the `DummyAuthorizer` (or a custom authorizer), or the authorizer is not properly assigned to the `FTPHandler`.
fix
Double-check the username, password, and permissions configured via `authorizer.add_user()` or `authorizer.add_anonymous()`, and ensure `handler.authorizer = authorizer` is set correctly.
Permission denied (when starting server on port < 1024)
On Unix-like operating systems, binding to network ports below 1024 (e.g., the standard FTP port 21) requires root privileges. Running the `pyftpdlib` server as an unprivileged user will result in this error.
fix
Run the Python script with root privileges (e.g., `sudo python your_ftp_server.py`) or configure the FTP server to listen on a port number greater than 1024 (e.g., 2121).
421 Active data channel timeout / Passive data channel timed out (for external connections)
The FTP server is likely behind a Network Address Translation (NAT) device or firewall, causing it to advertise its private (internal) IP address for passive data connections, or the range of passive ports is not open/forwarded in the firewall/router.
fix
Set `FTPHandler.masquerade_address` to the server's public IP address and configure `FTPHandler.passive_ports` with a specific range of TCP ports, ensuring these ports are open and forwarded from the router/firewall to the server's internal IP.
Upgrade
Version history
2.2.0latest on PyPI · released Feb 7, 2026
Audit
Dependencies
PyOpenSSLoptionalOptional, for FTPS (FTP over TLS/SSL) support.
psutiloptionalOptional, for tracking FTP server memory usage.
Agent activity
8 hits · last 30 days
node
8
Resources