Paramiko 是一个强大的、纯 Python 实现的 SSHv2 协议库,它允许你用 Python 代码来连接远程服务器,并执行命令、上传下载文件、设置隧道等,就像是你在终端里手动操作一样,它不依赖于任何外部的 SSH 客户端或库(如 OpenSSH),非常方便。

核心功能
Paramiko 主要提供了以下几个核心功能:
- 执行远程命令:这是最基本的功能,连接到服务器后,可以执行任何 Shell 命令并获取其输出。
- 文件传输 (SFTP):
Paramiko内置了 SFTP (SSH File Transfer Protocol) 客户端,可以方便地在本地和远程服务器之间上传或下载文件和目录。 - SSH 端口转发:可以创建安全的隧道,将本地端口映射到远程服务器,或者反之,这对于访问远程数据库、服务等非常有用。
- 处理密钥认证:支持通过密码和 SSH 密钥对(公钥/私钥)进行身份验证。
安装
在使用之前,你需要先安装 paramiko,可以通过 pip 轻松安装:
pip install paramiko
基本用法
执行远程命令
这是最常见的用法,基本流程是:创建一个 SSHClient 对象 -> 连接服务器 -> 执行命令 -> 关闭连接。
import paramiko
# --- 1. 创建 SSHClient 对象 ---
ssh = paramiko.SSHClient()
# --- 2. 自动添加主机密钥 (第一次连接时需要) ---
# 在生产环境中,更安全的做法是使用 known_hosts 文件
# ssh.load_system_host_keys()
# 或者手动指定主机密钥
# ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) # 不推荐生产环境使用
ssh.set_missing_host_key_policy(paramiko.RejectPolicy()) # 更安全,会拒绝未知主机
try:
# --- 3. 连接服务器 ---
# 使用密码认证
hostname = "your_server_ip"
port = 22
username = "your_username"
password = "your_password"
ssh.connect(hostname, port=port, username=username, password=password)
print("连接成功!")
# --- 4. 执行命令 ---
command = "ls -l /home"
stdin, stdout, stderr = ssh.exec_command(command)
# --- 5. 获取命令输出 ---
# stdout 是标准输出
output = stdout.read().decode('utf-8')
# stderr 是标准错误
error = stderr.read().decode('utf-8')
if error:
print(f"命令执行出错: {error}")
else:
print(f"命令执行结果:\n{output}")
except paramiko.AuthenticationException:
print("认证失败,请检查用户名和密码。")
except paramiko.SSHException as e:
print(f"SSH连接或命令执行出错: {e}")
except Exception as e:
print(f"发生未知错误: {e}")
finally:
# --- 6. 关闭连接 ---
if ssh:
ssh.close()
print("连接已关闭。")
代码解析:

