Labee Dev Toolbox
技術ノートガイド用語解説
無料で試す
  1. ホーム
  2. / 技術ノート
  3. / GitHub Actions で DNS・SSL・メール認証を定期チェックする CI ワークフローの作り方
CI/CD

GitHub Actions で DNS・SSL・メール認証を定期チェックする CI ワークフローの作り方

2026年4月19日 公開 2026年4月19日 更新 8分で読めます

DNS レコード、SSL 証明書の到達性、メール認証(SPF・DKIM・DMARC)の設定状態は、デプロイや移行のたびに壊れるリスクがあります。この記事では、dig や openssl を使った CI でのチェック方法と、その制約を補う HTTPS 経由の API 呼び出しを組み合わせて、GitHub Actions で定期的に検証するワークフローの作り方を解説します。

手動チェックの限界と CI 化の動機

DNS レコードの確認は dig、SSL 接続の確認は openssl s_client が標準的な手段です。手元のターミナルからであれば、dig A example.com +short で A レコードを、openssl s_client -connect example.com:443 で SSL 接続をすぐに確認できます。

開発チームで複数のドメインを運用していると、デプロイ後やインフラ変更後に「DNS が正しいか」「HTTPS で到達できるか」「メール認証が欠落していないか」を毎回手動で確認する作業が発生します。ドメインが 5 個以上になると、毎回すべてに対してコマンドを打つのは現実的ではありません。確認の抜け漏れが起き、SSL の到達不能やメール認証の欠落に気づくのが遅れるケースが出てきます。

GitHub Actions の schedule トリガーと workflow_dispatch を組み合わせれば、定期チェックと手動実行の両方に対応できます。以下のセクションでは、DNS・SSL・メール認証のそれぞれについて、dig/openssl を使ったチェック方法を先に紹介し、CI 環境での制約がある場合の代替手段として HTTPS 経由の API を併記します。

DNS レコードのチェック

DNS レコードの確認は dig が最も手軽です。Google Public DNS(8.8.8.8)を指定すれば、ローカルのキャッシュリゾルバーを経由せずに外部の値を取得できます。

result=$(dig +short A example.com @8.8.8.8)
if [ -z "$result" ]; then
  echo "::error::A record not found for example.com"
  exit 1
fi
echo "A record: $result"

MX や TXT も同様に確認できます。

dig +short MX example.com @8.8.8.8
dig +short TXT example.com @8.8.8.8

CI 環境での制約

この方法は CI 環境から 8.8.8.8 への UDP 53 が通る前提です。GitHub Actions のランナーではファイアウォールで DNS の外部問い合わせがブロックされていることがあり、dig がタイムアウトで失敗する場合があります。

UDP 53 がブロックされている環境では、HTTPS 経由で DNS を確認する方法が確実です。Labee Dev Toolbox の DNS API は認証不要で、curl だけで動作します。

result=$(curl -fsS "https://labee.dev/api/dns?domain=example.com&type=A")
count=$(echo "$result" | jq '.data.records.A | length')
if [ "$count" -eq 0 ]; then
  echo "::error::A record not found for example.com"
  exit 1
fi
echo "A record count: $count"
{
  "success": true,
  "data": {
    "domain": "example.com",
    "records": {
      "A": [
        { "address": "203.0.113.1", "ttl": 3600 }
      ]
    }
  },
  "error": null,
  "meta": { "responseTime": 45 }
}

data.records はレコード種別ごとの配列です。レコードが存在しない種別は null で返ります。type パラメーターを省略すると A, AAAA, MX, TXT, NS, CNAME, SOA, CAA の 8 種類を一括取得できます。API キーは不要なので、Secrets の設定なしで動きます。

SSL 到達性のチェック

openssl s_client を使えば、SSL/TLS 接続の確認と証明書の詳細を一度に取得できます。

echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | head -5

接続が成功すれば証明書チェーンの情報が出力されます。CI のステップで使う場合は、終了コードで判定します。

if echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | grep -q "Verify return code: 0"; then
  echo "SSL connection verified"
else
  echo "::error::SSL verification failed for example.com"
  exit 1
fi

証明書の有効期限も取得できます。

expiry=$(echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
  | openssl x509 -noout -enddate | cut -d= -f2)
expiry_epoch=$(date -d "$expiry" +%s)
now_epoch=$(date +%s)
days_left=$(( (expiry_epoch - now_epoch) / 86400 ))
if [ "$days_left" -lt 30 ]; then
  echo "::warning::SSL certificate expires in $days_left days"
fi

CI 環境での制約

openssl s_client はタイムアウトの設定やスクリプトでの終了コード判定が煩雑です。-servername の指定漏れで SNI が効かなかったり、2>/dev/null を忘れて標準エラーがログに混ざるなど、CI スクリプトとしての保守性に課題があります。

「HTTPS で到達できるか」だけを確認したい場合は、Labee Dev Toolbox の SSL API が簡潔です。

result=$(curl -fsS "https://labee.dev/api/ssl-cert?hostname=example.com")
reachable=$(echo "$result" | jq -r '.data.reachable')
status=$(echo "$result" | jq '.data.status')
if [ "$reachable" != "true" ]; then
  echo "::error::HTTPS unreachable for example.com"
  exit 1
fi
echo "HTTPS reachable, status: $status"
{
  "success": true,
  "data": {
    "hostname": "example.com",
    "port": 443,
    "reachable": true,
    "status": 200
  },
  "error": null,
  "meta": { "responseTime": 120 }
}

data.reachable が true なら HTTPS 接続が成功しています。接続に失敗した場合は reachable が false になり、error フィールドにエラー内容が入ります。この API は到達性の確認に特化しているため、証明書の有効期限を監視したい場合は前述の openssl による確認を併用してください。

メール認証のチェック

SPF、DKIM、DMARC はそれぞれ dig で確認できます。

# SPF
dig +short TXT example.com @8.8.8.8 | grep "v=spf1"

# DMARC
dig +short TXT _dmarc.example.com @8.8.8.8

# DKIM(セレクターを指定)
dig +short TXT google._domainkey.example.com @8.8.8.8

CI のステップでは、出力が空かどうかで判定します。

spf=$(dig +short TXT example.com @8.8.8.8 | grep "v=spf1")
if [ -z "$spf" ]; then
  echo "::error::SPF record not found"
  exit 1
fi

dmarc=$(dig +short TXT _dmarc.example.com @8.8.8.8)
if [ -z "$dmarc" ]; then
  echo "::error::DMARC record not found"
  exit 1
fi
echo "SPF: found, DMARC: found"

CI 環境での制約

DNS チェックと同様に、UDP 53 がブロックされている環境では dig が使えません。DKIM は使用しているセレクター名を事前に把握しておく必要があり、セレクターが不明な場合は候補を総当たりで試すスクリプトが必要になります。

Labee Dev Toolbox のメール認証 API を使うと、SPF・DKIM・DMARC・BIMI を 1 回のリクエストで確認できます。DKIM はセレクターを省略すると google, selector1, default など 12 種類のセレクターを自動で試行します。

result=$(curl -fsS "https://labee.dev/api/mail-auth?domain=example.com")
spf=$(echo "$result" | jq -r '.data.spf.exists')
dmarc=$(echo "$result" | jq -r '.data.dmarc.exists')
if [ "$spf" != "true" ]; then
  echo "::error::SPF record not found"
  exit 1
fi
if [ "$dmarc" != "true" ]; then
  echo "::error::DMARC record not found"
  exit 1
