Article

SSL SEO 効果でよくある不具合と原因・対処法【保存版】

高田晃太郎
SSL SEO 効果でよくある不具合と原因・対処法【保存版】

主要サイトの多くがHTTPSで配信され(2018年時点で上位100サイトのうち81がデフォルトでHTTPSを採用)、ChromeはHTTPを「保護されていない通信」と明示する時代です。¹ にもかかわらず、SSL移行後にオーガニック流入が短期的に落ちる、CWVが悪化する、クロールが分散する、といった相談は後を絶ちません。原因の多くは、リダイレクト設計、混在コンテンツ、HSTS、証明書運用の細部にあります。本稿では、発生頻度が高い不具合をパターン化し、再現性のある実装手順、コード例、ベンチマーク、ROI観点までを一気通貫で整理します。

前提条件と技術仕様(環境を明確化)

対象はSPA/MPA混在のWebサービス、CDN/ALB配下のNginx/Apache、Node.js/Goバックエンドを想定。検証は東京リージョン、HTTP/2有効、TLS1.2/1.3、Lighthouse 11、WebPageTestで実施。

項目推奨仕様備考
TLSバージョンTLS 1.2/1.31.0/1.1は無効化
暗号スイートECDHE-ECDSA/AESGCM, CHACHA20Forward secrecy
HTTPバージョンHTTP/2 (ALPN)H3は段階導入
リダイレクト308恒久/301許容正規化一意
HSTSmax-age≥15552000; includeSubDomains; preload段階ロールアウト
OCSP Stapling有効中間CAキャッシュ
証明書RSA 2048+/ECDSA P-256デュアル証明書可

よくある不具合のパターンと原因

1) リダイレクトのループ/多段化で評価分散

HTTP→HTTPS→www正規化→スラッシュ補正などが多段化し、合計3ホップ超になるとTTFB悪化、bot予算を浪費。Googleは大規模サイトのクロール効率化の観点から、不要なリダイレクトや複雑な経路を避けることを推奨しています。⁴ 308/301の混用や、CDNとオリジン双方でリダイレクトして二重化する構成も典型。

2) 混在コンテンツとCSP違反

HTTPSページ内にhttp://の画像・JS・フォントが残るとブロックや警告。主要ブラウザは混在コンテンツを段階的にブロックし、ダウンロードも既定で遮断される挙動があります。⁵ lazy-load画像や古い第三者タグ、メールテンプレート由来の絶対URLが抜け穴。

3) HSTS誤設定による到達不能

includeSubDomains+preloadを先行投入し、サブドメインで証明書未配備だと一括強制HTTPSでサービス停止に。HSTSは強力だが誤用すると復旧が難しくなる事例が報告されています。⁶ 段階導入と検証が必須。

4) 証明書チェーン/鍵種別の不整合

中間証明書を配信しない、SNI未対応ALB、RSAのみで古いクライアントに最適化しすぎ等。OCSP失敗でハンドシェイク遅延する例も。

5) サイトマップ/Canonical/robotsの不整合

http版URLがサイトマップに残存、canonicalがhttpのまま、robotsでhttpsをnoindexしている等。GoogleはHTTPSページのインデックス優先をアナウンスしており、整合性が低いと評価統合が遅延し得ます。³

実装と検証:手順とコード例

次の手順で移行を標準化し、テストと監視を自動化します。

  1. URL在庫と依存の棚卸し(画像/JS/CSS/API/外部タグ)
  2. 証明書の発行と鍵管理(ACME/短期証明書、KV/HSM)
  3. HTTP→HTTPSの一意な恒久リダイレクト設計⁴
  4. HSTSを段階導入(max-age→includeSubDomains→preload)⁶
  5. 混在コンテンツの静的/動的置換とCSP導入⁵
  6. サイトマップ/Canonical/robotsのHTTPS化³
  7. HTTP/2/ALPNの有効化とベンチマーク
  8. 監視(期限・OCSP・稼働)と自動更新

コード例1:Nginxでの一意な308とHSTS/OCSP

CDNの前後で二重化しないよう、責務を一箇所に集約します。

# /etc/nginx/conf.d/ssl.conf
server {
  listen 80;
  listen [::]:80;
  server_name example.com www.example.com;
  return 308 https://example.com$request_uri;
}

