Python SCP Client
The `scp.py` module, currently at version 0.15.0, provides a pure-Python implementation of the SCP1 (Secure Copy Protocol) client. It leverages the `paramiko` library for SSH transport, enabling secure file transfers over SSH connections, mirroring the functionality of the OpenSSH `scp` program. The library is actively maintained but follows an irregular release cadence.
Warnings
- gotcha The `scp` library is a thin wrapper around `paramiko`. Therefore, `paramiko` and its dependencies (like `cryptography`, which might require compilation tools) must be correctly installed. Issues with `paramiko` often manifest as `scp` problems.
- gotcha For security, always verify host keys. Using `paramiko.AutoAddPolicy()` in production is dangerous as it makes your client vulnerable to man-in-the-middle attacks.
- deprecated The underlying SCP1 protocol has known security limitations and is considered deprecated by OpenSSH in favor of SFTP. While `scp.py` implements SCP1, be aware that future changes in OpenSSH servers might affect compatibility or expose vulnerabilities.
- breaking The `progress` callback signature changed in version 0.13.0. It reverted to accepting 3 arguments (`path`, `total_size`, `sent_size`). A new `progress4` parameter was introduced to accept 4 arguments, including `peername`. Code using the 4-argument `progress` callback from pre-0.13.0 versions will break.
- gotcha Prior to version 0.13.6, the `put()` method might have behaved unexpectedly when the source directory path had a trailing slash (e.g., `scp.put('my_dir/', remote_path)`).
Install
-
pip install scp -
pip install paramiko scp
Imports
- SCPClient
from scp import SCPClient
- SSHClient
from paramiko import SSHClient
Quickstart
import os
from paramiko import SSHClient, AutoAddPolicy
from scp import SCPClient
# Configuration from environment variables for security
HOSTNAME = os.environ.get('SCP_HOSTNAME', 'your_remote_host')
USERNAME = os.environ.get('SCP_USERNAME', 'your_username')
PASSWORD = os.environ.get('SCP_PASSWORD', '') # Use SSH keys in production
local_file = 'local_test_file.txt'
remote_path = '/tmp/remote_test_file.txt'
# Create a dummy local file for the example
with open(local_file, 'w') as f:
f.write('Hello from scp.py!')
ssh = SSHClient()
# Set policy to auto-add host keys for demo. In production, use ssh.load_system_host_keys() or HostKeys().add().
ssh.set_missing_host_key_policy(AutoAddPolicy())
try:
# Connect to the remote server
ssh.connect(hostname=HOSTNAME, username=USERNAME, password=PASSWORD, port=22)
print(f"Connected to {HOSTNAME}")
# SCPCLient takes a paramiko transport as an argument
with SCPClient(ssh.get_transport()) as scp:
# Upload a file
scp.put(local_file, remote_path)
print(f"Uploaded '{local_file}' to '{remote_path}'")
# Download the file back to verify
downloaded_file = 'downloaded_test_file.txt'
scp.get(remote_path, downloaded_file)
print(f"Downloaded '{remote_path}' to '{downloaded_file}'")
except Exception as e:
print(f"An error occurred: {e}")
finally:
ssh.close()
print("SSH connection closed.")
# Clean up dummy files
import os
if os.path.exists(local_file):
os.remove(local_file)
if os.path.exists(downloaded_file):
os.remove(downloaded_file)