个人习惯在windows上申请证书,因为直接点击我写的申请脚本就可以了,一句命令行都不用输,非常方便。之前用bat脚本写的并不是很好用,现在用powershell来重构一下,顺便增添些新功能。顺带一提,powershell的脚本文件后缀名是“.ps1”。想要运行外部powershell脚本需要先修改本地的安全策略,默认是禁止运行的。

证书申请流程

   一般来说我们都会选择申请“主域+通配符子域”的形式,拿我这个博客示例,就是申请“cctv.moe + *.cctv.moe”。这种方式只能用DNS验证域名所有权,就是在主域上添加TXT记录,然后certbot验证这条DNS记录,通过了就给你发证书。


   有时候我们不是完全持有某个域名,比如从某宝买的“二级不死”域名,一般来说是企业备案,可以自由挑选阿里、腾讯等备案方,针对我这种懒得自己备案的人来说,这也是一个非常不错的方式。我买的只需要50块钱一年,这成本真的非常低了。


   但是这些商家提供的DNS解析服务就有亿些鸡肋了,比如我买的就限制所有DNS记录只能有一条,但有时候certbot要求添加两条TXT记录。这时候就只能选择HTTP方式验证域名所有权了,就是将域名解析到自己的服务器,然后certbot访问网址,服务器返回指定字符串,这样就能验证通过了。当然这种验证方式不能申请通配符证书,门槛也有些高,之后我也许会出Nginx配置HTTP验证的教程。

证书申请脚本

   回到正题,现在贴出我的powershell证书申请脚本。首先安装certbot(点击跳转Github下载页)。脚本上面的变量需要你自己更改,代码复制到记事本之后保存编码一定要选择“UTF-8 BOM”,然后把文件后缀名从.txt改成.ps1:

#手动设置要申请证书的域名数组
[String[]]$hostInputArr = @(
    "cctv.moe",
    "cheap.pp.ua"
)

#手动设置certbot的exe目录
[String]$certbotPath = "C:\Program Files\Certbot\bin\certbot.exe"

#手动设置是否要申请通配符子域(1:不申请、2:申请)
[int]$pathDepth = 2

#手动设置域名验证方式(1:HTTP、2:DNS)
[int]$verifyMethod = 2

@'
#############################################################################
#                              Power By FLAAC3                              #
#/ᐠ。ꞈ。ᐟ\                    https://blog.cctv.moe                    /ᐠ。ꞈ。ᐟ\#
#                         https://github.com/FLAAC3                         #
#############################################################################
'@ | Write-Host

#脚本全路径
[String]$scriptPath = $MyInvocation.MyCommand.Path

class MyHost {
    [System.Collections.Generic.List[string]]$hostList
    MyHost ([string]$hostStr) {
        $this.hostList = [System.Collections.Generic.List[string]]::new()
        foreach ($i in 1..$script:pathDepth) {
            $this.hostList.Add($hostStr)
            $hostStr = "*." + $hostStr
        }
    }
    [string]ToString() {
        return [string]::Join("、", $this.hostList)
        }
    [System.Collections.Generic.List[string]]GetCertbotCmd () {
        $commandList = [System.Collections.Generic.List[string]]::new()
        $commandList.AddRange([string[]]@(
            "certonly",
            "--manual",
            "--agree-tos",
            "--preferred-challenges"
        ))
        if ($script:verifyMethod -eq 1) {
            $commandList.Add("http")
        } else {
            $commandList.Add("dns")
        }
        foreach ($hostStr in $this.hostList) {
            $commandList.Add("-d")
            $commandList.Add($hostStr)
        }
        return $commandList
    }
}

#检查是否用管理员权限打开
function Test-IsAdmin {
    return (net session 2>$null) -ne $null
}

#转换域名数组
function Get-Host-List {
    $hostList = [System.Collections.Generic.List[MyHost]]::new()
    foreach ($hostStr in $hostInputArr) {
        $hostList.Add([MyHost]::new($hostStr))
    }
    return $hostList
}

#选择域名
function Select-Host ([System.Collections.Generic.List[MyHost]]$hostList) {
    Write-Host "输入要申请SSL证书的域名编号:"
    for ($i = 1; $i -le $hostList.Count; $i++) {
        Write-Host $("{0}) " -f $i) -NoNewline -ForegroundColor green
        Write-Host $($hostList[$i - 1])
    }
    while ($true) {
        [int]$id = 0
        [int]::TryParse((Read-Host), [ref]$id) > $null
        if ($id -ge 1 -and $id -le $hostList.Count) {
            return $id - 1
        } else {
            Write-Host 输入有误!请重新输入! -ForegroundColor red
        }
    }
}

if (!$(Test-IsAdmin)) {
    Start-Process powershell -Verb runAs -ArgumentList @(
        "-NoProfile", #禁止加载所有PS配置文件
        "-ExecutionPolicy", "Bypass",
        "-file", $scriptPath
    )
    exit 0
}
$hostList = Get-Host-List
$index = Select-Host $hostList
while ($true) {
      & $certbotPath $hostList[$index].GetCertbotCmd()
    Write-Host `n脚本运行结束,按空格重新申请当前域名,按回车退出 -ForegroundColor green
    $key = [System.Console]::ReadKey($true)
    if ($key.Key -ne [System.ConsoleKey]::Spacebar) { break }
}

脚本运行截图:

   各位如果觉得有用请点击下方的打赏,扫描二维码给我投币,创作不易,感谢支持!