fi
echo "SPF: $spf, DMARC: $dmarc"
{
  "success": true,
  "data": {
    "spf": {
      "record": "v=spf1 include:_spf.google.com ~all",
      "exists": true
    },
    "dkim": {
      "mode": "auto",
      "record": "v=DKIM1; k=rsa; p=...",
      "exists": true,
      "selector": "google",
      "matches": [
        { "selector": "google", "record": "v=DKIM1; k=rsa; p=...", "exists": true }
      ],
      "checkedSelectors": ["google", "selector1", "selector2", "s1", "s2", "k1", "k2", "k3", "default", "dkim", "mail", "smtp"],
      "exhaustive": false
    },
    "dmarc": {
      "record": "v=DMARC1; p=reject; rua=mailto:dmarc@example.com",
      "exists": true
    },
    "bimi": {
      "record": null,
      "exists": false
    }
  },
  "error": null,
  "meta": { "responseTime": 200 }
}

dig と openssl で組むワークフロー

CI 環境から UDP 53 が通る場合は、dig と openssl だけでワークフローを組めます。

name: Domain Health Check (dig/openssl)
on:
  schedule:
    - cron: '0 9 * * 1'  # 毎週月曜 09:00 UTC
  workflow_dispatch:

jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - name: DNS A record
        run: |
          result=$(dig +short A example.com @8.8.8.8)
          if [ -z "$result" ]; then
            echo "::error::A record not found"
            exit 1
          fi
          echo "A record: $result"

      - name: SSL connection
        run: |
          if echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | grep -q "Verify return code: 0"; then
            echo "SSL OK"
          else
            echo "::error::SSL verification failed"
            exit 1
          fi

      - name: SSL expiry
        run: |
          expiry=$(echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
            | openssl x509 -noout -enddate | cut -d= -f2)
          expiry_epoch=$(date -d "$expiry" +%s)
          now_epoch=$(date +%s)
          days_left=$(( (expiry_epoch - now_epoch) / 86400 ))
          if [ "$days_left" -lt 30 ]; then
            echo "::warning::SSL certificate expires in $days_left days"
          fi

      - name: SPF record
        run: |
          spf=$(dig +short TXT example.com @8.8.8.8 | grep "v=spf1")
          if [ -z "$spf" ]; then
            echo "::error::SPF record not found"
            exit 1
          fi

      - name: DMARC record
        run: |
          dmarc=$(dig +short TXT _dmarc.example.com @8.8.8.8)
          if [ -z "$dmarc" ]; then
            echo "::error::DMARC record not found"
            exit 1
          fi

workflow_dispatch を追加しておくと、Actions のタブから手動実行もできます。schedule の cron は UTC で解釈されるため、日本時間の月曜 18:00 に実行したい場合は 0 9 * * 1 を指定します。

この方法は CI 環境から 8.8.8.8 への UDP 53 が通る前提です。GitHub Actions の ubuntu-latest ランナーでは通常動作しますが、セルフホストランナーやファイアウォールで制限されている環境では dig がタイムアウトで失敗します。

HTTPS 経由の API で組むワークフロー

UDP 53 がブロックされている環境や、dig のインストールが保証されない環境では、HTTPS 経由の API を使う方法もあります。Labee Dev Toolbox の API は認証不要で、curl だけで動作します。

name: Domain Health Check (API)
on:
  schedule:
    - cron: '0 9 * * 1'
  workflow_dispatch:

jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - name: DNS A record
        run: |
          result=$(curl -fsS "https://labee.dev/api/dns?domain=example.com&type=A")
          count=$(echo "$result" | jq '.data.records.A | length')
          if [ "$count" -eq 0 ]; then
            echo "::error::A record not found"
            exit 1
          fi

      - name: SSL reachability
        run: |
          result=$(curl -fsS "https://labee.dev/api/ssl-cert?hostname=example.com")
          reachable=$(echo "$result" | jq -r '.data.reachable')
          if [ "$reachable" != "true" ]; then
            echo "::error::HTTPS unreachable"
            exit 1
          fi

      - name: Mail authentication
        run: |
          result=$(curl -fsS "https://labee.dev/api/mail-auth?domain=example.com")
          spf=$(echo "$result" | jq -r '.data.spf.exists')
          dmarc=$(echo "$result" | jq -r '.data.dmarc.exists')
          if [ "$spf" != "true" ] || [ "$dmarc" != "true" ]; then
            echo "::error::Mail auth incomplete: SPF=$spf DMARC=$dmarc"
            exit 1
          fi

