Python
SCP
File Transfer
Programming
Automation

How to scp in Python?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

If you want to copy files over SSH from Python, the most common approach is to combine paramiko with the scp package. That gives you a pure-Python way to upload and download files without shelling out to the system scp command. It is a good fit for automation scripts, deployment helpers, and internal tools.

Installing the Required Packages

You need an SSH client library and an SCP wrapper around its transport.

bash
python -m pip install paramiko scp

paramiko handles the SSH connection, authentication, and host keys. The scp package adds the familiar put and get file transfer operations on top of that connection.

Uploading and Downloading Files

The following example opens an SSH connection, uploads one file, then downloads another file.

python
1from pathlib import Path
2
3import paramiko
4from scp import SCPClient
5
6host = "example.com"
7username = "deploy"
8key_file = Path.home() / ".ssh" / "id_ed25519"
9
10ssh = paramiko.SSHClient()
11ssh.load_system_host_keys()
12ssh.connect(hostname=host, username=username, key_filename=str(key_file))
13
14with SCPClient(ssh.get_transport()) as scp:
15    scp.put("report.csv", "/tmp/report.csv")
16    scp.get("/var/log/app.log", "downloads/app.log")
17
18ssh.close()

This is the basic pattern to remember:

  • create an SSHClient
  • load trusted host keys
  • connect with a key or password
  • create SCPClient from the SSH transport
  • call put or get

If you need to copy directories, pass recursive=True.

Wrapping the Logic in a Reusable Function

For scripts that run repeatedly, it is cleaner to move the connection details into a small helper.

python
1from contextlib import contextmanager
2
3import paramiko
4from scp import SCPClient
5
6@contextmanager
7def open_scp(hostname, username, key_filename):
8    ssh = paramiko.SSHClient()
9    ssh.load_system_host_keys()
10    ssh.connect(hostname=hostname, username=username, key_filename=key_filename)
11    try:
12        with SCPClient(ssh.get_transport()) as scp:
13            yield scp
14    finally:
15        ssh.close()
16
17with open_scp("example.com", "deploy", "/Users/me/.ssh/id_ed25519") as scp:
18    scp.put("build/output.tar.gz", "/srv/releases/output.tar.gz")

This keeps the connection lifecycle safe and reduces duplication when several transfers happen in one script.

When subprocess Is Simpler

If you already rely on the system SSH configuration and you do not need Python-level control over the connection, calling the native scp binary with subprocess.run can be fine. That approach inherits your local SSH agent, config file, and jump-host settings more naturally.

The tradeoff is portability and error handling. With paramiko and scp, everything stays inside Python objects. With subprocess, you are orchestrating an external process and parsing its failures.

If your environment already depends on complex SSH config such as bastion hosts, custom identities, or per-host settings in ~/.ssh/config, the native client route can also save setup time because it reuses tooling your team already trusts.

Common Pitfalls

The biggest security mistake is adding AutoAddPolicy and forgetting about host key verification. That makes initial development convenient, but it weakens protection against man-in-the-middle attacks. Loading known host keys and rejecting unknown hosts is the safer default.

Another common problem is path confusion. The local path in scp.put is resolved on the machine running Python, while the remote destination is resolved on the SSH server. Mixing those up causes frustrating file-not-found errors.

Remember to close the SSH connection. A with block around SCPClient helps with the transfer object, but you still need to close the parent SSHClient.

Finally, do not assume SCP is the best choice for every workload. For large directory sync jobs or resumable transfers, SFTP, rsync, or cloud-native storage APIs may be more robust.

Summary

  • Use paramiko plus scp for programmatic SCP transfers in Python.
  • Load trusted host keys instead of blindly accepting unknown hosts.
  • Create SCPClient from ssh.get_transport() and use put or get.
  • Wrap connection setup in a helper when scripts perform repeated transfers.
  • Consider subprocess, SFTP, or rsync when your use case needs different tradeoffs.

Course illustration
Course illustration

All Rights Reserved.