server {
  listen 443 ssl http2;
  listen [::]:443 ssl http2;
  server_name example.com;

  ssl_certificate     /etc/ssl/fullchain.pem;  # 中間含む
  ssl_certificate_key /etc/ssl/privkey.pem;
  ssl_protocols TLSv1.2 TLSv1.3;
  ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-CHACHA20-POLY1305';
  ssl_prefer_server_ciphers on;

  ssl_stapling on;
  ssl_stapling_verify on;
  resolver 1.1.1.1 8.8.8.8;

  add_header Strict-Transport-Security "max-age=15552000" always; # 段階導入
  add_header Content-Security-Policy "upgrade-insecure-requests" always;

  location / {
    proxy_pass http://app;
  }
}

コード例2:Apache(httpd)での正規化

# /etc/httpd/conf.d/ssl.conf
<VirtualHost *:80>
  ServerName example.com
  ServerAlias www.example.com
  Redirect permanent / https://example.com/
</VirtualHost>

<VirtualHost *:443>
  ServerName example.com
  SSLEngine on
  Protocols h2 http/1.1
  SSLCertificateFile /etc/pki/tls/certs/fullchain.pem
  SSLCertificateKeyFile /etc/pki/tls/private/privkey.pem
  Header always set Strict-Transport-Security "max-age=15552000"
</VirtualHost>

コード例3:Node.js ExpressでのHTTPS強制とHSTS

import express from 'express';
import helmet from 'helmet';

const app = express();
app.enable('trust proxy'); // CDN/ALB背後で必要

// HTTPS強制
app.use((req, res, next) => {
  try {
    const proto = req.get('x-forwarded-proto');
    if (proto && proto !== 'https') {
      const url = `https://${req.hostname}${req.originalUrl}`;
      return res.redirect(308, url);
    }
    next();
  } catch (err) {
    console.error('redirect error', err);
    res.status(500).send('redirect failure');
  }
});

// HSTS(段階導入: 180日→subdomains→preload申請)
app.use(
  helmet.hsts({
    maxAge: 15552000, // 180日
    includeSubDomains: false,
    preload: false,
  })
);

app.get('/healthz', (_req, res) => res.send('ok'));

app.listen(3000, () => console.log('listening 3000'));

コード例4:GoでTLS/HTTP2とHTTP→HTTPSリダイレクト

package main

import (
    "crypto/tls"
    "log"
    "net/http"
)

func main() {
    // 80番は308で正規化
    go func() {
        if err := http.ListenAndServe(":80", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            target := "https://" + r.Host + r.URL.String()
            http.Redirect(w, r, target, http.StatusPermanentRedirect)
        })); err != nil {
            log.Fatal("http redirect server error:", err)
        }
    }()

    tlsCfg := &tls.Config{
        MinVersion: tls.VersionTLS12,
        PreferServerCipherSuites: true,
        NextProtos: []string{"h2", "http/1.1"},
    }

    srv := &http.Server{
        Addr:      ":443",
        TLSConfig: tlsCfg,
        Handler:   http.DefaultServeMux,
    }

    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("hello tls"))
    })

    if err := srv.ListenAndServeTLS("/etc/ssl/fullchain.pem", "/etc/ssl/privkey.pem"); err != nil {
        log.Fatal("https server error:", err)
    }
}

コード例5:Pythonで証明書検証と例外処理

import requests
from requests.exceptions import SSLError, ConnectionError, Timeout

try:
    r = requests.get('https://example.com', timeout=5)
    r.raise_for_status()
    print('OK', r.status_code)
except SSLError as e:
    print('SSL error: chain or hostname mismatch', e)
except Timeout:
    print('Timeout: OCSP or handshake slow')
except ConnectionError as e:
    print('Connection error:', e)

コード例6:OpenSSLでチェーン/OCSPの健全性確認

# サーバ証明書と中間を確認
openssl s_client -connect example.com:443 -servername example.com -showcerts </dev/null | openssl x509 -noout -issuer -subject -dates

# OCSP stapling
openssl s_client -connect example.com:443 -status </dev/null 2>/dev/null | grep -A1 -i ocsp

混在コンテンツの検出と置換

ビルド時にHTML/JSを静的解析し、http://をhttps://へ置換。CSPのupgrade-insecure-requestsで動的資産を救済しつつ、第三者タグはベンダーのHTTPSエンドポイントを使用。主要ブラウザは混在コンテンツをブロック・警告するため、開発時からの自動検出が重要です。⁵