API 版では SSL の到達性のみを確認します。証明書の有効期限を監視したい場合は、dig/openssl 版の SSL expiry ステップを追加してください。

複数ドメインへの対応

管理するドメインが複数ある場合は、matrix strategy でドメインの一覧を定義します。上記の dig/openssl 版・API 版のどちらのステップでも matrix と組み合わせられます。

jobs:
  check:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        domain:
          - example.com
          - example.jp
          - api.example.com
      fail-fast: false
    steps:
      - name: DNS check
        run: |
          result=$(dig +short A ${{ matrix.domain }} @8.8.8.8)
          if [ -z "$result" ]; then
            echo "::error::A record not found: ${{ matrix.domain }}"
            exit 1
          fi

      - name: SSL check
        run: |
          if echo | openssl s_client -connect ${{ matrix.domain }}:443 -servername ${{ matrix.domain }} 2>/dev/null | grep -q "Verify return code: 0"; then
            echo "SSL OK: ${{ matrix.domain }}"
          else
            echo "::error::SSL failed: ${{ matrix.domain }}"
            exit 1
          fi

      - name: Mail auth
        run: |
          spf=$(dig +short TXT ${{ matrix.domain }} @8.8.8.8 | grep "v=spf1")
          dmarc=$(dig +short TXT _dmarc.${{ matrix.domain }} @8.8.8.8)
          if [ -z "$spf" ] || [ -z "$dmarc" ]; then
            echo "::error::Mail auth incomplete: ${{ matrix.domain }}"
            exit 1
          fi

fail-fast: false を設定すると、1 つのドメインが失敗しても残りのドメインのチェックは続行されます。3 ドメインのうち 2 つに問題がある場合でも、1 回の実行で全体像を把握できます。

matrix の配列に新しいドメインを追加するだけでチェック対象が増えるため、ドメインが増えても管理コストはほとんど変わりません。UDP 53 がブロックされている環境では、前述の API 版ワークフローのステップに置き換えてください。

デプロイ後に自動でチェックを実行する

定期チェックに加えて、デプロイ直後にもチェックを走らせておくと、設定ミスの検知が速くなります。workflow_run トリガーを使うと、別のワークフローの完了を起点にできます。

name: Post-Deploy Check
on:
  workflow_run:
    workflows: ["Deploy"]
    types: [completed]

jobs:
  verify:
    if: ${{ github.event.workflow_run.conclusion == 'success' }}
    runs-on: ubuntu-latest
    steps:
      - name: Wait for propagation
        run: sleep 60

      - name: DNS check
        run: |
          result=$(dig +short A example.com @8.8.8.8)
          if [ -z "$result" ]; then
            echo "::error::A record not found after deploy"
            exit 1
          fi

      - name: SSL check
        run: |
          if echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | grep -q "Verify return code: 0"; then
            echo "SSL OK after deploy"
          else
            echo "::error::SSL failed after deploy"
            exit 1
          fi

workflows にはトリガー元のワークフロー名を配列で指定します。types: [completed] は成功・失敗に関わらず完了時に発火するため、if 条件で conclusion == 'success' に絞っています。

DNS 変更を伴うデプロイの場合、変更直後はまだキャッシュが残っていることがあります。sleep 60 で 1 分待つのは簡易的な対策です。TTL を 300 秒(5 分) に事前に下げておけば、sleep 300 で確実にキャッシュが入れ替わった状態を確認できます。

Slack 通知の追加

