カテゴリ: WordPress / Web技術
タグ: WordPress, iPhone, iPad, iOS, 動画, mp4, WebKit, Cloudflare
はじめに
WordPressにアップロードしたMP4動画が、PCやAndroidでは問題なく再生できるのに、iPhoneやiPadでは一切再生できないというトラブルに遭遇しました。
ChromeでもBraveでもダメ——そう気づいたとき、問題はブラウザではなくOSレベルにあることがわかりました。本記事では原因の特定から解決策の検討まで、実際のトラブルシューティングの過程をまとめます。
結論を先に
iOSデバイス(iPhone・iPad)上のすべてのブラウザはWebKitエンジンを使用しており、動画再生時に Accept-Ranges: bytes HTTPヘッダーを必須とします。このヘッダーが返らないサーバー環境では、動画は完全に再生できません。
原因:iOSはすべてWebKitエンジン
Appleの規約により、iOS/iPadOS上のすべてのブラウザ(Chrome・Brave・Firefox含む)はSafariと同じWebKitレンダリングエンジンを使用します。
| デバイス | ブラウザ | エンジン | 再生結果 |
|---|---|---|---|
| PC | Chrome / Firefox | Blink / Gecko | ✅ OK |
| Android | Chrome | Blink | ✅ OK |
| iPhone / iPad | Chrome | WebKit(強制) | ❌ NG |
| iPhone / iPad | Brave | WebKit(強制) | ❌ NG |
AndroidのBlinkエンジンはHTTP 200レスポンスでも動画を再生できますが、WebKitは動画のストリーミング再生のために HTTP 206 Partial Content(バイト範囲リクエスト) を必須とします。サーバーが Accept-Ranges: bytes ヘッダーを返さないと、WebKitは再生を拒否します。
診断方法:curl -I でヘッダーを確認する
問題の切り分けには curl -I コマンドが有効です。動画ファイルのURLに対してHEADリクエストを送り、レスポンスヘッダーを確認します。
curl -I https://your-site.com/wp-content/uploads/xxxx/your-video.mp4
curl -I https://your-site.com/wp-content/uploads/xxxx/your-video.mp4
問題が発生している場合のレスポンス例:
HTTP/2 200 content-type: video/mp4 server: cloudflare
← accept-ranges: bytes がない
HTTP/2 200
content-type: video/mp4
server: cloudflare
# ← accept-ranges: bytes がない
accept-ranges: bytes が含まれていない場合、iOSデバイスでの再生に失敗します。
Cloudflare環境での落とし穴
さくらインターネットなどのサーバーにCloudflareを前段に置いている場合、問題はより複雑になります。
今回の構成(さくらインターネット RSプレミアム + Cloudflare)では次の現象が起きました。
Transform Rule を設定しても効かない
CloudflareのTransform Rule(レスポンスヘッダー変換ルール)で Accept-Ranges: bytes を付与するルールを作成・有効化しましたが、ヘッダーが反映されませんでした。
キャッシュのパージが必要
cf-cache-status: HIT の状態では新しいルールが適用されないため、Cloudflareのキャッシュパージ(Purge Cache)が必要です。ただし今回はパージ後も解決しませんでした。
.htaccessへの追記でも解決しない
Apacheの .htaccess にオリジンからヘッダーを返す設定を追記しましたが、Cloudflareのプロキシ経由ではヘッダーが消える現象が継続しました。
# 試みた設定(.htaccess末尾に追記) <FilesMatch ”\.(mp4|m4v|mov)$”> Header always set Accept-Ranges bytes
# 試みた設定(.htaccess末尾に追記)
<FilesMatch "\.(mp4|m4v|mov)$">
Header always set Accept-Ranges bytes
</FilesMatch>
⚠️ 注意:
<IfModule mod_headers.c>で囲むと既存のCocoon設定と競合してHTTP 500エラーが発生することがあります。
最終的な解決策:YouTube埋め込みへの切り替え
Cloudflareプロキシ経由での解決が困難と判断し、YouTubeに動画をアップロードして埋め込む方法に切り替えました。
この方法のメリット
- iPhoneを含むすべてのデバイス・ブラウザで動作保証
- CloudflareやWebサーバーの設定に依存しない
- WordPressはYouTubeのURLを貼るだけで自動的に埋め込みになる
手順
- YouTubeに動画をアップロード(限定公開推奨)
- 動画のURLをコピー
- WordPressのブロックエディタで「埋め込み」ブロックにURLを貼り付け
自動再生・ループなどの制御が必要な場合
埋め込みURLにパラメータを追加することで細かい制御が可能です。
https://www.youtube.com/embed/VIDEO\_ID?autoplay=1&loop=1&mute=1&controls=0&playlist=VIDEO\_ID
https://www.youtube.com/embed/VIDEO_ID?autoplay=1&loop=1&mute=1&controls=0&playlist=VIDEO_ID
| パラメータ | 値 | 意味 |
|---|---|---|
| autoplay | 1 | 自動再生(muteが必要) |
| loop | 1 | ループ再生 |
| mute | 1 | ミュート |
| controls | 0 | コントロール非表示 |
| playlist | VIDEO_ID | loopに必要 |
事前対策:faststart変換
動画をWordPressに直接アップロードする場合、MP4ファイルのmoov atom(メタデータ)がファイル末尾にあると、WebKitはファイル全体をダウンロードするまで再生できません。
ffmpegで事前に変換しておくことで、WebKitでもストリーミング再生が可能になります。
ffmpeg -i input.mp4 -c copy -movflags faststart output.mp4
ffmpeg -i input.mp4 -c copy -movflags faststart output.mp4
これにより、メタデータがファイル先頭に移動します。動画をアップロードする前の定番処理として覚えておくと便利です。
まとめ
| チェック項目 | 確認方法 |
|---|---|
Accept-Ranges: bytes が返っているか | curl -I でレスポンスヘッダーを確認 |
MIMEタイプが video/mp4 か | 同上 |
| moov atomがファイル先頭にあるか | ffmpegで faststart 変換 |
| Cloudflareがヘッダーを削除していないか | MISS状態でcurl確認 |
iOSデバイスでのみ再生できない場合は、まず curl -I でヘッダーを確認することが診断の第一歩です。Cloudflareを使用している環境では、オリジンからのヘッダーが意図通りに届かないケースがあるため、YouTube埋め込みへの切り替えが最も確実な解決策になります。
この記事はITQが実際に遭遇したトラブルシューティングの記録です。同じ問題で困っている方の参考になれば幸いです。