1. 背景
服务器使用宝塔面板管理服务器,服务器上部署了两个动态 网站和一个静态网站.网站不多,没有必要上流水线.每次都要经历一个繁琐的过程,并且都是手动操作,极容易出错.目前三个站点更新大体步骤如下:
- 停用管理端和移动端网站
- 编译管理段后端代码
- 编译移动端后端代码
- 编译管理端前端代码
- 上传管理段后端编译文件
- 上传移动端后端编译文件
- 压缩前端编译文件,并上传压缩文件
- 解压前端编译文件
- 启用管理端网站
- 启用移动端网站
一次两次更新还好,多网站,多频次更新,还是需要一个简单脚本实现自动化更新部署.
2. 开启api访问
登录宝塔面板,找到设置/面板设置>api接口,点击api接口配置获取接口密钥,以及配置ip白名单.配置图如下

3. 访问签名处理
访问接口时,需要添加签名参数,签名参数生成规是 token: md5(str(时间戳) + 密钥md5),python实现代码如下
# self.api_key 是在接口配置获取的接口密钥
# 公众号: 小满小慢
def _generate_sign(self) -> dict:
now_time = int(time.time())
api_key_md5 = hashlib.md5(self.api_key.encode()).hexdigest()
token_str = str(now_time) + api_key_md5
token = hashlib.md5(token_str.encode()).hexdigest()
return {
'request_token': token,
'request_time': now_time
}4. 通用请求处理
api所有的请求都需要带上签名信息,我们这里对访问的接口 做一个统一的封装,使调用接口只关心业务参数,对一封装代码如下
# self.panel_url 配置的宝塔面板地址
# 公众号: 小满小慢
def _post(self, endpoint: str, data: dict = none) -> dict:
if data is none:
data = {}
sign_params = self._generate_sign()
all_data = {**data, **sign_params}
url = urljoin(self.panel_url, endpoint)
try:
response = requests.post(
url,
data=all_data,
timeout=self.request_timeout,
verify=false
)
response.raise_for_status()
result = response.json()
if result.get('status') == false:
raise exception(f"地心侠士: api 错误: {result.get('msg', '未知错误')}")
return result
except requests.exceptions.requestexception as e:
raise exception(f"地心侠士: 请求失败: {e}")
5. 文件上传
文件上传比较特殊,这里需读取本地文件,并上传到服务器指定目录,这里单独封成一个方法.
# 公众号: 小满小慢
# 小游戏: 地心侠士
def upload_file(self, local_path: str, remote_path: str) -> bool:
try:
file_name = os.path.basename(local_path)
file_size = os.path.getsize(local_path)
remote_dir = os.path.dirname(remote_path)
print(f" 地心侠士 准备上传: {file_name} ({file_size} bytes) -> {remote_path}")
sign_data = self._generate_sign()
data = {
'f_path': remote_dir,
'f_name': remote_path,
'f_size': file_size,
'f_start': 0,
'request_token': sign_data['request_token'],
'request_time': sign_data['request_time']
}
files = {
'blob': (file_name, open(local_path, 'rb'), 'application/octet-stream')
}
endpoint = '/files?action=upload'
url = urljoin(self.panel_url, endpoint)
headers = {
'accept': '*/*',
'accept-encoding': 'zh-cn,zh;q=0.9',
'connection': 'keep-alive'
}
response = requests.post(
url,
headers=headers,
data=data,
files=files,
timeout=self.request_timeout,
verify=false
)
files['blob'][1].close()
response.raise_for_status()
result = response.json()
if result.get('status') == false:
raise exception(f"地心侠士 api 错误: {result.get('msg', '未知错误')}")
print(f" 地心侠士 [成功] 文件上传完成: {file_name}")
return true
except exception as e:
print(f" 地心侠士 [错误] 文件上传失败: {e}")
return false
6. 文件解压
文件解压接口,根据文件上传的路径,调用文件解压接口,实现文件解压功能,以及删除解压完成的zip文件,核心代码如下
# remote_zip 是服务上传的zip文件路径
# web_site_path 是网站解压路径
# 公众号: 小满小慢
try:
unzip_result = api._post('/files?action=unzip', {
'sfile': remote_zip,
'dfile': web_site_path,
'encoding': 'utf-8'
})
if unzip_result.get('status'):
print(f" 地心侠士 [成功] zip文件已解压到: {web_site_path}")
try:
api._post('/files?action=deletefile', {
'path': remote_zip
})
print(f" 地心侠士 [成功] 已清理临时zip文件")
except:
pass
else:
print(f" 地心侠士 [警告] 解压可能有问题: {unzip_result.get('msg', '未知错误')}")
print(f" 地心侠士 请手动解压: {remote_zip} -> {web_site_path}")
7. 停用启用网站
文件部署完成后,针对后端的任务,如果没有开启热启动,这里我们需要先获取站点信息,然后停用网站,再启动网站
获取网站信息
# 公众号: 小满小慢
# 返回信息说明: name 网站名称 path 网站路径 site_id 网站id
sites_result = api._post('/data?action=getdata', {
'table': 'sites',
'limit': 1000
})
停用网站
stop_result = api._post('/site?action=sitestop', {
'id': site_id,
'name': site_name
})
启动网站
start_result = api._post('/site?action=sitestart', {
'id': site_id,
'name': site_name
})
8. 总结
使用脚本自动化部署,最重要的好处就是在脚本编写完成后,完全解放双手,并且不易出错,当然也得做好备份.目前宝塔的api信息不多,当前部署需要的api信息汇总如下
| 功能 | 接口地址 | 方法 |
|---|---|---|
| 测试连接 | /system?action=getnetwork | post |
| 文件上传 | /files?action=upload | post |
| 文件解压 | /files?action=unzip | post |
| 删除文件 | /files?action=deletefile | post |
| 获取网站列表 | /data?action=getdata | post |
| 停用网站 | /site?action=sitestop | post |
| 启用网站 | /site?action=sitestart | post |
到此这篇关于linux宝塔面板使用api自动部署更新文件的完整指南的文章就介绍到这了,更多相关linux宝塔面板管理服务器内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论