Of course! Let's break down how to use SSH in Python. The most common and recommended library for this is paramiko.

The Recommended Library: paramiko
Paramiko is a pure Python implementation of the SSHv2 protocol. It provides a rich set of features for connecting to remote servers, executing commands, transferring files, and more.
Step 1: Install paramiko
If you don't have it installed, open your terminal or command prompt and run:
pip install paramiko
Step 2: Basic SSH Connection and Command Execution
This is the most fundamental task: connecting to a server and running a single command.
Here's a complete, commented example.

import paramiko
import sys
# --- Configuration ---
# Replace with your server's hostname or IP address
hostname = 'your_server_ip'
# Replace with your SSH username
username = 'your_username'
# Replace with your SSH password (or use key-based auth, shown later)
password = 'your_password'
# --- Create an SSH Client ---
try:
# Create a new SSHClient instance
ssh_client = paramiko.SSHClient()
# Automatically add the server's host key (this is insecure for production)
# It will accept any new host key without verification.
# For better security, you should use load_system_host_keys() or
# add_host_key() with a known key.
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# --- Connect to the Server ---
print(f"Connecting to {hostname}...")
ssh_client.connect(hostname=hostname, username=username, password=password)
print("Connection successful!")
# --- Execute a Command ---
# We'll run 'ls -l' to list files in the current directory
command = 'ls -l'
print(f"Executing command: '{command}'")
# The exec_command() method returns three values:
# 1. A standard input stream (stdin)
# 2. A standard output stream (stdout)
# 3. A standard error stream (stderr)
stdin, stdout, stderr = ssh_client.exec_command(command)
# --- Read the Output ---
# Read the output from stdout
output = stdout.read().decode('utf-8')
# Read any errors from stderr
error = stderr.read().decode('utf-8')
if error:
print("Error occurred:")
print(error)
else:
print("\n--- Command Output ---")
print(output)
# --- Close the Connection ---
ssh_client.close()
print("\nConnection closed.")
except paramiko.AuthenticationException:
print("Authentication failed, please verify your credentials.")
except paramiko.SSHException as e:
print(f"Unable to establish SSH connection: {e}")
except Exception as e:
print(f"An unexpected error occurred: {e}")
To run this script:
- Save the code as a Python file (e.g.,
ssh_example.py). - Replace
your_server_ip,your_username, andyour_passwordwith your actual details. - Run from your terminal:
python ssh_example.py
Step 3: Key-Based Authentication (More Secure)
Using passwords is convenient, but SSH keys are far more secure and standard practice. Paramiko supports them easily.
You'll need:
- A private key file (e.g.,
id_rsaorid_ed25519) on your local machine. - The corresponding public key must be in the
~/.ssh/authorized_keysfile on the remote server.
Here's how to modify the code to use a key:

import paramiko
# --- Configuration ---
hostname = 'your_server_ip'
username = 'your_username'
# Path to your private key file
private_key_path = '/path/to/your/private_key' # e.g., '~/.ssh/id_rsa'
# --- Create an SSH Client ---
ssh_client = paramiko.SSHClient()
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
# --- Connect using a private key ---
# You can use either a password-protected key or an unprotected one.
# For an unprotected key:
print(f"Connecting to {hostname} with key...")
private_key = paramiko.RSAKey.from_private_key_file(private_key_path)
ssh_client.connect(hostname=hostname, username=username, pkey=private_key)
# For a password-protected key (passphrase):
# private_key = paramiko.RSAKey.from_private_key_file(private_key_path, password='your_key_passphrase')
# ssh_client.connect(hostname=hostname, username=username, pkey=private_key)
print("Connection successful!")
# --- Execute a command ---
stdin, stdout, stderr = ssh_client.exec_command('uname -a')
output = stdout.read().decode('utf-8')
error = stderr.read().decode('utf-8')
if error:
print("Error:", error)
else:
print("Server OS Info:")
print(output)
ssh_client.close()
except Exception as e:
print(f"An error occurred: {e}")
Step 4: Interactive Shell (Like ssh)
Sometimes you want an interactive session, not just to run a single command. You can do this with invoke_shell().
import paramiko
import time
hostname = 'your_server_ip'
username = 'your_username'
password = 'your_password'
ssh_client = paramiko.SSHClient()
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
ssh_client.connect(hostname=hostname, username=username, password=password)
print("Connected. Starting interactive shell...")
# Start an interactive shell
channel = ssh_client.invoke_shell()
# Send a command
channel.send("ls -l\n") # The '\n' is crucial to execute the command
# Wait for the command to execute and read the output
time.sleep(1) # Give it a moment to process
# Read the output
output = channel.recv(4096).decode('utf-8')
print(output)
# Send another command
channel.send("echo 'Hello from Paramiko!'\n")
time.sleep(1)
output = channel.recv(4096).decode('utf-8')
print(output)
# Close the channel and connection
channel.close()
ssh_client.close()
except Exception as e:
print(f"An error occurred: {e}")
Step 5: File Transfer (SFTP)
Paramiko has a built-in SFTP client for secure file transfers.
import paramiko
hostname = 'your_server_ip'
username = 'your_username'
password = 'your_password'
# --- Local file to upload and remote path ---
local_path = 'local_file.txt'
remote_path = '/home/your_username/remote_file.txt'
ssh_client = paramiko.SSHClient()
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
ssh_client.connect(hostname=hostname, username=username, password=password)
print("Connection established for SFTP.")
# Create an SFTP client from the SSH session
sftp = ssh_client.open_sftp()
# --- Upload a file ---
print(f"Uploading {local_path} to {remote_path}...")
sftp.put(local_path, remote_path)
print("Upload complete.")
# --- Download a file ---
# remote_download_path = '/home/your_username/remote_file.txt'
# local_download_path = 'downloaded_file.txt'
# print(f"Downloading {remote_download_path} to {local_download_path}...")
# sftp.get(remote_download_path, local_download_path)
# print("Download complete.")
# Close the SFTP session
sftp.close()
ssh_client.close()
print("SFTP session and connection closed.")
except Exception as e:
print(f"An error occurred during SFTP: {e}")
Summary of Key paramiko Components
| Component | Description | Common Use Case |
|---|---|---|
paramiko.SSHClient() |
The main object for managing an SSH connection. | Creating a connection session. |
.connect() |
Establishes the connection to the server. | Authenticating and logging in. |
.set_missing_host_key_policy() |
Configures how to handle unknown server host keys. | Essential for security (use AutoAddPolicy cautiously). |
.exec_command() |
Executes a single command on the server. | Running scripts, checking system status. |
invoke_shell() |
Starts an interactive, text-based shell session. | Running multiple commands interactively. |
.open_sftp() |
Creates an SFTP client for file operations. | Uploading and downloading files. |
stdin, stdout, stderr |
Standard streams returned by exec_command. |
Getting command output and error messages. |
pkey= (in .connect) |
Parameter for authenticating with a private key. | Secure, passwordless login. |
Alternatives to paramiko
While paramiko is the most popular, there are other options:
fabric: A higher-level library built on top ofparamiko. It simplifies common tasks like running commands on multiple servers, uploading files, and handling environment variables. It's great for automation scripts.asyncssh: A modern library that provides an asynchronous API using Python'sasyncio. It's ideal for applications that need to handle many SSH connections concurrently (e.g., monitoring many servers at once).subprocess+sshcommand: You could use Python'ssubprocessmodule to run thesshcommand-line tool directly. This is simple but gives you less control and bypasses Python's exception handling. It's generally not recommended for robust applications.
