Python Paramiko: Upload and Download Files over SFTP
Upload and download files over SFTP using Python Paramiko. This guide covers connection setup, host key verification, error handling, and cleanup.
When you need to move files between machines over SSH, Paramiko's SFTP client is a common choice in Python. The core operations are straightforward: connect to the server, open an SFTP session, then call put() to upload a local file or get() to download a remote file. This article covers connection setup, host key verification, error handling, and cleanup for reliable transfer scripts.
Setting Up Paramiko
Install Paramiko with pip:
pip install paramiko
Import it in your script:
import paramiko
Paramiko is a Python implementation of the SSHv2 protocol. Installing it with pip also installs the cryptographic packages it depends on.
Establishing an SFTP Connection
To start an SFTP session, create an SSHClient, connect to the remote host, and call open_sftp(). The connect method accepts hostname, port, username, and password or key-based authentication.
ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh.connect('example.com', port=22, username='user', password='secret') sftp = ssh.open_sftp()
The set_missing_host_key_policy line controls how missing host keys are handled. By default, Paramiko rejects unknown host keys. AutoAddPolicy accepts a missing host key and remembers it in memory for the current session. This is convenient for scripts but weakens security; see the host key verification section below.
Once connected, open_sftp() returns an SFTPClient object that provides the file transfer methods.
Uploading a File with put()
The put() method uploads a local file to a remote path:
sftp.put('local_file.txt', '/remote/path/file.txt')
The main arguments are the local path and the remote destination. You can also pass a callback that receives the number of bytes transferred and the total file size, which is useful for progress reporting:
def progress(transferred, total): print(f'Transferred {transferred}/{total} bytes') sftp.put('local_file.txt', '/remote/path/file.txt', callback=progress)
put() returns an SFTPAttributes object with metadata about the remote file.
Downloading a File with get()
The get() method downloads a remote file to a local path:
sftp.get('/remote/path/file.txt', 'local_file.txt')
Like put(), it accepts an optional callback for progress reporting. For most transfers, get() is sufficient; if you need finer control, you can open the remote file and read it in chunks manually.
Handling Errors and Exceptions
Network issues, permission problems, and missing files can raise exceptions. Many remote SFTP failures surface as OSError in Python 3, while SSH-level problems such as authentication failures often raise paramiko.SSHException subclasses. Catch the exceptions you expect and log them:
try: sftp.put('local.txt', '/remote/upload.txt') except OSError as e: print(f'Filesystem error: {e}') except paramiko.SSHException as e: print(f'SSH/SFTP error: {e}')
Make sure to close the SFTP session and SSH client in a finally block, or use the context managers shown below.
Security: Host Key Verification
AutoAddPolicy is convenient but vulnerable to man-in-the-middle attacks. In production, use the default RejectPolicy and verify the host key explicitly. One way is to load the system's known-host keys:
ssh = paramiko.SSHClient() ssh.load_system_host_keys() # loads from ~/.ssh/known_hosts ssh.connect('example.com', username='user', password='secret')
By default, SSHClient rejects a host key that is not in known_hosts. If a known key does not match, Paramiko raises BadHostKeyException (an SSHException subclass).
Reusing Connections for Multiple Transfers
Creating a new SSH connection for each file transfer adds significant overhead. If you need to move many files, reuse the same SFTPClient instance: keep the session open, perform the transfers, and close it when the work is done.
Using Context Managers for Cleaner Code
SSHClient and SFTPClient support context managers, so resources are closed even if an exception occurs:
import paramiko with paramiko.SSHClient() as ssh: ssh.load_system_host_keys() ssh.connect('example.com', username='user', password='secret') with ssh.open_sftp() as sftp: sftp.put('local.txt', '/remote/upload.txt') sftp.get('/remote/download.txt', 'local.txt')
The with blocks close the SFTP session and the SSH connection automatically, making this a good pattern for scripts and automation tasks.