SSHClient(): 创建客户端实例。set_missing_host_key_policy(): 第一次连接到一台新服务器时,服务器会发送它的公钥(主机密钥),你需要决定如何处理这个密钥。AutoAddPolicy: 自动接受并保存。方便但不够安全,可能会受到中间人攻击。RejectPolicy: 拒绝连接。更安全,需要你提前知道并验证服务器的公钥。
connect(): 建立连接,可以通过password传密码,也可以通过pkey传私钥对象。exec_command(): 执行命令,它返回三个文件类对象:stdin(标准输入),stdout(标准输出),stderr(标准错误)。stdout.read(): 读取命令的输出,返回的是字节流,通常需要用.decode('utf-8')解码成字符串。
使用 SSH 密钥对认证
使用密钥对比密码更安全、更自动化。
前提:你已经有一对公钥和私钥(通常在 ~/.ssh/ 目录下,id_rsa 是私钥,id_rsa.pub 是公钥),并且公钥已经通过 ssh-copy-id user@host 命令添加到了远程服务器的 ~/.ssh/authorized_keys 文件中。
import paramiko
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
# --- 1. 指定私钥文件路径 ---
private_key_path = '/home/user/.ssh/id_rsa'
# --- 2. 加载私钥 ---
# 如果你的私钥有密码,需要用 password 参数指定
private_key = paramiko.RSAKey.from_private_key_file(private_key_path)
ssh.connect(hostname="your_server_ip",
username="your_username",
pkey=private_key,
# password="your_private_key_password" # 如果私钥有密码
)
print("密钥认证连接成功!")
stdin, stdout, stderr = ssh.exec_command('echo "Hello from Paramiko!"')
print(stdout.read().decode('utf-8'))
except Exception as e:
print(f"连接或执行命令出错: {e}")
finally:
ssh.close()
文件传输 (SFTP)
Paramiko 的 SFTPClient 使得文件传输变得非常简单。
import paramiko
import os
# 假设已经通过上面的方式建立了 ssh 连接
# ssh = paramiko.SSHClient()
# ssh.connect(...)
# ... (连接代码同上)
# 从 SSHClient 实例获取 SFTP 客户端
sftp = ssh.open_sftp()
try:
# --- 上传文件 ---
local_path = 'local_file.txt'
remote_path = '/home/your_username/remote_file.txt'
print(f"正在上传 {local_path} 到 {remote_path}...")
sftp.put(local_path, remote_path)
print("上传成功!")
# --- 下载文件 ---
# local_download_path = 'downloaded_file.txt'
# remote_download_path = '/home/your_username/remote_file.txt'
# print(f"正在下载 {remote_download_path} 到 {local_download_path}...")
# sftp.get(remote_download_path, local_download_path)
# print("下载成功!")
# --- 创建目录 ---
# remote_dir = '/home/your_username/new_dir'
# try:
# sftp.mkdir(remote_dir)
# print(f"目录 {remote_dir} 创建成功!")
# except IOError:
# print(f"目录 {remote_dir} 已存在。")
# --- 列出远程目录内容 ---
# dir_list = sftp.listdir('/home/your_username')
# print(f"远程目录内容: {dir_list}")
finally:
# 关闭 SFTP 和 SSH 连接
sftp.close()
ssh.close()
print("SFTP 和 SSH 连接已关闭。")
SFTP 常用方法:
sftp.put(local_path, remote_path): 上传文件。sftp.get(remote_path, local_path): 下载文件。sftp.listdir(path): 列出指定目录下的文件和文件夹名(列表)。sftp.listdir_attr(path): 列出指定目录下的文件和文件夹的属性(包含权限、大小、时间等)。sftp.mkdir(path): 创建目录。sftp.remove(path): 删除文件。sftp.rmdir(path): 删除空目录。sftp.stat(path): 获取文件/目录的属性信息。
SSH 端口转发
Paramiko 可以创建本地、远程或动态的端口转发。
示例:本地端口转发
将你本地的 localhost:8888 端口的所有流量,通过 SSH 服务器 your_server_ip 转发到目标服务器 target_server_ip:3306(远程的 MySQL 数据库)。
import paramiko
import socket
# --- 1. 建立 SSH 连接 ---
ssh_transport = paramiko.Transport(('your_server_ip', 22))
# 使用密码或密钥进行认证
# ssh_transport.connect(username='your_username', password='your_password')
# ... (或使用 pkey 认证)
# --- 2. 设置端口转发 ---
# 参数: (本地端口, 目标主机, 目标端口)
local_port = 8888
target_host = 'target_server_ip'
target_port = 3306
# 创建一个本地端口转发通道
channel = ssh_transport.open_port_fwd('', local_port)
# --- 3. 将本地端口绑定到目标 ---
# 这个循环会阻塞,保持转发通道开启
try:
print(f"正在开启本地端口转发: 127.0.0.1:{local_port} -> {target_host}:{target_port}")
# 使用 socket 来处理连接
# 这部分代码相对复杂,通常会用更高级的封装
# 这里简化说明原理
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind(('', local_port))
server_socket.listen(1)
while True:
client_socket, addr = server_socket.accept()
print(f"收到来自 {addr} 的连接")
# 将客户端的连接转发到远程服务器
# ... (这里需要处理数据流转发,略)
except KeyboardInterrupt:
print("端口转发已停止。")
finally:
channel.close()
ssh_transport.close()
注意:端口转发的实现细节相对复杂,上面的例子展示了基本原理,在实际应用中,可能会使用 paramiko 的 Channel 对象进行更精细的数据流控制。
最佳实践与注意事项
-
主机密钥验证:永远不要在生产环境中使用
AutoAddPolicy,你应该提前获取服务器的公钥(ssh-keyscan your_server_ip),然后在代码中加载它。# 安全的主机密钥验证方式 host_key = paramiko.RSAKey(data=b'...') # 这里放你获取到的服务器公钥 ssh = paramiko.SSHClient() ssh.get_host_keys().add('your_server_ip', 'ssh-rsa', host_key) ssh.connect(...) -
使用上下文管理器 (
with语句):为了确保连接和资源(如 SFTP 客户端)总是被正确关闭,可以封装一个上下文管理器,幸运的是,paramiko的SSHClient和SFTPClient都支持with语句。# 使用 with 语句,自动管理连接 with paramiko.SSHClient() as ssh: ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh.connect("your_server_ip", username="user", password="pass") with ssh.open_sftp() as sftp: sftp.put('local.txt', 'remote.txt') print("文件传输完成,连接已自动关闭。") # 连接在这里自动关闭 -
处理长时间运行的命令:
exec_command会等待命令执行完毕,对于长时间运行的进程(如tail -f),它可能会阻塞,这时,可以考虑使用invoke_shell方法,它交互式地打开一个 Shell 会话,你可以像在终端里一样持续地发送和接收数据。 -
错误处理:
paramiko会抛出多种异常,如AuthenticationException,SSHException,BadHostKeyException等,使用try...except块来捕获这些异常,可以让你的代码更健壮。
| 功能 | 核心方法/对象 | 描述 |
|---|---|---|
| 执行命令 | SSHClient.exec_command() |
执行单条命令,获取输出和错误。 |
| 文件传输 | SSHClient.open_sftp() + SFTPClient |
获取 SFTP 客户端,用于上传下载文件 (put, get)。 |
| 端口转发 | Transport.open_port_fwd() |
创建安全的 SSH 隧道。 |
| 认证方式 | password 参数 (密码) pkey 参数 (密钥对象) |
两种主要的身份验证方式。 |
| 安全实践 | set_missing_host_key_policy(paramiko.RejectPolicy()) |
严格验证服务器主机密钥,防止中间人攻击。 |
paramiko 是 Python 自动化运维、远程管理、部署脚本等场景下的必备神器,掌握它能极大地提升你的工作效率。
