2026年5月31日

2026年5月31日

WordPressに最適なCDNを選ぶ方法【CloudFront・Cloudflare・BunnyCDN比較】

はじめに

WordPressサイトにCDNを導入することで、静的ファイルの配信速度向上とオリジンサーバーの負荷軽減を同時に実現できます。しかし、CloudFront・Cloudflare・BunnyCDNはそれぞれ特性が異なり、サイトの規模や用途によって最適な選択が変わります。本記事では3つのCDNを機能・価格・WordPress連携の観点から比較し、実際の設定方法まで解説します。

症状・原因

  • 海外や地方からのアクセスでページ表示が遅い
  • 画像・CSS・JSの配信がオリジンサーバーに集中している
  • 大量の静的ファイルリクエストでサーバーの帯域を消費している
  • DDoS攻撃や大量リクエストで直接オリジンサーバーが攻撃されている
  • 記事公開後もCDNキャッシュが更新されず古いページが表示される

解決手順

ステップ1:CDNの比較と選定

3つのCDNの主要な特徴を理解して選定します。

| 項目 | CloudFront | Cloudflare | BunnyCDN |

|---|---|---|---|

| 価格モデル | 転送量課金 | 無料プランあり | 転送量課金(格安) |

| 月額目安 | $5〜50+ | 無料〜$20 | $1〜10 |

| エッジ拠点数 | 450+ | 300+ | 120+ |

| DDoS防御 | 別途AWS Shield | 標準搭載 | 標準搭載 |

| WordPress統合 | 要設定 | 簡単 | プラグインあり |

| キャッシュ制御 | 細かく設定可 | ページルール | エッジルール |

選定基準:

  • AWS環境のWordPress → CloudFront(VPC内通信でOrigin費用なし)
  • セキュリティ重視・初心者向け → Cloudflare(無料SSL・DDoS防御標準搭載)
  • コスト最優先・高トラフィック → BunnyCDN(従量課金が最安水準)

ステップ2:CDN Enablerプラグインでの基本設定

CDN EnablerプラグインはCloudFront・BunnyCDNの両方に対応しています。

<?php
// CDN Enabler が生成するURLを wp-config.php でカスタマイズ
// または functions.php に直接記述

/**
 * WordPressのアセットURLをCDN URLに書き換え
 * CDN Enabler プラグイン不使用の場合の手動実装
 */
add_filter( 'script_loader_src', 'wpcdn_rewrite_url', 20 );
add_filter( 'style_loader_src',  'wpcdn_rewrite_url', 20 );

function wpcdn_rewrite_url( string $url ): string {
    // wp-admin は書き換えない
    if ( is_admin() ) {
        return $url;
    }

    $cdn_url    = defined( 'WP_CDN_URL' ) ? WP_CDN_URL : '';
    $site_url   = get_site_url();

    if ( empty( $cdn_url ) || empty( $site_url ) ) {
        return $url;
    }

    // サイトURLをCDN URLに置換
    return str_replace( $site_url, $cdn_url, $url );
}

// wp-config.php に追加:
// define( 'WP_CDN_URL', 'https://cdn.example.com' );

ステップ3:記事公開時のキャッシュ自動無効化

記事を投稿・更新した際にCDNキャッシュを自動的に削除します。

<?php
// mu-plugins/cdn-cache-purge.php

/**
 * 投稿更新時にCDNキャッシュをパージ
 */
add_action( 'save_post', 'wpcdn_purge_post_cache', 10, 2 );
add_action( 'wp_trash_post', 'wpcdn_purge_post_cache' );

function wpcdn_purge_post_cache( int $post_id, WP_Post $post = null ): void {
    // 自動保存・リビジョンはスキップ
    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
        return;
    }
    if ( wp_is_post_revision( $post_id ) ) {
        return;
    }

    $post     = $post ?? get_post( $post_id );
    $post_url = get_permalink( $post_id );
    $cdn_type = defined( 'WP_CDN_TYPE' ) ? WP_CDN_TYPE : 'cloudflare';

    switch ( $cdn_type ) {
        case 'cloudflare':
            wpcdn_purge_cloudflare( [ $post_url ] );
            break;
        case 'cloudfront':
            wpcdn_purge_cloudfront( [ '/' . ltrim( wp_make_link_relative( $post_url ), '/' ) ] );
            break;
        case 'bunnycdn':
            wpcdn_purge_bunnycdn( $post_url );
            break;
    }
}

/**
 * Cloudflare Cache Purge API
 */
function wpcdn_purge_cloudflare( array $urls ): void {
    $zone_id = defined( 'CLOUDFLARE_ZONE_ID' ) ? CLOUDFLARE_ZONE_ID : '';
    $token   = defined( 'CLOUDFLARE_API_TOKEN' ) ? CLOUDFLARE_API_TOKEN : '';

    if ( empty( $zone_id ) || empty( $token ) ) {
        return;
    }

    wp_remote_post(
        "https://api.cloudflare.com/client/v4/zones/{$zone_id}/purge_cache",
        [
            'headers' => [
                'Authorization' => "Bearer {$token}",
                'Content-Type'  => 'application/json',
            ],
            'body'    => wp_json_encode( [ 'files' => $urls ] ),
            'timeout' => 10,
        ]
    );
}

