群晖利用acme.sh自动申请证书并且自动重载证书的问题解决

news2024/12/22 22:03:30

在这里插入图片描述

前言

21年的时候写了一个在群晖(黑群晖)下利用acme.sh自动申请Let‘s Encrypt的脚本工具 群晖使用acme自动申请Let‘s Encrypt证书脚本,自动申请虽然解决了,但是自动重载一直是一个问题,本人也懒,一想到去跟踪重载过程就头大,所以就一直没有更新,每一次证书快过期了,就得手动登陆进去把全部证书的绑定替换两遍,因为在网页端手动更换绑定会触发证书重载的刷新,替换两次是因为第一次换成错的,第二次换成正确的绑定,仅此而已。

虽然拖了几年一直没跟踪这个自动化的实现过程,但是心里始终是有点东西没放下,今天终于解决了!当然解决这个问题的动因还是因为我的公司域名需要加入到以前的脚本当中,本来只是想把脚本做个优化,支持多个账户同时申请,想来想去,一不做二不休,还是一次性把自动重载的过程一起解决了!!!

原理

自动重载的过程分为这么几步:

  • 1、重载使用ssl证书的系统服务
  • 2、重载反向代理的ssl证书
  • 3、重载WebStation的ssl证书
  • 4、特殊处理的系统服务
  • 5、重载web服务

原理介绍

  • 1、重载使用ssl证书的系统服务
    必要的系统服务包括以下几项:
    service_map["DirectoryServer"]="pkgctl-DirectoryServer"
    service_map["MailServer"]="pkgctl-MailServer"
    service_map["ReverseProxy"]="nginx"
    service_map["SynologyDrive"]="pkgctl-SynologyDrive"
    service_map["WebDAVServer"]="pkgctl-WebDAVServer"
    service_map["WebStation"]="pkgctl-WebStation"
    service_map["smbftpd"]="ftpd"
    
    在INFO文件的绑定中,看到的DirectoryServer 服务名,真实调用需要使用的服务名称为pkgctl-DirectoryServer
    重载的命令:
    /usr/syno/sbin/synoservice --reload "pkgctl-DirectoryServer"
    
    其他几项也是同样的,不过多介绍,特殊的服务有1个:WebDAV,这个放到步骤四介绍
  • 2、重载反向代理的ssl证书
    反向代理的重载过程分为两步:
    • 2.1、拷贝证书到反向代理证书存放的目录

      # 复制证书文件
      cp -f "/usr/syno/etc/certificate/_archive/xxxxxx/cert.pem" "/usr/syno/etc/certificate/ReverseProxy/$uuid/cert.pem"
      cp -f "/usr/syno/etc/certificate/_archive/xxxxxx/privkey.pem" "/usr/syno/etc/certificate/ReverseProxy/$uuid/privkey.pem"
      cp -f "/usr/syno/etc/certificate/_archive/xxxxxx/fullchain.pem" "/usr/syno/etc/certificate/ReverseProxy/$uuid/fullchain.pem"
      
    • 2.2、调用反向代理的重载指令

      /usr/libexec/certificate.d/ReverseProxy "$uuid"
      

      ps:$uuid进入到/usr/syno/etc/certificate/ReverseProxy/目录下直接查看文件夹名称就是了,另外INFO的配置信息中也存在有$uuid

  • 3、重载WebStation的ssl证书
    • 3.1 拷贝证书文件到目录:/usr/local/etc/certificate/WebStation/$uuid

      cp -f "/usr/syno/etc/certificate/_archive/xxxxxx/cert.pem" "/usr/local/etc/certificate/WebStation/$uuid/cert.pem"
      cp -f "/usr/syno/etc/certificate/_archive/xxxxxx//privkey.pem" "/usr/local/etc/certificate/WebStation/$uuid/privkey.pem"
      cp -f "/usr/syno/etc/certificate/_archive/xxxxxx//fullchain.pem" "/usr/local/etc/certificate/WebStation/$uuid/fullchain.pem"
      
    • 3.2 重载WebStation证书命令

      /usr/local/libexec/certificate.d/WebStation "$uuid"
      
    ps:vhost类型的$uuid和反向代理类型的$uuid区别就是以vhost_开头
  • 4、特殊处理的系统服务
    WebDAV是一个特殊的服务,和其他系统服务的重载方式不同,如下:
    /var/packages/WebDAVServer/target/scripts/synowebdavserver_httpd_control.sh stop
    sleep 2
    /var/packages/WebDAVServer/target/scripts/synowebdavserver_httpd_control.sh start
    
  • 5、重载web服务
    重启web服务,就看各位使用的是apache还是nginx了,我使用的nginx所以对于apache也没做测试和跟进,有需要的同学抛砖引玉,自行排查一下:
    /usr/syno/sbin/synoservice --reload nginx
    

