<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>acme.sh  |  takeHo（たけほ）のへなちょこ台帳</title>
	<atom:link href="https://blog.takeho.com/tag/acme-sh/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.takeho.com</link>
	<description>いわゆる自由帳ってところです。</description>
	<lastBuildDate>Tue, 29 Sep 2026 04:16:41 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.6</generator>

<image>
	<url>https://blog.takeho.com/wp-content/uploads/2024/08/icon-150x150.png</url>
	<title>acme.sh  |  takeHo（たけほ）のへなちょこ台帳</title>
	<link>https://blog.takeho.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>証明書の手動更新は、もう限界。acme.shで発行から自動更新まで構築する方法</title>
		<link>https://blog.takeho.com/e6kcp7r7qfz650shpt17buc29wm3yzbm/</link>
					<comments>https://blog.takeho.com/e6kcp7r7qfz650shpt17buc29wm3yzbm/#respond</comments>
		
		<dc:creator><![CDATA[たけほ]]></dc:creator>
		<pubDate>Tue, 29 Sep 2026 10:15:00 +0000</pubDate>
				<category><![CDATA[セキュリティ]]></category>
		<category><![CDATA[ACME]]></category>
		<category><![CDATA[acme.sh]]></category>
		<guid isPermaLink="false">https://blog.takeho.com/?p=2012</guid>

					<description><![CDATA[前回はWindows Server向けのwin-acmeと、Linuxでも使えるlegoを紹介しました。今回は、シェルスクリプトで動くACMEクライアント「acme.sh」を使います。 証明書の期限切れは、利用者には「サ [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>前回はWindows Server向けのwin-acmeと、Linuxでも使えるlegoを紹介しました。今回は、シェルスクリプトで動くACMEクライアント「acme.sh」を使います。</p>



<p>証明書の期限切れは、利用者には「サイトに安全に接続できない」という警告として現れます。「担当者が更新を忘れた」は、訪問者には関係ありません。証明書の有効期間が短くなるほど、手作業で予定表を回す運用は危うくなります。更新担当者の記憶力を最後の防壁にするのは、そろそろやめましょう。</p>



<p>この記事では、Linux上のNginxで公開する <code>example.com</code> を例に、<strong>発行・配置・反映・定期実行の確認</strong>まで進めます。<code>example.com</code> は説明用ドメインです。実行時は管理する実際のドメイン名に置き換えてください。</p>




  <div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-2"><label class="toc-title" for="toc-checkbox-2">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">acme.shとは</a></li><li><a href="#toc2" tabindex="0">発行前の準備</a></li><li><a href="#toc3" tabindex="0">acme.shをインストールする</a></li><li><a href="#toc4" tabindex="0">HTTP-01で証明書を発行する</a></li><li><a href="#toc5" tabindex="0">証明書をNginxへ配置する</a></li><li><a href="#toc6" tabindex="0">自動更新の設定を確認する</a></li><li><a href="#toc7" tabindex="0">よくあるつまずき</a></li><li><a href="#toc8" tabindex="0">まとめ</a></li></ol>
    </div>
  </div>

<h2 class="wp-block-heading"><span id="toc1">acme.shとは</span></h2>



<p>acme.shは、認証局とのACME通信、ドメイン認証、証明書の取得と更新を行うクライアントです。インストール時に定期実行のcronを登録し、更新が必要か毎日確認します。ただし、<strong>取得した証明書をNginxに配置し、更新後に読み直す設定</strong>まで済ませて、初めてサイトの更新が自動化されます。</p>



<p>以下はUbuntu系Linux、Nginx、HTTP-01認証、Let&#8217;s Encryptを例にします。acme.shの初期設定の認証局はバージョンや設定によって異なるため、この記事では明示的に指定します。商用CAのACMEを利用する場合は、提供元のディレクトリURL、アカウント登録方法、認証方式、商品条件に従ってください。</p>



<h2 class="wp-block-heading"><span id="toc2">発行前の準備</span></h2>



<ul class="wp-block-list">
<li><code>example.com</code> のDNSが、このWebサーバを指している。</li>



<li>インターネットから <code>http://example.com/.well-known/acme-challenge/</code> にポート80でアクセスできる。</li>



<li>Nginxの <code>example.com</code> 用サイト設定と、Webルート <code>/var/www/example.com/public</code> を用意している。</li>



<li>管理者が <code>sudo</code> を使える。cron、curl、git、opensslを利用できる。</li>
</ul>



<p>HTTP-01認証では、認証局が指定URLへアクセスします。ロードバランサーやCDNを使う場合は、認証要求が正しいWebルートまで届くようにしてください。ポート80を開けられない環境やワイルドカード証明書では、後述のDNS-01を検討します。</p>



<p>まず、Webルートを用意します。既存サイトであれば、そのサイトの実際のWebルートを使ってください。</p>



<pre class="wp-block-code"><code>sudo mkdir -p /var/www/example.com/public</code></pre>



<p>Nginxには、少なくとも <code>example.com</code> のHTTPリクエストをこのWebルートから配信する設定が必要です。新規サイト向けの最小例です。既存の設定を上書きせず、対象のserverブロックに合わせてください。</p>



<pre class="wp-block-code"><code>server {
    listen 80;
    server_name example.com;
    root /var/www/example.com/public;

    location ^~ /.well-known/acme-challenge/ {
        try_files $uri =404;
    }
}</code></pre>



<p>設定を反映する前に構文を確認します。</p>



<pre class="wp-block-code"><code>sudo nginx -t
sudo systemctl reload nginx</code></pre>



<p><code>nginx -t</code> は設定の検査、<code>reload</code> は稼働中のNginxに設定を読み直させる操作です。認証用ディレクトリへのアクセスがリダイレクトや認証画面に吸い込まれないか、外部ネットワークからも確認しておきます。</p>



<h2 class="wp-block-heading"><span id="toc3">acme.shをインストールする</span></h2>



<p>今回は公式リポジトリから取得し、rootの管理領域へインストールします。メールアドレスはご自身が受信できるものに変えてください。</p>



<pre class="wp-block-code"><code>sudo git clone https://github.com/acmesh-official/acme.sh.git /opt/acme.sh-source
sudo /opt/acme.sh-source/acme.sh --install -m admin@example.com
sudo /root/.acme.sh/acme.sh --version</code></pre>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>コマンド</th><th>役割</th></tr></thead><tbody><tr><td><code>git clone</code></td><td>公式のソースを取得します。</td></tr><tr><td><code>--install -m</code></td><td>acme.shを配置し、アカウント連絡先メールアドレスを設定します。</td></tr><tr><td><code>--version</code></td><td>インストールされた版を確認します。</td></tr></tbody></table></figure>



<p>上記は新規導入例です。<code>/opt/acme.sh-source</code> がすでに存在する場合は、既存の導入状態を確認してください。以降は <code>sudo /root/.acme.sh/acme.sh</code> とフルパスで実行します。インストーラーは通常、日次のcronも登録しますが、後で必ず確認します。</p>



<p>利用する認証局を明示します。</p>



<pre class="wp-block-code"><code>sudo /root/.acme.sh/acme.sh --set-default-ca --server letsencrypt</code></pre>



<h2 class="wp-block-heading"><span id="toc4">HTTP-01で証明書を発行する</span></h2>



<pre class="wp-block-code"><code>sudo /root/.acme.sh/acme.sh --issue \
  --server letsencrypt \
  -d example.com \
  -w /var/www/example.com/public</code></pre>



<p><code>--issue</code> は新しい証明書の取得、<code>-d</code> は対象ドメイン、<code>-w</code> はNginxが公開するWebルートです。acme.shが認証用ファイルを一時的に配置し、認証局がHTTP経由で確認します。取得に失敗したら、DNS、ポート80、Webルート、リダイレクト、CDNの経路を順番に確認します。</p>



<p>acme.shの既定はECC鍵です。サーバや連携先にRSA鍵が必要な場合は、要件を確かめたうえで発行時に <code>--keylength 2048</code> などを指定してください。以下の配置例は既定のECC証明書を前提とします。</p>



<h2 class="wp-block-heading"><span id="toc5">証明書をNginxへ配置する</span></h2>



<p>証明書が取得できても、Nginxが古いファイルを読み続ければサイトは更新されません。公開用の配置先を作ります。</p>



<pre class="wp-block-code"><code>sudo mkdir -p /etc/nginx/ssl/example.com</code></pre>



<p>次に、acme.shへ配置先と更新後の再読み込みコマンドを登録します。</p>



<pre class="wp-block-code"><code>sudo /root/.acme.sh/acme.sh --install-cert -d example.com --ecc \
  --key-file /etc/nginx/ssl/example.com/key.pem \
  --fullchain-file /etc/nginx/ssl/example.com/fullchain.pem \
  --reloadcmd "systemctl reload nginx"</code></pre>



<p><code>key.pem</code> は秘密鍵、<code>fullchain.pem</code> はサーバ証明書と中間証明書を含むファイルです。<code>--reloadcmd</code> により、更新後にNginxが新しい証明書を読み込みます。acme.sh内部の <code>~/.acme.sh/</code> にある証明書ファイルをWebサーバから直接参照する運用は避け、必ず <code>--install-cert</code> で公開用のパスへ配置します。秘密鍵は公開ディレクトリに置かず、アクセス権を絞って管理してください。</p>



<p>Nginxの443番ポート用serverブロックに、次の証明書パスを指定します。既存のサイト設定に組み込んでください。</p>



<pre class="wp-block-code"><code>server {
    listen 443 ssl;
    server_name example.com;
    root /var/www/example.com/public;

    ssl_certificate     /etc/nginx/ssl/example.com/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/example.com/key.pem;
}</code></pre>



<pre class="wp-block-code"><code>sudo nginx -t
sudo systemctl reload nginx</code></pre>



<p>Nginxの設定検査が成功してから反映します。初回の <code>--install-cert</code> 時点でまだ443番の設定がなく、再読み込みコマンドが失敗した場合は、443番の設定を完成させたあと、上の <code>--install-cert</code> を再実行してください。</p>



<h2 class="wp-block-heading"><span id="toc6">自動更新の設定を確認する</span></h2>



<pre class="wp-block-code"><code>sudo crontab -l
sudo /root/.acme.sh/acme.sh --list
sudo /root/.acme.sh/acme.sh --info -d example.com --ecc</code></pre>



<p>cronに <code>acme.sh --cron</code> の行があるか確認します。<code>--list</code> は管理中の証明書、<code>--info</code> は対象ドメインの更新予定や保存された設定の確認に使います。cronが見当たらない場合、インストール時のメッセージやcronの導入状態を確認し、acme.shの公式手順に沿って日次実行を設定してください。<strong>同じ処理のcronを二重登録しないこと</strong>も大切です。</p>



<p>日次実行は「毎日必ず新しい証明書を発行する」という意味ではありません。acme.shが更新の必要性を判定し、必要なときに取得、配置、Nginxの再読み込みを行います。動作確認のために <code>--force</code> を繰り返すと、認証局の発行制限に触れる可能性があります。</p>



<p>実際に利用者へ提示される証明書も確認します。</p>



<pre class="wp-block-code"><code>openssl s_client -connect example.com:443 -servername example.com &lt;/dev/null 2&gt;/dev/null \
  | openssl x509 -noout -subject -issuer -dates</code></pre>



<p><code>-servername</code> はSNIで確認対象のホスト名を指定します。表示された有効期限と発行元が想定どおりかを見てください。<strong>cron登録済み、ファイル更新済み、公開中の証明書更新済み</strong>の3点を確認して、ようやく一連の作業が完了です。期限監視も別途設定しておくと、更新失敗を早期に発見できます。</p>



<h2 class="wp-block-heading"><span id="toc7">よくあるつまずき</span></h2>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>症状</th><th>確認すること</th></tr></thead><tbody><tr><td>HTTP認証に失敗する</td><td>DNSの宛先、ポート80、Webルート、CDN・リダイレクト・認証制限を確認。</td></tr><tr><td>発行されたのにサイトは古い証明書のまま</td><td><code>--install-cert</code> の配置先、Nginxの証明書パス、<code>--reloadcmd</code> の成否を確認。</td></tr><tr><td>定期更新されない</td><td><code>sudo crontab -l</code>、cronサービス、実行ユーザー、acme.shの実行ログを確認。</td></tr><tr><td>ワイルドカードを取得したい</td><td>HTTP-01では取得できません。DNS-01とDNS事業者のAPI連携を検討。</td></tr></tbody></table></figure>



<p>ログを残したい場合は、<code>--cron</code> を実行する設定に <code>--log</code> オプションを付ける方法などがあります。ログの保存先と権限を決め、失敗を検知できるようにしてください。DNS-01を手でTXTレコードを置く方式で実行すると、次回も手作業が必要です。自動更新が目的ならDNS APIに対応した設定を選びます。</p>



<h2 class="wp-block-heading"><span id="toc8">まとめ</span></h2>



<p>証明書の自動化は、コマンド1回で発行して終わりではありません。<strong>認証局から取得する、サーバへ配置する、Webサーバに読み直させる、失敗に気づける</strong>ところまでつながって、初めて運用できます。</p>



<p>「更新日は覚えているはず」という運用は、サイトの信頼を人の記憶に預けています。今日のうちに自動更新の経路を作り、公開中の証明書まで確認しましょう</p>



<div class="wp-block-cocoon-blocks-blogcard blogcard-type bct-none">

<a rel="noopener" href="https://github.com/acmesh-official/acme.sh" title="GitHub - acmesh-official/acme.sh: A pure Unix shell script ACME client for SSL / TLS certificate automation" class="blogcard-wrap external-blogcard-wrap a-wrap cf" target="_blank"><div class="blogcard external-blogcard eb-left cf"><div class="blogcard-label external-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail external-blogcard-thumbnail"><img decoding="async" src="https://opengraph.githubassets.com/6667012c1631ff1ea6b0e8988246afcc81a8b3943e0d1d1c1b1d826a74368a73/acmesh-official/acme.sh" alt="" class="blogcard-thumb-image external-blogcard-thumb-image" width="160" height="90" /></figure><div class="blogcard-content external-blogcard-content"><div class="blogcard-title external-blogcard-title">GitHub - acmesh-official/acme.sh: A pure Unix shell script ACME client for SSL / TLS certificate automation</div><div class="blogcard-snippet external-blogcard-snippet">A pure Unix shell script ACME client for SSL / TLS certificate automation - acmesh-official/acme.sh</div></div><div class="blogcard-footer external-blogcard-footer cf"><div class="blogcard-site external-blogcard-site"><div class="blogcard-favicon external-blogcard-favicon"><img decoding="async" src="https://www.google.com/s2/favicons?domain=https://github.com/acmesh-official/acme.sh" alt="" class="blogcard-favicon-image external-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain external-blogcard-domain">github.com</div></div></div></div></a>
</div>



<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.takeho.com/e6kcp7r7qfz650shpt17buc29wm3yzbm/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
