底层技术: 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

欧拉觉得速度慢可以换华为源

1
sed -i "s/repo.openeuler.org/mirrors.huaweicloud.com\/openeuler/g" /etc/yum.repos.d/openEuler.repo
1
sed -i "s/metalink/#metalink/g" /etc/yum.repos.d/openEuler.repo

首先安装基础环境

1
yum install vim* bash* net-tools wget -y

Docker安装(用于构建docker镜像)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 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

修改内核参数

1
2
3
4
5
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

生效内核参数

1
sysctl -p

Docker加速器/网络地址配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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安装

1
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编写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
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编写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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

脚本类

自动化目录检测

安装软件

1
yum install rsync inotify -y

修改rsync配置文件/etc/rsyncd.conf

1
2
3
4
5
[nuoyis-backup]
log file = /var/log/rsync.log
path = /nuoyis-web/nginx
uid = root
gid = root

脚本配置

1
2
3
4
5
6
7
8
9
#!/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)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
#!/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()

数据库配置区域

https://blog.nuoyis.net/posts/dcf7.html