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

数据库配置区域

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

最后修改:2025 年 01 月 15 日
如果觉得我的文章对你有用,请随意赞赏