脚本代码片段

大概过程就是如上几个步骤,有补充的同学请留言,下面是我的代码片段。这次我只放了片段出来,是因为我今天发现我的群晖上的wget不支持https了,就连curl也不能正确使用Tslv1.2库,本来想源码编译openssl库升级一下,结果发现我的设备能安装的gcc版本又太低,无奈之下我又拿golang写了个后端,放到另外一台机器上跑,完整的脚本代码需要配合后端运行,大概的逻辑是:

后端定时任务申请证书并保存且提供api给群晖下载证书 -> 群晖定时任务下载证书到本地 -> 自动部署并重载证书

因为临时抓起来的事情,后端功能仅限于自己使用,我担心安全意识薄弱的同学拿到自己的公网服务器上部署,那就完蛋了。我的部署都在局域网内,像这种不需要对公网开放的服务类项目,够用就行,所以暂时就不发全部的代码到帖子上了,下面这段代码,大家拿去和我21年那篇帖子的代码一结合,我相信就能解决单用户申请ssl证书的需求了。

如果大家强烈要求我发放完整代码的话,可以给我留言。

自动部署并重载ssl证书的代码片段

# 获取脚本所在目录的绝对路径
INFO_DIR="/usr/syno/etc/certificate/_archive"
INFO_FILE="/usr/syno/etc/certificate/_archive/INFO"