/**
 * CloudFront Cache Invalidation
 */
function wpcdn_purge_cloudfront( array $paths ): void {
    $distribution_id = defined( 'CLOUDFRONT_DISTRIBUTION_ID' ) ? CLOUDFRONT_DISTRIBUTION_ID : '';
    $access_key      = defined( 'AWS_ACCESS_KEY_ID' )           ? AWS_ACCESS_KEY_ID          : '';
    $secret_key      = defined( 'AWS_SECRET_ACCESS_KEY' )       ? AWS_SECRET_ACCESS_KEY      : '';

    if ( empty( $distribution_id ) ) {
        return;
    }

    // AWS SDK for PHP またはWP Offload Media Liteを使用
    // aws cloudfront create-invalidation --distribution-id $distribution_id --paths /*
    $command = sprintf(
        'aws cloudfront create-invalidation --distribution-id %s --paths %s 2>&1',
        escapeshellarg( $distribution_id ),
        implode( ' ', array_map( 'escapeshellarg', $paths ) )
    );
    exec( $command, $output, $return_code );

    if ( 0 !== $return_code ) {
        error_log( 'CloudFront invalidation failed: ' . implode( "\n", $output ) );
    }
}

/**
 * BunnyCDN Cache Purge API
 */
function wpcdn_purge_bunnycdn( string $url ): void {
    $access_key = defined( 'BUNNYCDN_ACCESS_KEY' ) ? BUNNYCDN_ACCESS_KEY : '';

    if ( empty( $access_key ) ) {
        return;
    }

    wp_remote_post(
        'https://api.bunny.net/purge?url=' . urlencode( $url ) . '&async=true',
        [
            'headers' => [ 'AccessKey' => $access_key ],
            'timeout' => 10,
        ]
    );
}

ステップ4:wp-config.phpでCDN認証情報を設定

<?php
// wp-config.php に追加

// CDNタイプの指定(cloudflare / cloudfront / bunnycdn)
define( 'WP_CDN_TYPE', 'cloudflare' );
define( 'WP_CDN_URL',  'https://cdn.example.com' );

// Cloudflare設定
define( 'CLOUDFLARE_ZONE_ID',   'your-zone-id' );
define( 'CLOUDFLARE_API_TOKEN', 'your-api-token' );

// CloudFront設定
define( 'CLOUDFRONT_DISTRIBUTION_ID', 'EXXXXXXXXXX' );
define( 'AWS_ACCESS_KEY_ID',           'AKIAIOSFODNN7EXAMPLE' );
define( 'AWS_SECRET_ACCESS_KEY',       'your-secret-key' );

// BunnyCDN設定
define( 'BUNNYCDN_ACCESS_KEY', 'your-bunnycdn-access-key' );
define( 'BUNNYCDN_PULL_ZONE',  'your-pull-zone-name' );

ステップ5:コスト最適化とキャッシュヒット率の確認

CDNの効果を計測してコストを最適化します。

# Cloudflare: キャッシュヒット率の確認
curl -s -X POST "https://api.cloudflare.com/client/v4/graphql" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "{ viewer { zones(filter: {zoneTag: \"ZONE_ID\"}) { httpRequests1dGroups(limit:7) { dimensions { date } sum { requests cachedRequests } } } } }"
  }' | jq '.data.viewer.zones[0].httpRequests1dGroups[] | {date: .dimensions.date, hit_rate: (.sum.cachedRequests / .sum.requests * 100)}'

# BunnyCDN: 帯域使用量確認(APIで取得)
curl -s "https://api.bunny.net/statistics?dateFrom=2024-01-01&dateTo=2024-01-31" \
  -H "AccessKey: YOUR_ACCESS_KEY" | jq '.BandwidthUsedChart'

# CloudFrontのキャッシュ動作をcurlでテスト
curl -I https://cdn.example.com/wp-content/uploads/image.jpg | grep -i "x-cache\|age\|cache-control"
# X-Cache: Hit from cloudfront が表示されればキャッシュヒット

注意事項

  • CloudFrontは通常AWSの他サービス(EC2, RDS等)との組み合わせで真価を発揮する。単独でWordPressに使う場合はCloudflareの方がセットアップが容易
  • Cloudflareの無料プランではHTMLページのキャッシュがデフォルト無効。「Cache Level: Cache Everything」ページルールを設定する場合、ログイン済みページ(/wp-admin//cart/)の除外設定を必ず行うこと
  • CDNを導入後は wp-config.phpdefine('FORCE_SSL_ADMIN', true) を設定し、管理画面のHTTPSを強制すること
  • オリジンプル方式(Pull)のCDNはオリジンサーバーにファイルが存在することが前提。削除したファイルのCDNキャッシュは手動で削除が必要
  • キャッシュTTLを長くするほどCDNコストは下がるが、更新が遅延するリスクが高まる。画像は1年・CSS/JSは1週間・HTMLは1時間が推奨の目安

まとめ

WordPressへのCDN導入は費用対効果が高い施策ですが、CDNの種類によってWordPressとの統合方法やキャッシュ管理の考え方が異なります。キャッシュ戦略の全体設計については「WordPressへの突然のトラフィックスパイクを対処する方法」と組み合わせて検討してください。

お気軽にご相談ください

お見積りへ お問い合わせへ