チェックが失敗したとき、Slack に通知を送ることで対応を速められます。Incoming Webhook の URL をリポジトリの Secrets に SLACK_WEBHOOK_URL として登録し、失敗時のステップで呼び出します。

      - name: Notify on failure
        if: failure()
        run: |
          curl -fsS -X POST "$SLACK_WEBHOOK" \
            -H 'Content-Type: application/json' \
            -d "{\"text\":\"Domain check failed: ${{ matrix.domain }}\\nSee: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\"}"
        env:
          SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}

if: failure() は、同じジョブ内の先行ステップが 1 つでも失敗した場合に実行されます。matrix strategy と組み合わせると、失敗したドメインごとに通知が飛びます。

Webhook の URL は平文でワークフローファイルに書かず、Secrets 経由で渡します。$SLACK_WEBHOOK は環境変数として展開されるため、Actions のログにも表示されません。

ワークフロー設計の注意点

レート制限

Labee Dev Toolbox の API にはレート制限があります。matrix で 10 ドメイン以上を一括チェックする場合は、ステップ間に sleep 1 を挟むと安全です。

cron の最短間隔

GitHub Actions の schedule トリガーは 5 分間隔が最短です。実行が混雑時には数分から数十分遅延することがあります。正確なタイミングが必要な場合は、外部のスケジューラーから workflow_dispatch を呼び出す構成を検討してください。

SSL API の確認範囲

SSL API は HTTPS 接続の到達性を確認するエンドポイントです。証明書の有効期限や発行者の詳細は返しません。証明書の有効期限を監視したい場合は、「SSL 到達性のチェック」セクションで紹介した openssl s_client によるチェックを併用してください。SSL 証明書の自動更新が失敗するパターンや対策は「SSL 証明書の期限切れを防ぐために知っておくべきこと」で詳しく解説しています。

メール認証の 3 要素(SPF・DKIM・DMARC)を dig で個別に確認する手順や、Gmail のバルクセンダー要件との照合方法は「SPF・DKIM・DMARC を外部から確認する方法」にまとめています。

手元のドメインでまずは 1 つワークフローを動かしてみてください。example.com を自分のドメインに置き換えれば、そのまま使えます。ブラウザーから確認する場合は Labee Dev Toolbox の DNS チェック画面、SSL 到達確認画面、メール認証チェック画面で API が返す値を事前に確認できます。

実際のドメインで確認してみる

登録不要、無料です。ドメイン名を入れるだけで外部からの見え方を確認できます。

無料で試す

Pro プラン(準備中)

DNS 変更の自動検知・SSL 期限アラート・複数ドメイン管理など、継続して確認し続けるための機能を準備中です。

関連記事

メール認証

SPF・DKIM・DMARC を外部から確認する方法 — dig と API で設定漏れを検出する

dig コマンドと外部 API を使って、SPF・DKIM・DMARC の設定状況を外部視点から確認する手順を解説します。DKIM セレクターの自動検索、Gmail のバルクセンダー要件との照合、よくある設定漏れパターンの特定方法も紹介します。

2026-04-01 ・ 7分

DNS

DNS 変更後の反映確認、dig だけで大丈夫?

DNS レコードを変更した後、dig コマンドだけでは正確な反映状況がわかりません。キャッシュの仕組みと、外部から確認する具体的な方法を解説します。

2026-04-10 ・ 6分

DNS

ドメインを取得したら最初にやる DNS チェック — NS から SSL 到達確認まで一通り解説

新規ドメイン取得後に確認すべき DNS 設定を順番に整理します。NS・A・MX レコードの確認、SPF/DKIM/DMARC の初期設定、SSL の外部到達確認まで、dig コマンドと外部 API の両面から手順を解説します。

2026-04-12 ・ 8分

コンテンツ 技術ノート ガイド 用語解説
ツール ツール一覧 API Reference
Labee 日本語トップ Labee LLC
© 2026 Labee LLC . All rights reserved.
ホーム ブログ ガイド 用語集