准备工作
如果使用SSH连接的话,首先在本地生成SSH密钥对,有两种方式都可以用
生成ras密钥对
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
生成ed25519密钥对
ssh-keygen -t ed25519 -C "your_email@example.com"
生成过程
$ ssh-keygen -t ed25519 -C "user@company.com"
Enter file in which to save the key (/home/username/.ssh/id_ed25519): [回车使用默认路径]
Enter passphrase (empty for no passphrase): [可选:输入密码保护私钥]
Enter same passphrase again: [再次输入]
使用
源码中,有SSH连接和密码连接,建议和我一样使用SSH来弄,这样子安全一点
源码包:下载源码
配置好后,把证书移进cert目录里面,然后运行代码就好
import os # os模块,处理文件
import subprocess
import sys
import shutil
import time
try:
import paramiko # sftp插件
except ImportError as error:
response = input("paramiko 未安装。是否现在安装? (y/n): ")
if response.lower().strip() in ['y', 'yes', '是']:
print("正在尝试自动安装paramiko插件...")
try:
subprocess.check_call((sys.executable, "-m", "pip", "install", "paramiko")) # 安装paramiko插件
print("paramiko 安装成功!")
import paramiko # sftp插件
except subprocess.CalledProcessError as error:
print("paramiko 安装失败!请手动运行 'pip install paramiko' 安装")
except Exception as e:
print(f"安装过程中发生未知错误: {e}")
sys.exit(1) # 安装失败,退出脚本
else:
print("请手动运行 'pip install paramiko' 安装")
# 上传文件
def file_upload(host, port, username, privateKey, upload_path):
global current_directory # 添加成全局,最后用
ssh = paramiko.SSHClient() # 创建SSH客户端
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) # 自动添加主机密钥
private_key = paramiko.RSAKey(filename=privateKey) # 加载RSA私钥
# 如果是 Ed25519 密钥,使用下面这行:
# private_key = paramiko.Ed25519Key(filename=privateKey) # 加载Ed25519私钥
try:
current_directory = os.path.join(os.path.dirname(os.path.abspath(__file__)), "cert") # 获取证书文件目录
# 进度条特效
progress_bar(10)
print(f"获取证书文件目录:{current_directory}")
all_items = os.listdir(current_directory) # 获取文件夹中所有文件和文件夹名
# '.idea', 'main.py' 这两个文件不上传
result_files = [
item for item in all_items
if os.path.isfile(os.path.join(current_directory, item)) and item not in {'.idea', 'main.py'}
]
# 如果 result_files 为空,抛出异常
if not result_files:
raise ValueError("未找到有效的上传文件:result_files 为空")
# 进度条特效
progress_bar(13)
print(f"获取要上传的文件:{result_files}")
ssh.connect(hostname=host, port=port, username=username, pkey=private_key)
# 进度条特效
progress_bar(14)
print("服务器连接成功")
sftp = ssh.open_sftp() # 创建SFTP会话
# 进度条特效
progress_bar(11)
print("会话创建成功")
for file in result_files:
local_path = os.path.join(current_directory, file)
remote_path = os.path.join(upload_path, file)
if not os.path.isfile(local_path):
raise FileNotFoundError(f"本地文件不存在:{local_path}")
sftp.put(local_path, remote_path)
print(f"文件上传成功:{local_path} -----> {remote_path}")
# 进度条特效
progress_bar(13)
print("文件上传完成")
"""
重启服务器nginx
"""
command = "sudo /usr/local/bin/nginx -t"
stdin, stdout, stderr = ssh.exec_command(command)
print(stderr.read().decode('utf-8'))
command = "sudo /usr/local/bin/nginx -s reload"
stdin, stdout, stderr = ssh.exec_command(command)
# 检查命令退出状态
exit_status = stdout.channel.recv_exit_status()
if exit_status == 0:
print("✅ nginx 配置成功!")
else:
print(f"❌ nginx 配置失败!退出状态码: {exit_status}")
except paramiko.PasswordRequiredException:
raise Exception("私钥受密码保护,请提供密码")
except paramiko.SSHException as e:
print(f"验证失败:{e}")
except Exception as e:
print(f"上传失败:{e}")
finally:
# 关闭连接
sftp.close()
ssh.close()
# 进度条特效
progress_bar(15)
print("连接已关闭")
# 清空证书文件夹
for filename in os.listdir(current_directory):
file_path = os.path.join(current_directory, filename)
try:
if os.path.isfile(file_path) or os.path.islink(file_path):
os.unlink(file_path) # 删除文件或符号链接
elif os.path.isdir(file_path):
shutil.rmtree(file_path) # 删除目录树
print("本地证书已经删除")
except Exception as e:
print(f'删除 {file_path} 失败: {e}')
# 进度条特效
def progress_bar(sum):
print(), print() # 换行
for i in range(5, sum + 1):
bar = '█' * i + '.' * (sum - i)
print(f"\r进度: {i}/{sum} [{bar}]", end="", flush=True)
time.sleep(0.1)
print() # 换行
if __name__ == '__main__':
host = '47.120.4.193' # 要上传的服务器地址
port = 22 # 要上传的服务器端口
username = 'lyj' # 要上传的服务器用户名
privateKey = r'C:\Users\Administrator\.ssh\id_rsa' # 客户端SSH公钥
upload_path = '/server/ceshi/' # 要上传的文件目录
file_upload(host, port, username, privateKey, upload_path)
报错解决方法
这个是鉴权失败,先检查客户端的公钥文件有没有写入服务端的authorized_keys文件里面
如果确定写入了,就检查一下服务端ssh的文件权限,可以按照下面的语句跟着输出一遍
chmod 700 /home/lyj/.ssh
chmod 600 /home/lyj/.ssh/authorized_keys
chown -R lyj:lyj /home/lyj/.ssh
lyj改成自己的用户名
这个是你在生成客户端密钥对的时候,设置了密码,但是在连接的时候,又没有配置密码导致,把里面的代码换成下面这个就可以了
private_key = paramiko.RSAKey(filename=privateKey, password='你的密码') # 加载RSA私钥
或者
这两个报错是在操作nginx命令时出现,是因为当你使用sudo
时,默认需要一个终端来输入密码,但在自动化脚本中没有 TTY(终端),所以报错
但是好像可以这样子,但是密码暴露在代码里面很危险
command = "echo 你的密码 | sudo /usr/local/bin/nginx -s reload"
我是这样子解决的,如果有不同见解,欢迎评论纠正
首先,我的服务端是centos服务器,如果你们的不是这个,可以ai一下
在服务器使用这个查找 nginx
可执行文件的路径
which nginx
然后打开/etc/sudoers文件,输入这两行语句,保存退出(lyj改成你们的用户名)
lyj ALL=(ALL) NOPASSWD: /usr/local/bin/nginx -t
lyj ALL=(ALL) NOPASSWD: /usr/local/bin/nginx -s reload
然后再把脚本的这两个改成你们配置的
command = "sudo /usr/local/bin/nginx -t"
command = "sudo /usr/local/bin/nginx -s reload"
就这样,大功告成啦,初版脚本,不足的地方还有好多,但能用就用嘛~