底层技术: docker
自编写docker-compose/编译dockerfile
诺依阁服务器要求
1.SLA可用性> 90%,可快速跨服务器部署,有一台节点做主备调度,在不存在问题时候依据服务器位置相应对用户提供服务,
2.lnmp中对nginx不漏版本号,防止黑客攻击,同时限制nginx 并发数量,并充分利用cpu多核心、线程进行调优,要求ssl具有OCSP(在线证书状态协议)和http2功能,且用TLS1.2和TLS1.3协议进行加密,php要求页面打开速度不得高于6秒(不包括其他后加载js),必要时候可以采取redis进行数据库读写
3.要求docker进行高可用检测,对于不健康的容器进行自动重启/重新创建,网络保持在同一个网络下
4.要求分布式服务器对指定目录实时监测,发现增加、删除文件及时同步
5.对系统ssh采取f2ban防护,防止密码爆破器(后续再写搭建)
6.对linux进行性能和其他方面调优,保证docker在高峰期时稳定运行
7.对mariadb-server数据库做双主同步,保证数据库数据在分布式服务器上保持一致
系统配置
基础配置
2核cpu+
2G内存+
20G硬盘+
网络能连接外网环境进行拉取镜像(内网也可以需要手动下载)
本文采取欧拉24.03LTS-SP1
欧拉觉得速度慢可以换华为源
sed -i "s/repo.openeuler.org/mirrors.huaweicloud.com\/openeuler/g" /etc/yum.repos.d/openEuler.repo
sed -i "s/metalink/#metalink/g" /etc/yum.repos.d/openEuler.repo
首先安装基础环境
yum install vim* bash* net-tools wget -y
Docker安装(用于构建docker镜像)
# step 1: 安装必要的一些系统工具
yum install yum-utils device-mapper-persistent-data lvm2 -y
# Step 2: 添加软件源信息
yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
# Step 3
sed -i 's+download.docker.com+mirrors.aliyun.com/docker-ce+' /etc/yum.repos.d/docker-ce.repo
# Step 3 of openEuler
sudo sed -i 's+$releasever+9+' /etc/yum.repos.d/docker-ce.repo
# Step 4: 更新并安装Docker-CE
yum makecache
yum install docker-ce docker-compose docker-compose-plugin -y
# Step 4: 开启并设置自动启动Docker服务
systemctl enable --now docker
# 查看docker版本
docker version
修改内核参数
cat > /etc/sysctl.d/docker.conf << EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
EOF
生效内核参数
sysctl -p
Docker加速器/网络地址配置
touch /etc/docker/daemon.json
cat > /etc/docker/daemon.json << EOF
{
"registry-mirrors": [
"https://docker.m.daocloud.io",
"https://docker.nastool.de",
"https://docker.1ms.run",
"https://docker.1panel.live",
"https://docker.1panel.top",
"https://hub-mirror.c.163.com",
"https://mirror.baidubce.com",
"https://dockerhub.icu",
"https://hub.rat.dev",
"https://docker.wanpeng.top",
"https://docker.mrxn.net",
"https://docker.anyhub.us.kg",
"https://dislabaiot.xyz",
"https://docker.fxxk.dedyn.io",
"https://docker-mirror.aigc2d.com",
"https://doublezonline.cloud",
"https://dockerproxy.com",
"https://mirror.iscas.ac.cn",
"https://docker66ccff.lovablewyh.eu.org"
],
"bip": "192.168.100.1/24",
"default-address-pools": [
{
"base": "192.168.100.0/16",
"size": 24
}
]
}
EOF
systemctl daemon-reload
systemctl restart docker
Docker-compose安装
curl -L "https://gh.llkk.cc/https://github.com/docker/compose/releases/download/v2.32.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/bin/docker-compose && chmod +x /usr/bin/docker-compose
Dockerfile编写
FROM debian:12
# 设置默认的 shell 为 Bash
SHELL ["/bin/bash", "-c"]
# 基础创建
RUN mkdir -p /nuoyis-build/{php-8.4.2/ext/php-redis,php-8.1.31/ext/php-redis} && \
mkdir -p /nuoyis-web/logs/nginx && \
mkdir -p /nuoyis-web/nginx/{conf,webside/default,server/1.27.3/conf/ssl,webside/default} && \
mkdir -p /var/run/php/{81,84} && \
useradd -M -s /sbin/nologin nuoyis-web && \
mkdir -p /etc/supervisor.d && \
sed -i 's/deb.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list.d/debian.sources && apt-get update -y && apt-get install apt-transport-https ca-certificates -y && sed -i 's/http:\/\/mirrors.ustc.edu.cn/https:\/\/mirrors.huaweicloud.com/g' /etc/apt/sources.list.d/debian.sources
# nginx和php-fpm构建
RUN apt-get update && apt-get install -y \
vim \
make \
procps \
gcc \
inetutils-ping \
pkg-config \
g++ \
curl \
libpcre3 \
libpcre3-dev \
zlib1g-dev \
openssl \
libssl-dev \
libxslt1-dev \
libpng-dev \
libjpeg-dev \
libfreetype6-dev \
libxml2-dev \
libsqlite3-dev \
libbz2-dev \
libcurl4-openssl-dev \
libxpm-dev \
libzip-dev \
libonig-dev \
libgd-dev \
libgeoip-dev \
supervisor && \
cd /nuoyis-build && \
curl -sSOL https://mirrors.huaweicloud.com/nginx/nginx-1.27.3.tar.gz && \
curl -sSOL https://alist.nuoyis.net/d/blog/linux%E8%BD%AF%E4%BB%B6%E5%8C%85%E5%8A%A0%E9%80%9F/php/php-8.4.2.tar.gz && \
curl -sSOL https://alist.nuoyis.net/d/blog/linux%E8%BD%AF%E4%BB%B6%E5%8C%85%E5%8A%A0%E9%80%9F/php/php-8.1.31.tar.gz && \
curl -sSOL https://ghproxy.cc/https://github.com/phpredis/phpredis/archive/refs/tags/6.1.0.tar.gz && \
tar -xzf nginx-1.27.3.tar.gz && tar -xzf php-8.4.2.tar.gz && tar -xzf php-8.1.31.tar.gz && tar -xzf 6.1.0.tar.gz && \
cd /nuoyis-build/nginx-1.27.3 && \
sed -i 's/#define NGINX_VERSION\s\+".*"/#define NGINX_VERSION "1.27.3"/g' ./src/core/nginx.h && \
sed -i 's/"nginx\/" NGINX_VERSION/"nuoyis server"/g' ./src/core/nginx.h && \
sed -i 's/Server: nginx/Server: nuoyis server/g' ./src/http/ngx_http_header_filter_module.c && \
sed -i 's/"Server: " NGINX_VER CRLF/"Server: nuoyis server" CRLF/g' ./src/http/ngx_http_header_filter_module.c && \
sed -i 's/"Server: " NGINX_VER_BUILD CRLF/"Server: nuoyis server" CRLF/g' ./src/http/ngx_http_header_filter_module.c && \
./configure --prefix=/nuoyis-web/nginx/server/1.27.3 \
--user=nuoyis-web --group=nuoyis-web \
--with-compat \
--with-file-aio \
--with-threads \
--with-http_addition_module \
--with-http_auth_request_module \
--with-http_dav_module \
--with-http_flv_module \
--with-http_gunzip_module \
--with-http_gzip_static_module \
--with-http_mp4_module \
--with-http_random_index_module \
--with-http_realip_module \
--with-http_secure_link_module \
--with-http_slice_module \
--with-http_ssl_module \
--with-http_stub_status_module \
--with-http_sub_module \
--with-http_v2_module \
--with-mail \
--with-mail_ssl_module \
--with-stream \
--with-stream_realip_module \
--with-stream_ssl_module \
--with-stream_ssl_preread_module \
--with-cc-opt='-static -s' \
--with-ld-opt=-static && \
make -j$(nproc) && make install && \
cp -r /nuoyis-build/phpredis-6.1.0/* /nuoyis-build/php-8.4.2/ext/php-redis && \
cp -r /nuoyis-build/phpredis-6.1.0/* /nuoyis-build/php-8.1.31/ext/php-redis && \
cd /nuoyis-build/php-8.4.2 && \
./configure --prefix=/nuoyis-web/php/8.4.2/ \
--enable-static \
--disable-shared \
--with-config-file-path=/nuoyis-web/php/8.4.2/etc/ \
--with-curl \
--with-freetype \
--enable-gd \
--with-jpeg \
--with-gettext \
--with-libdir=lib64 \
--with-libxml \
--with-mysqli \
--with-openssl \
--with-pdo-mysql \
--with-pdo-sqlite \
--with-pear \
--enable-sockets \
--with-mhash \
--with-ldap-sasl \
--with-xsl \
--with-zlib \
--with-zip \
--with-bz2 \
--with-iconv \
--enable-fpm \
--enable-pdo \
--enable-bcmath \
--enable-mbregex \
--enable-mbstring \
--enable-opcache \
--enable-pcntl \
--enable-shmop \
--enable-soap \
--enable-ftp \
--with-xpm \
--enable-xml \
--enable-sysvsem \
--enable-cli \
--enable-intl \
--enable-calendar \
--enable-static \
--enable-ctype \
--enable-mysqlnd \
--enable-session \
--enable-redis && \
make -j$(nproc) && make install && \
cd /nuoyis-build/php-8.1.31 && \
./configure --prefix=/nuoyis-web/php/8.1.31/ \
--enable-static \
--disable-shared \
--with-config-file-path=/nuoyis-web/php/8.1.31/etc/ \
--with-curl \
--with-freetype \
--enable-gd \
--with-jpeg \
--with-gettext \
--with-libdir=lib64 \
--with-libxml \
--with-mysqli \
--with-openssl \
--with-pdo-mysql \
--with-pdo-sqlite \
--with-pear \
--enable-sockets \
--with-mhash \
--with-ldap-sasl \
--with-xsl \
--with-zlib \
--with-zip \
--with-bz2 \
--with-iconv \
--enable-fpm \
--enable-pdo \
--enable-bcmath \
--enable-mbregex \
--enable-mbstring \
--enable-opcache \
--enable-pcntl \
--enable-shmop \
--enable-soap \
--enable-ftp \
--with-xpm \
--enable-xml \
--enable-sysvsem \
--enable-cli \
--enable-intl \
--enable-calendar \
--enable-static \
--enable-ctype \
--enable-mysqlnd \
--enable-session \
--enable-redis && \
make -j$(nproc) && make install && \
apt-get autoremove --purge -y \
make \
procps \
gcc \
procps \
inetutils-ping \
pkg-config \
libssl-dev \
g++ && \
apt-get remove -y \
libpcre3-dev \
zlib1g-dev \
libpng-dev \
libjpeg-dev \
libfreetype6-dev \
libbz2-dev \
libcurl4-openssl-dev \
libxpm-dev \
libgd-dev && \
apt-get clean && \
rm -rf /var/cache/apt/* /nuoyis-build /var/lib/apt/lists/* /tmp/* /var/tmp/* && \
ln -s /nuoyis-web/nginx/server/1.27.3/sbin/nginx /usr/bin/nginx && \
mv /nuoyis-web/php/8.4.2/etc/php-fpm.conf.default /nuoyis-web/php/8.4.2/etc/php-fpm.conf && \
mv /nuoyis-web/php/8.1.31/etc/php-fpm.conf.default /nuoyis-web/php/8.1.31/etc/php-fpm.conf && \
curl -L -o /nuoyis-web/nginx/server/1.27.3/conf/nginx.conf https://alist.nuoyis.net/d/blog/nuoyis-lnmp-np/%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6/v1.30/nginx.conf.txt && \
curl -L -o /nuoyis-web/nginx/webside/default/index.html https://alist.nuoyis.net/d/blog/nuoyis-lnmp-np/%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6/v1.30/index.html && \
curl -L -o /nuoyis-web/nginx/server/1.27.3/conf/ssl/default.pem https://alist.nuoyis.net/d/blog/nuoyis-lnmp-np/%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6/v1.30/ssl/default.pem && \
curl -L -o /nuoyis-web/nginx/server/1.27.3/conf/ssl/default.key https://alist.nuoyis.net/d/blog/nuoyis-lnmp-np/%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6/v1.30/ssl/default.key && \
curl -L -o /nuoyis-web/nginx/server/1.27.3/conf/start-php-84.conf https://alist.nuoyis.net/d/blog/nuoyis-lnmp-np/%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6/v1.30/start-php-84.conf.txt && \
curl -L -o /nuoyis-web/nginx/server/1.27.3/conf/path.conf https://alist.nuoyis.net/d/blog/nuoyis-lnmp-np/%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6/v1.30/path.conf.txt && \
curl -L -o /nuoyis-web/nginx/server/1.27.3/conf/start-php-81.conf https://alist.nuoyis.net/d/blog/nuoyis-lnmp-np/%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6/v1.30/start-php-81.conf.txt && \
curl -L -o /nuoyis-web/php/8.4.2/etc/php.ini https://alist.nuoyis.net/d/blog/nuoyis-lnmp-np/%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6/v1.30/84php.ini.txt && \
curl -L -o /nuoyis-web/php/8.4.2/etc/php-fpm.d/fpm.conf https://alist.nuoyis.net/d/blog/nuoyis-lnmp-np/%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6/v1.30/fpm-84.conf.txt && \
curl -L -o /nuoyis-web/php/8.1.31/etc/php.ini https://alist.nuoyis.net/d/blog/nuoyis-lnmp-np/%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6/v1.30/81php.ini.txt && \
curl -L -o /nuoyis-web/php/8.1.31/etc/php-fpm.d/fpm.conf https://alist.nuoyis.net/d/blog/nuoyis-lnmp-np/%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6/v1.30/fpm-81.conf.txt && \
curl -L -o /etc/supervisord.conf https://alist.nuoyis.net/d/blog/nuoyis-lnmp-np/%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6/v1.30/supervisord.conf.txt
# 暴露端口
EXPOSE 80 443
# 设置容器的入口点
ENTRYPOINT ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"]
docker-compose编写
version: '2.32.2'
services:
nuoyis-lnmp-np:
container_name: nuoyis-lnmp-np
image: swr.cn-north-4.myhuaweicloud.com/nuoyis/nuoyis-lnp:v1.32
networks:
nuoyis-net:
aliases:
- nuoyis-lnp
ports:
- 80:80
- 443:443
volumes:
- /nuoyis-web/nginx/conf:/nuoyis-web/nginx/conf
- /nuoyis-web/nginx/webside:/nuoyis-web/nginx/webside
- /nuoyis-web/nginx/ssl:/nuoyis-web/nginx/ssl
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost"]
interval: 30s
retries: 3
start_period: 10s
timeout: 10s
restart: always
nuoyis-lnmp-mariadb:
container_name: nuoyis-lnmp-mariadb
image: mariadb:latest
networks:
nuoyis-net:
aliases:
- nuoyis-mariadb
environment:
TIME_ZONE: Asia/Shanghai
MYSQL_ROOT_PASSWORD: ""
volumes:
- /nuoyis-web/mariadb/init/init.sql:/docker-entrypoint-initdb.d/init.sql
- /nuoyis-web/mariadb/server:/var/lib/mysql
- /nuoyis-web/mariadb/import:/nuoyis-web/mariadb/import
- /nuoyis-web/mariadb/config/my.cnf:/etc/mysql/my.cnf
ports:
- 3306:3306
healthcheck:
test: ["CMD", "sh", "-c", "mariadb -u root -p$$MYSQL_ROOT_PASSWORD -e 'SELECT 1 FROM information_schema.tables LIMIT 1;'"]
interval: 30s
retries: 3
start_period: 10s
timeout: 10s
restart: always
nuoyis-lnmp-autoheal:
container_name: nuoyis-lnmp-autoheal
image: willfarrell/autoheal
environment:
- AUTOHEAL_CONTAINER_LABEL=all
volumes:
- /var/run/docker.sock:/var/run/docker.sock
restart: always
networks:
nuoyis-net:
driver: bridge
ipam:
driver: default
config:
- subnet: 192.168.223.0/24
gateway: 192.168.223.1
nuoyis-app(常用软件) docker-compose
version: '2.32.2'
services:
nuoyis-app-alist:
container_name: alist
image: xhofe/alist:latest
volumes:
- /nuoyis-server/alist/data:/opt/alist/data
ports:
- 5244:5244
environment:
- PUID=0
- PGID=0
- UMASK=022
restart: always
nuoyis-app-qinglong:
container_name: qinglong
image: whyour/qinglong:debian
volumes:
- /nuoyis-server/qinglong/data:/ql/data
ports:
- 5700:5700
environment:
QlBaseUrl: '/'
restart: always
nuoyis-app-certd:
image: registry.cn-shenzhen.aliyuncs.com/handsfree/certd:latest
container_name: certd
ports:
- 7001:7001
- 7002:7002
volumes:
- /data/certd:/app/data
labels:
com.centurylinklabs.watchtower.enable: "true"
environment:
- certd_system_resetAdminPasswd=false
restart: always
脚本类
自动化目录检测
安装软件
yum install rsync inotify -y
修改rsync配置文件/etc/rsyncd.conf
[nuoyis-backup]
log file = /var/log/rsync.log
path = /nuoyis-web/nginx
uid = root
gid = root
脚本配置
#!/bin/bash
SOURCE_DIR="/nuoyis-web/nginx"
TARGET_DIR="root@ip::nuoyis-backup"
inotifywait -m -e modify -e create -e delete -r "$SOURCE_DIR" | while read path action file; do
echo "文件变化:$action 文件: $file"
rsync -az --delete "$SOURCE_DIR/" "$TARGET_DIR"
done
自动化(又拍云)SSL上传(配合certd)
#!/usr/bin/env python
# -*-coding:utf-8-*-
import logging
import sys
from requests import Session
from time import time, sleep
"""
@ author:wenjun
@ E-mail: hi@awen.me
@ datetime:2020/10/27 6:34 上午
@ software: PyCharm
@ filename: migrate_upyun_certificate.py
"""
class MigrateUpyunCertificate:
def __init__(self):
self.session = Session()
self.logger = logging.getLogger("upyun")
formatter = logging.Formatter('%(asctime)s %(levelname)-8s: %(message)s')
# 文件日志
file_handler = logging.FileHandler("upyun.log")
file_handler.setFormatter(formatter) # 可以通过setFormatter指定输出格式
# 控制台日志
console_handler = logging.StreamHandler(sys.stdout)
console_handler.formatter = formatter # 也可以直接给formatter赋值
# 为logger添加的日志处理器
self.logger.addHandler(file_handler)
self.logger.addHandler(console_handler)
# 指定日志的最低输出级别,默认为WARN级别
self.logger.setLevel(logging.INFO)
def login(self, username, password):
"""
登录又拍云
:param username:
:param password:
:return:
"""
url = "https://console.upyun.com/accounts/signin/"
payload = {"username": username, "password": password}
headers = {
'Accept': "application/json, text/plain, */*",
'Accept-Encoding': "gzip, deflate, br",
'Accept-Language': "zh-CN,zh;q=0.9,en;q=0.8",
'Cache-Control': "no-cache",
'Connection': "keep-alive",
'Content-Type': "application/json",
'DNT': "1",
'Host': "console.upyun.com",
'Origin': "https://console.upyun.com",
'Pragma': "no-cache",
'Referer': "https://console.upyun.com/login/",
'User-Agent': "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) "
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36",
'cache-control': "no-cache",
'Postman-Token': "2d9bd080-b549-4c41-89ce-0b011f344a3f"
}
response = self.session.post(url, json=payload, headers=headers)
if response.status_code == 200:
return response.cookies
def get_ssl_list(self):
"""
获取SSL 列表
:return:
"""
url = "https://console.upyun.com/api/https/certificate/list/?limit=10"
headers = {
'Accept': 'application/json, text/plain, */*',
'Accept-Encoding': 'gzip, deflate, br',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'DNT': '1',
'Host': 'console.upyun.com',
'Pragma': 'no-cache',
'Referer': 'https://console.upyun.com/toolbox/ssl/',
'Sec-Fetch-Dest': 'empty',
'Sec-Fetch-Mode': 'cors',
'Sec-Fetch-Site': 'ame-origin',
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36'
'(KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36'
}
response = self.session.get(url, headers=headers)
if response.status_code == 200:
resp_json = response.json()
result = resp_json["data"]["result"]
return result
@staticmethod
def format_result_info(result_json, check_domain):
"""
格式化输出cer_id 以及到期时间等信息
:param check_domain:
:param result_json:
:return:
"""
cer_list = []
for key, value in result_json.items():
cer_id = key
if len(key) != 32:
continue
common_name = value["commonName"]
validity_end = value["validity"]["end"]
if common_name != check_domain:
continue
data = {
"cer_id": cer_id,
"domain": common_name,
"validity_end": validity_end
}
cer_list.append(data)
return cer_list
def upload_cerfile(self, certificate_path, private_key_path):
"""
上传证书
:param private_key_path:
:param certificate_path:
:return:
"""
with open(certificate_path) as f:
certificate_str = f.read()
with open(private_key_path) as k:
private_key_str = k.read()
url = "https://console.upyun.com/api/https/certificate/"
payload = {"certificate": certificate_str.strip("\n"),
"private_key": private_key_str.strip("\n")
}
headers = {
'Accept': 'application/json, text/plain, */*',
'Accept-Encoding': 'zip, deflate, br',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'content-type': 'application/json',
'DNT': '1',
'Host': 'console.upyun.com',
'Origin': 'https://console.upyun.com',
'Pragma': 'no-cache',
'Referer': 'https://console.upyun.com/toolbox/ssl/',
'Sec-Fetch-Dest': 'empty',
'Sec-Fetch-Mode': 'cors',
'Sec-Fetch-Site': 'same-origin',
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 '
'(KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36'
}
response = self.session.post(url, headers=headers, json=payload)
if response.status_code == 200:
resp_json = response.json()
common_name = resp_json["data"]["result"]["commonName"]
certificate_id = resp_json["data"]["result"]["certificate_id"]
validity_start = resp_json["data"]["result"]["validity"]["start"]
validity_end = resp_json["data"]["result"]["validity"]["end"]
data = {
"common_name": common_name,
"certificate_id": certificate_id,
"validity_start": validity_start,
"validity_end": validity_end
}
return data
def migrate_certificate(self, new_cer_id, old_cer_id):
"""
证书迁移
:param new_cer_id:
:param old_cer_id:
:return:
"""
url = "https://console.upyun.com/api/https/migrate/certificate"
payload = {"old_crt_id": old_cer_id, "new_crt_id": new_cer_id}
headers = {
'Accept': 'application/json, text/plain, */*',
'Accept-Encoding': 'gzip, deflate, br',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'content-type': 'application/json',
'DNT': '1',
'Host': 'console.upyun.com',
'Origin': 'https://console.upyun.com',
'Pragma': 'no-cache',
'Referer': 'https://console.upyun.com/toolbox/ssl/',
'Sec-Fetch-Dest': 'empty',
'Sec-Fetch-Mode': 'cors',
'Sec-Fetch-Site': 'same-origin',
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 '
'(KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36'
}
response = self.session.post(url, headers=headers, json=payload)
if response.status_code != 200:
return False
resp_json = response.json()
if resp_json["data"]["result"]:
result_data = resp_json["data"]["result"]
self.logger.info(f"证书迁移结果 {result_data}")
return True
def delete_certificate(self, certificate_id, by_time):
"""
删除旧的证书
:param by_time:
:param certificate_id:
:return:
"""
if by_time >= 1:
self.logger.info("当前证书大于 2天,无需删除")
return
self.logger.info("小于 1 天,开始删除旧证书")
url = "https://console.upyun.com/api/https/certificate/?certificate_id={}".format(certificate_id)
headers = {
'Accept': 'application/json, text/plain, */*',
'Accept-Encoding': 'gzip, deflate, br',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'DNT': '1',
'Host': 'console.upyun.com',
'Origin': 'https://console.upyun.com',
'Pragma': 'no-cache',
'Referer': 'https://console.upyun.com/toolbox/ssl/',
'Sec-Fetch-Dest': 'empty',
'Sec-Fetch-Mode': 'cors',
'Sec-Fetch-Site': 'same-origin',
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) '
'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36'
}
response = self.session.delete(url, headers=headers)
if response.status_code != 200:
self.logger.info("证书删除失败,连接异常")
resp_json = response.json()
try:
if resp_json["data"]["status"]:
self.logger.info("证书删除成功")
except KeyError:
self.logger.info("证书删除失败")
@staticmethod
def read_acme_conf(conf_path, unix_time):
with open(conf_path) as f:
for i in (f.readlines()):
key = i.strip().split("=")
if key[0] == "Le_NextRenewTime":
le_next_renew_time = str(key[1]).replace("'", "")
return int(int(le_next_renew_time) - unix_time) / 60 / 60 / 24
def main(self):
"""############# 配置信息段 #############"""
username = "" # 又拍云用户名,必填
password = "" # 又拍云密码,必填
check_domain = "nuoyis.net" # 要配置的证书,避免误删其他过期证书,必填
certificate_path = "/nuoyis-web/nginx/ssl/nuoyis.net.pem" # 证书公钥,建议配置待根证书的证书内容,否则在部分浏览器可能会出现问题。必填
private_key_path = "/nuoyis-web/nginx/ssl/nuoyis.net.key" # 证书私钥,必填
"""############# 配置信息段 #############"""
unix_time = int(time())
self.logger.info("开始登录又拍云")
self.login(username=username, password=password)
self.logger.info("开始获取证书列表")
result_json = self.get_ssl_list()
cer_list = self.format_result_info(result_json, check_domain)
old_cer_id = cer_list[-1]["cer_id"]
validity_end = cer_list[-1]["validity_end"]
now_unix = unix_time * 1000
by_time = int((int(validity_end) - now_unix) / 1000 / 60 / 60 / 24)
self.logger.info(f"当前时间 {now_unix}, 证书截止时间 {validity_end} 剩余时间 {by_time} 天")
if by_time >= 1:
self.logger.info("当前证书大于 2天,无需操作")
return
self.logger.info("开始读取本地证书公钥和私钥信息")
self.logger.info("开始上传证书")
upload_cerfile_info = self.upload_cerfile(certificate_path=certificate_path,
private_key_path=private_key_path)
new_cer_id = upload_cerfile_info["certificate_id"]
self.logger.info("开始迁移证书")
self.migrate_certificate(new_cer_id=new_cer_id, old_cer_id=old_cer_id)
sleep(5)
self.logger.info(f"开始删除已过期的 {check_domain} 证书,sold_cer_id {old_cer_id},by_time {by_time}")
self.delete_certificate(old_cer_id, by_time)
if __name__ == '__main__':
migrate_upyun_certificate = MigrateUpyunCertificate()
migrate_upyun_certificate.main()