# 重新加载证书
ReloadCerts() {
    echo "开始重新加载证书..."
    
    # 定义服务名称映射
    declare -A service_map
    service_map["DirectoryServer"]="pkgctl-DirectoryServer"
    service_map["MailServer"]="pkgctl-MailServer"
    service_map["ReverseProxy"]="nginx"
    service_map["SynologyDrive"]="pkgctl-SynologyDrive"
    service_map["WebDAVServer"]="pkgctl-WebDAVServer"
    service_map["WebStation"]="pkgctl-WebStation"
    service_map["smbftpd"]="ftpd"
    
    # 获取所有需要重载的服务名称
    services=$(jq -r '
        . as $root |
        [
            to_entries[] |
            select(.value.services != null) |
            .value.services[] |
            select(.service != null) |
            .subscriber
        ] | unique[]
    ' "$INFO_FILE")
    
    # 重载每个服务
    for service in $services; do
        if [ "${service_map[$service]}" != "" ]; then
            actual_service="${service_map[$service]}"
            echo "重载服务: $service (${actual_service})"
            if [ -f "/usr/syno/sbin/synoservice" ]; then
                # 尝试重载服务
                /usr/syno/sbin/synoservice --reload "$actual_service" || {
                    echo "尝试重启服务: $actual_service"
                    /usr/syno/sbin/synoservice --restart "$actual_service"
                }
                
                # 如果是 nginx,给它一点时间完成重载
                if [ "$actual_service" = "nginx" ]; then
                    sleep 2
                fi
            fi
        else
            echo "跳过未知服务: $service"
        fi
    done
    
    # 更新并重载反向代理和 vhost 证书
    echo "开始处理反向代理和 vhost 证书..."
    
    # 从 INFO 文件中获取证书和服务的映射关系
    jq -r '
        . as $root |
        to_entries[] |
        select(.value.services != null) |
        .key as $cert_name |
        .value.services[] |
        select(.subscriber == "ReverseProxy" or .subscriber == "WebStation") |
        [$cert_name, .service, .subscriber] |
        @tsv
    ' "$INFO_FILE" | while IFS=$'\t' read -r cert_name service_uuid subscriber; do
        # 跳过空值
        if [ -z "$cert_name" ] || [ -z "$service_uuid" ]; then
            continue
        fi
        
        # 源证书目录
        cert_dir="$INFO_DIR/$cert_name"
        if [[ "$service_uuid" == vhost_* ]] && [ "$subscriber" == "WebStation" ]; then
            # 处理 vhost 证书
            vhost_dir="/usr/local/etc/certificate/WebStation/$service_uuid"
            if [ -d "$cert_dir" ]; then
                echo "更新 vhost 证书 $cert_name 到 UUID: $service_uuid"
                
                # 确保目标目录存在
                mkdir -p "$vhost_dir"
                
                # 复制证书文件
                cp -f "$cert_dir/cert.pem" "$vhost_dir/cert.pem"
                cp -f "$cert_dir/privkey.pem" "$vhost_dir/privkey.pem"
                cp -f "$cert_dir/fullchain.pem" "$vhost_dir/fullchain.pem"
                
                # 设置正确的权限
                chmod 400 "$vhost_dir"/*.pem
                
                # 重载 vhost 证书
                echo "重载 vhost 证书 UUID: $service_uuid"
                /usr/local/libexec/certificate.d/WebStation "$service_uuid"
                sleep 1
            fi
        elif [ "$subscriber" == "ReverseProxy" ]; then
            # 处理反向代理证书
            proxy_dir="/usr/syno/etc/certificate/ReverseProxy/$service_uuid"
            if [ -d "$cert_dir" ] && [ -d "$proxy_dir" ]; then
                echo "更新反向代理证书 $cert_name 到 UUID: $service_uuid"

                # 确保目标目录存在
                mkdir -p "$proxy_dir"
                
                # 复制证书文件
                cp -f "$cert_dir/cert.pem" "$proxy_dir/cert.pem"
                cp -f "$cert_dir/privkey.pem" "$proxy_dir/privkey.pem"
                cp -f "$cert_dir/fullchain.pem" "$proxy_dir/fullchain.pem"
                
                # 设置正确的权限
                chmod 400 "$proxy_dir"/*.pem

                # 重载反向代理证书
                echo "重载反向代理证书 UUID: $uuid"
                /usr/libexec/certificate.d/ReverseProxy "$uuid"
                sleep 1
            fi
        fi
    done
    
    # 检查并重启 WebDAV 服务
    if [ -f "/var/packages/WebDAVServer/scripts/start-stop-status" ]; then
        echo "检查 WebDAV 服务..."
        if /var/packages/WebDAVServer/scripts/start-stop-status status >/dev/null 2>&1; then
            echo "重启 WebDAV 服务..."
            /var/packages/WebDAVServer/target/scripts/synowebdavserver_httpd_control.sh stop
            sleep 2
            /var/packages/WebDAVServer/target/scripts/synowebdavserver_httpd_control.sh start
            
            sleep 2
            if ! /var/packages/WebDAVServer/scripts/start-stop-status status >/dev/null 2>&1; then
                echo "警告:WebDAV 服务可能未正确启动"
            else
                echo "WebDAV 服务已成功重启"
            fi
        else
            echo "WebDAV 服务未运行,跳过重启"
        fi
    fi
    
    # 最后再次重载 nginx 以确保所有更改生效
    if [ -f "/usr/syno/sbin/synoservice" ]; then
        echo "最后重载 nginx 服务..."
        /usr/syno/sbin/synoservice --reload nginx
    fi
    
    echo "证书重新加载完成"
    return 0
}

case "$1" in 
    *)
        ReloadCerts
        ;;
esac

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2263915.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

level2逐笔委托查询接口

沪深逐笔委托队列查询 前置步骤 分配数据库服务器 查询模板 以下是沪深委托队列查询的请求模板&#xff1a; http://<数据库服务器>/sql?modeorder_book&code<股票代码>&offset<offset>&token<token>查询参数说明 参数名类型说明mo…

delve调试环境搭建—golang

原文地址&#xff1a;delve调试环境搭建—golang – 无敌牛 欢迎参观我的个人博客&#xff1a;无敌牛 – 技术/著作/典籍/分享等 由于平时不用 IDE 开发环境&#xff0c;习惯在 linux终端vim 环境下开发&#xff0c;所以找了golang的调试工具&#xff0c;delve类似gdb的调试界…

PC寄存器(Program Counter Register) jvm

在JVM&#xff08;Java虚拟机&#xff09;中&#xff0c;PC寄存器&#xff08;Program Counter Register&#xff09;扮演着至关重要的角色&#xff0c;它是JVM执行引擎的核心组成部分之一。以下是PC寄存器在JVM中的具体角色和职责&#xff1a; 指令执行指针&#xff1a; PC寄存…

线性分类器(KNN,SVM损失,交叉熵损失,softmax)

KNN 工作机制 k-近邻算法的工作机制可以分为两个主要阶段&#xff1a;训练阶段和预测阶段。 训练阶段 在训练阶段&#xff0c;k-近邻算法并不进行显式的模型训练&#xff0c;而是简单地存储训练数据集。每个样本由特征向量和对应的标签组成。此阶段的主要任务是准备好数据&…

重拾设计模式--适配器模式

文章目录 适配器模式&#xff08;Adapter Pattern&#xff09;概述适配器模式UML图适配器模式的结构目标接口&#xff08;Target&#xff09;&#xff1a;适配器&#xff08;Adapter&#xff09;&#xff1a;被适配者&#xff08;Adaptee&#xff09;&#xff1a; 作用&#xf…

StarRocks:存算一体模式部署

目录 一、StarRocks 简介 二、StarRocks 架构 2.1 存算一体 2.2 存算分离 三、前期准备 3.1前提条件 3.2 集群规划 3.3 配置环境 3.4 准备部署文件 四、手动部署 4.1 部署FE节点 4.2 部署BE节点 4.3 部署CN节点&#xff08;可选&#xff09; 4.4 FE高可用…

找数字:JAVA

题目描述 试计算在区间1 到n 的所有整数中&#xff0c;数字x&#xff08;0 ≤ x ≤ 9&#xff09;共出现了多少次&#xff1f; 例如&#xff0c;在1到11 中&#xff0c;即在1、2、3、4、5、6、7、8、9、10、11 中&#xff0c;数字1 出现了4 次。 输入描述: 输入共1行&#xf…

AI的使用:结构化提示词

根据自己的使用&#xff0c;不断的完善自己的提示词。并且像程序版本一样管理和迭代自己的提示词&#xff0c;这样才能准确的按照自己的目的去使用AI。而为了更好的管理&#xff0c;我们在一开始使用的时候&#xff0c;就要有一个易于管理的定义&#xff0c;即&#xff1a;结构…

Netcat:网络中的瑞士军刀

免责声明&#xff1a;使用本教程或工具&#xff0c;用户必须遵守所有适用的法律和法规&#xff0c;并且用户应自行承担所有风险和责任。 文章目录 一、引言二、简述三、Netcat功能&#xff1f;四、参数选项五、Netcat 的常见功能六、高级用法多连接处理创建简单的代理 七、Netc…

VS Code Copilot 与 Cursor 对比

选手简介 VS Code Copilot&#xff1a;算是“老牌”编程助手了&#xff0c;虽然Copilot在别的编辑器上也有扩展&#xff0c;不过体验最好的还是VS Code&#xff0c;毕竟都是微软家的所以功能集成更好一些&#xff1b;主要提供的是Complete和Chat能力&#xff0c;也就是代码补全…

28、基于springboot的房屋租赁系统

房屋是人类生活栖息的重要场所&#xff0c;随着城市中的流动人口的增多&#xff0c;人们对房屋租赁需求越来越高&#xff0c;为满足用户查询房屋、预约看房、房屋租赁的需求&#xff0c;特开发了本基于Spring Boot的房屋租赁系统。 本文重点阐述了房屋租赁系统的开发过程&…

【Qt】显示类控件:QLabel、QLCDNumber、QProgressBar、QCalendarWidget

目录 QLabel QFrame 例子&#xff1a; textFormat pixmap、scaledContents alignment wordWrap、indent、margin buddy QLCDNumber 例子&#xff1a; QTimer QProgressBar 例子&#xff1a; QCalendarWidget 例子&#xff1a; QLabel 标签控件&#xff0c;用来显示…

基于STM32的自学习智能小车设计

目录 引言系统设计 硬件设计软件设计系统功能模块 传感器模块控制模块自学习算法模块系统实现 硬件实现软件实现测试与优化结论与展望 1. 引言 随着人工智能和机器学习技术的不断发展&#xff0c;越来越多的智能小车开始实现自主学习与行为决策。传统的智能小车通常依靠固定的…

Android OpenGLES2.0开发(九):图片滤镜

“当你改变想法的时候&#xff0c;记得也要改变你的世界。”——诺曼文森特皮尔 Android OpenGLES开发&#xff1a;EGL环境搭建Android OpenGLES2.0开发&#xff08;一&#xff09;&#xff1a;艰难的开始Android OpenGLES2.0开发&#xff08;二&#xff09;&#xff1a;环境搭…

梳理你的思路(从OOP到架构设计)_简介设计模式

目录 1、 模式(Pattern) 是较大的结构​编辑 2、 结构形式愈大 通用性愈小​编辑 3、 从EIT造形 组合出设计模式 1、 模式(Pattern) 是较大的结构 组合与创新 達芬奇說&#xff1a;簡單是複雜的終極形式 (Simplicity is the ultimate form of sophistication) —Leonardo d…

vscode的keil assistant 中搜索不到全局变量

搜不到 但是在包含的文件中输入 ../../../,就是全局搜索的结果 我的文件结构是&#xff1a;\Desktop\LVGL文件系统移植&#xff08;lvgl8&#xff0e;&#xff13;&#xff09;\Projects\MDK-ARM 盲猜是keil assistant 当前文件夹打开的时候是进入到了MDK-ARM文件夹层次&…

HTML语法规范

HTML语法规则 HTML 标签是由尖括号包围的关键词&#xff0c;标签通常是成对出现的&#xff0c;例如 <html> 和 </html>&#xff0c;称为双标签 。标签对中的第一个标签是开始标签&#xff0c;第二个标签是结束标签单标签比较少&#xff0c;例如<br />&#x…

flink实现复杂kafka数据读取

接上文&#xff1a;一文说清flink从编码到部署上线 环境说明&#xff1a;MySQL&#xff1a;5.7&#xff1b;flink&#xff1a;1.14.0&#xff1b;hadoop&#xff1a;3.0.0&#xff1b;操作系统&#xff1a;CentOS 7.6&#xff1b;JDK&#xff1a;1.8.0_401。 常见的文章中&…

大模型微调---Prompt-tuning微调

目录 一、前言二、Prompt-tuning实战2.1、下载模型到本地2.2、加载模型与数据集2.3、处理数据2.4、Prompt-tuning微调2.5、训练参数配置2.6、开始训练 三、模型评估四、完整训练代码 一、前言 Prompt-tuning通过修改输入文本的提示&#xff08;Prompt&#xff09;来引导模型生…

如何使用 WebAssembly 扩展后端应用

1. WebAssembly 简介 随着互联网的发展&#xff0c;越来越多的应用借助 Javascript 转到了 Web 端&#xff0c;但人们也发现&#xff0c;随着移动互联网的兴起&#xff0c;需要把大量的应用迁移到手机端&#xff0c;随着手端的应用逻辑越来越复杂&#xff0c;Javascript 的解析…