準備が整ったら、PowerShellスクリプトを用意します。
下記の例で作成するスクリプトの前提は二つ
- DigiCertのAPIキーを用いてACMEサーバに証明書発行のリクエストを行います
- DNS-01チャレンジを実行するため、ACMEクライアントにRoute53プラグインを追加し、
三つのスクリプトを用意します
| スクリプト名 | 実行タイミング | 説明 |
| install_teppinet.ps1 (登録スクリプト) | 初回だけ | WinACME実行環境に、teppi.netドメインの証明書取得環境をセットアップします |
| postinstall_teppinet.ps1 (配布スクリプト) | 新しいSSL証明書を取得したときにのみ、renewスクリプトから呼ばれて実行 | 所定のフォルダにダウンロードされた証明書を、Webアプリサーバに配布したり(、Webサーバにシグナルを送ってリロードを促したり)します。 |
install_teppinet.ps1 ー 登録スクリプト
まずは、登録クリプト(install_teppinet.ps1)を作成し、PowerShellで実行しつつデバッグします。APIキーなどが正しければ、登録が成功します。登録が一度成功すると、WinACME実行環境が更新に必要な各種接続情報を記憶してくれます。
与えられたACMEサーバに、EabKeyIdとEabHmacKeyで接続し、DNS-01チャレンジに AWS Route53を用いて(APIキーで接続して)応答する設定を登録する場合の例となります。
最初は、配布スクリプト(post-install.ps1)を空にしておくか、呼び出し箇所をコメントアウトして実行するとよいでしょう。また、下の例では「#」でコメントアウトされていますが「--verbose」オプションを有効にすると原因がわかりやすくなります。
param(
[string]$WacsPath = "C:\Program Files\WinACME\wacs.exe",
# ACME Serverの接続情報
[string]$AcmeDirectoryUrl = "https://xxx.digicert.com/xxx/xxxx",
[string]$Email = "my@email.address.com",
[string]$EabKid = "XXX 認証局の Key Identifier XXX",
[string]$EabHmacKey = "XXX 認証局の HMAC Key XXX",
# 証明書対象
[string]$Hosts = "teppi.net,*.teppi.net",
[string]$CommonName = "teppi.net",
[string]$FriendlyName = "digicert-teppi-net",
# AWS Route53 接続情報
[string]$Route53AccessKeyId = "XXXXXXXXXX",
[string]$Route53SecretAccessKey = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
# 出力
[string]$PemFilesPath = "E:\teppi\Develop\Env\WinACME\Certs",
[string]$PemFilesName = "teppi.net",
[string]$PostInstallScript = "E:\teppi\Develop\Env\WinACME\Scripts\post-install.ps1"
)
$ErrorActionPreference = "Stop"
if (!(Test-Path $WacsPath)) {
throw "wacs.exe が見つかりません: $WacsPath"
}
if ($EabHmacKey -eq "PUT_DIGICERT_EAB_HMAC_KEY_HERE") {
throw "DigiCert の EAB HMAC key を設定してください。KID だけでは登録できません。"
}
if (!(Test-Path $PemFilesPath)) {
New-Item -ItemType Directory -Path $PemFilesPath -Force | Out-Null
}
$arguments = @(
"--baseuri", $AcmeDirectoryUrl,
"--source", "manual",
"--host", $Hosts,
"--commonname", $CommonName,
"--friendlyname", $FriendlyName,
"--id", $FriendlyName,
"--validation", "route53",
"--route53accesskeyid", $Route53AccessKeyId,
"--route53secretaccesskey", $Route53SecretAccessKey,
"--store", "pemfiles",
"--pemfilespath", $PemFilesPath,
"--pemfilesname", $PemFilesName,
"--installation", "script",
"--script",$PostInstallScript,
"--scriptparameters", " `"{CertCommonName}`"",
"--accepttos",
"--emailaddress", $Email,
"--eab-key-identifier", $EabKid,
"--eab-key", $EabHmacKey,
"--eab-algorithm", "HS256",
# "--verbose",
"--notaskscheduler"
)
Write-Host "Creating DigiCert renewal with Route53 validation..."
& $WacsPath @arguments
if ($LASTEXITCODE -ne 0) {
throw "wacs 実行失敗。ExitCode=$LASTEXITCODE"
}
Write-Host "完了: DigiCert 用 renewal を作成しました。"
日本語テキストを含めた場合、UTF-8 BOMありで保存します。
PowerShellコマンドラインからスクリプトファイルを実行して成功すると、WinACMEは設定を下記のフォルダ・ファイルに保存します。
- WinACMEの本体 wacs.exeがあるカレントフォルダの、settings.json(たとえば C:\Program Files\WinACME\settings.json)にグローバル設定
- C:\ProgramData\win-acme\<設定別フォルダ>(PowerShellを管理者権限で実行した場合)に、個別ACMサーバ用の設定(アカウントキー情報など)
デバッグで行き詰ったら上記の設定をクリアしてやり直しましょう。
初回実行は、うまくいくと、こんな感じになります
PS E:\teppi\Develop\Env\WinACME\Scripts> .\install-wwwteppinet.ps1
Creating DigiCert renewal with Route53 validation.-
A simple Windows ACMEv2 client (WACS)
Software version 2.2.9.1701 (release, pluggable, standalone, 64-bit)
Connecting to https://xxx.digicert.com/xxx...
Connection OK!
Scheduled task not configured yet
Please report issues at https://github.com/win-acme/win-acme
Running in mode: Unattended
Source generated using plugin Manual: teppi.net and 1 alternatives
Overwriting previously created renewal
Plugin Manual generated source teppi.net with 2 identifiers
Plugin Single created 1 order
Renewing digicert-teppi-net
Using cache for digicert-teppi-net. To get a new certificate within 1 days, run with --nocache.
Store with PemFiles...
Exporting .pem files to E:\teppi\Develop\Env\WinACME\Certs
Installing with Script...
Script E:\teppi\Develop\Env\WinACME\Scripts\post-install.ps1 starting with parameters teppi.net
Script finished
Next renewal due after 2026/5/11
Certificate digicert-teppi-net created
完了: DigiCert 用 renewal を作成しました。
更新のスケジュール
登録が一度成功すると、WinACME実行環境が更新に必要な各種接続情報を記憶してくれます。二度目以降は、登録名をキーにACMEクライアントを呼び出すだけです。
WinACMEを使う場合下記のコマンドで、Windowsタスクスケジューラにジョブを登録してくれます。
C:\Windows\System32>"C:\Program Files\WinACME\wacs.exe" --setuptaskscheduler --baseuri "https://xxx.digicert.com/xxxxx"
Found 2 files older than 120 days in C:\ProgramData\win-acme\one.digicert.commpkiapiv1acmev2directory\Certificates, enable Cache.DeleteStaleFiles in settings.json to automatically delete these on each run.
A simple Windows ACMEv2 client (WACS)
Software version 2.2.9.1701 (release, pluggable, standalone, 64-bit)
Connecting to https://xxx.digicert.com/xxxxx...
Connection OK!
Scheduled task not configured yet
Please report issues at https://github.com/win-acme/win-acme
Adding Task Scheduler entry with the following settings
- Name win-acme renew (one.digicert.commpkiapiv1acmev2directory)
- Path C:\Program Files\WinACME
- Command wacs.exe --renew --baseuri "https://xxx.digicert.com/xxxxx"
- Start at 09:00:00
- Random delay 04:00:00
- Time limit 02:00:00
登録されるジョブの名前は自動で付与されますが、「win-acme renew ( BaseUriで与えたACMEサーバのホスト名)」という形式になります。
同じACMEサーバで、複数ドメインのSSL証明書発行をリクエストするよう登録している場合も、タスク登録は一つだけで十分です。
登録されたタスクの実行頻度はデフォルトで毎日となります。実際には、取得済の証明書の有効期限が一定以上(デフォルトでは残り1/3以上)残っている場合には、サーバにリクエストを行わずにすぐに処理が完了しますので、毎日実行しても構いません。
実行結果のログは、WinACMEのデータフォルダの設定別フォルダ以下の「Log」フォルダ(C:\ProgramData\win-acme\<設定別フォルダ>\Logなど)に書き出されます。
postinstall_teppinet.ps1 (配布スクリプト)
登録スクリプト(install_xxx.ps1)や、更新スクリプト(renew_xxx.ps1)を実行すると、初めて実行した際には必ず証明書のダウンロードが発生します。
しかし、短い間隔で繰り返し実行した場合に、毎度毎度証明書を生成しなおすのは無駄であるため、前回の証明書の有効期間が十分に(デフォルトでは残り期間が1/3以上)残っている場合には処理がスキップされます。
一方で、実際に新しい証明書が発行された場合には、新しい証明書を各Webアプリケーションの実行環境に配布する必要があります。これを実行するのが配布スクリプト(Post Install Script)で、あらかじめ登録スクリプトで登録しておいたスクリプトが、必要に応じて(実際の証明書発行が行われたときに)ACMEクライアント(wacs.exeなど)によって呼び出されます。
配布スクリプトの役割は、通常は下記の二つとなります
- Webサーバ・アプリケーションサーバを対象とする場合は、アプリケーションサーバが参照する所定の場所に、新しい証明書ファイルをコピーする
(基本的には単なるファイルのコピーです。対象サーバが外部マシンだったらリモートコピー。外部UNIX/Linuxマシンの場合には、接続情報を記憶して実行する必要があります) - Webサーバ・アプリケーションサーバを再起動したり、シグナルなどの通知を行って、証明書のリロードを促す
証明書ファイル
install_xxx.ps1で、wacs.exeに --store pemfilesオプションを付与しているため、証明書保存フォルダには下記のようなファイルが作成されます。

chain-onlyが中間証明書、crtがサーバ証明書で、これを結合したものんがchain です。keyが秘密鍵
--storeオプションを変えることでpfxファイル(PKCS#12形式など)も作成できます。
これをコピーします。
配布スクリプトの例(一部)
- WindowsサーバへのコピーはPowerShellスクリプトで普通に実行できるでしょう。
# ローカルでコピーする例
Copy-Item -Path "E:\teppi\Develop\Env\WinACME\Certs\*.pem" -Destination "E:\AppData\FileBlog5\Config\Certs"
# WORKGROUPのリモートドライブをマウントして、コピーしてからマウント解除する例
#(あらかじめクレデンシャルファイルを作っておく。同じ実行ユーザで。)
# $cred = Get-Credential
# $cred | Export-Clixml -Path "E:\teppi\Develop\Env\WinACME\Scripts\cred_demo.xml"
$cred = Import-Clixml -Path "E:\teppi\Develop\Env\WinACME\Scripts\cred_demo.xml"
New-PSDrive -Name DemoCerts `
-PSProvider FileSystem `
-Root "\\demo_private\Certs" `
-Credential $cred
Copy-Item -Path "E:\teppi\Develop\Env\WinACME\Certs\*.pem" -Destination "DemoCerts:\"
Remove-PSDrive DemoCerts
コピー後, サービス再起動をしてもよいでしょうが、再起動してよい時間帯であることをチェックしたうえで行うのがよいでしょう。定期再起動は別途タスクでスケジュールしてもよいかもしれません。
- Linux/Unixサーバにコピーする場合はscpを使うなどの方法があります
- リモートのWebサーバに新しい証明書をリロードするよう通知できます
# xxx.teppi.net (linux) に配布
# あらかじめ最小限の権限を持つユーザ(certcopy)を作成して,sshキーを用意しておきます
scp -i $env:USERPROFILE\.ssh\certcopy *.pem certcopy@xxx.teppi.net:/home/certcopy/incoming/
ssh -i $env:USERPROFILE\.ssh\certcopy certcopy@xxx.teppi.net "sudo /etc/nginx/ssl/install-cert.sh"