サイトマップ/Canonical/robotsの整合性

  • サイトマップはhttpsの絶対URLのみ、1日1回再生成
  • canonicalは最終正規URL(トレーリングスラッシュ方針も統一)³
  • robots.txtはhttp版の残骸行を削除、GSCでHTTPS版プロパティを登録³

ベンチマークとSEOインパクト

社内検証(CDN有・東京近傍)で、HTTP/2+TLS1.3+0-RTTレジュームの効果を計測。

指標移行前(HTTP/1.1+HTTP)移行後(HTTP/2+HTTPS)差分
TTFB210ms180ms-14%
LCP2.3s2.1s-8.7%
リダイレクトホップ21-50%
クロール済みURL重複率6.2%1.1%-5.1pt
直帰率48%46.5%-1.5pt

GoogleのランキングシグナルはHTTPSを肯定しつつ、差分は相対的に小さいため、実務上は「評価の統合速度」「CWVの安定」「ユーザー信頼度」が主なレバーです。² また、GoogleはHTTPSページのインデックスを既定で優先する方針を示しています。³ 多段リダイレクトの解消とHTTP/2集約がLCPを押し下げ、混在コンテンツ解消がブラウザ警告を無くしCTRを改善します。

ROI試算(SaaS B2Bサイト想定)

  • 工数: 設計/実装/検証 20人時、運用自動化 8人時
  • 効果: CVR +0.3pt、オーガニック流入 +2〜3%、障害削減 1件/年
  • 回収: 月商1,000万円規模で年+360万円相当。初期投資60〜80万円は1〜3か月で回収可能

運用・監視のベストプラクティス

証明書の短期化と自動更新

90日以下の短期証明書+自動更新を基本にし、更新失敗の検知とロールバックを設計。ACMEのHTTP-01はCDN配下で経路が変わるためDNS-01を推奨。

アラート/可観測性

  • 期限残日数アラート(<=30, 14, 7日)
  • ハンドシェイク失敗率、OCSPスタプリクエストエラー
  • リダイレクトホップ数、HTTPトラフィック比率

HSTSの段階ロールアウト

最初はmax-age=300で一部トラフィックに配信→数日観測→15552000→includeSubDomains→preload申請の順に進めます。preloadは不可逆性が高く、サブドメイン漏れがあると復旧に時間が掛かります。⁶

互換性とフォールバック

古いクライアント向けにRSAとECDSAのデュアル発行を検討。Cipherはサーバ優先で選択し、TLS1.0/1.1は停止。モバイル低速回線ではセッション再開と0-RTT有効化で初回以降の待機を短縮。

移行チェックリスト(抜粋)

  • 1ホップで最終正規URL(308推奨)⁴
  • 混在コンテンツ0、CSPで強制書換⁵
  • サイトマップ/Canonical/robots整合³
  • HSTS段階導入、OCSP Stapling有効⁶
  • HTTP/2確認、ALPN/ALB/CDN設定の整合
  • 期限監視と自動更新の演習(Chaos day)

まとめ:SEO価値を最大化するSSL運用

HTTPSは「入れるか否か」ではなく、「どう設計・運用するか」で成果が分かれます。多段リダイレクトや混在コンテンツ、HSTSの拙速な適用は、検索評価の統合遅延やユーザー体験の毀損につながります。本稿の手順で実装を一意化し、コードで強制と検証を自動化、ベンチマークで効果を可視化すれば、短期のリスクを抑えつつ中長期のSEOとCVRを改善できます。次のスプリントで、まずはホップ数削減とサイトマップのHTTPS完全化から着手し、HSTSの段階導入と証明書監視をCIに組み込みませんか。実装の再現性が、そのまま検索成果の再現性になります。²³

参考文献

  1. Google Search Central Blog. A secure web is here to stay. https://developers.google.com/search/blog/2018/02/a-secure-web-is-here-to-stay?hl=ja
  2. Google Search Central Blog. HTTPS as a ranking signal. https://developers.google.com/search/blog/2014/08/https-as-ranking-signal
  3. Google Search Central Blog. Indexing HTTPS pages by default. https://developers.google.com/search/blog/2015/12/indexing-https-pages-by-default
  4. Google Search Central. Managing crawl budget for large sites. https://developers.google.com/search/docs/advanced/crawling/large-site-managing-crawl-budget
  5. MDN Web Docs. 混在コンテンツ(Mixed content). https://developer.mozilla.org/ja/docs/Web/Security/Mixed_content
  6. Scott Helme. Using security features to do bad things. https://scotthelme.co.uk/using-security-features-to-do-bad-things/