シナリオ
WordPressのメディアアップローダーで画像やPDFをアップロードしようとしています。プログレスバーが満タンになって……何も起きない。エラーメッセージが表示されます:
Upload: Failed to Write File to Disk
メディアライブラリにファイルはなく、ディスクにも何もない。ただそのメッセージだけ。原因の特定と修正方法を解説します。
何が起きているのか
WordPressのアップロードは2つの独立したステップで行われます。PHPがまず一時ディレクトリにファイルを書き込み、その後 wp-content/uploads/ へ移動します。どちらのステップが失敗してもこのエラーが発生します。原因は主に4つです:
wp-content/uploads/のパーミッションが正しくない — Webサーバーユーザーが書き込めない- PHPの一時ディレクトリに書き込めない — WordPressがファイルを移動しようとする前に、一時書き込みが失敗している
- アップロードディレクトリが存在しない — 移行や部分的なリストア後によく発生する
- ディスクまたはiノードのクォータが満杯 — 空き容量がなく、何も書き込めない
素早い診断
SSHでサーバーにログインし、何か変更する前にこの3つを確認してください。
1. ディスク容量を確認する
df -h /var/www/html
使用率が100%の場合は、まず容量を確保してください。iノードも確認しましょう — 小さなファイルが50,000個あるディレクトリは、ブロック容量に空きがあってもiノードを使い切ることがあります:
df -i /var/www/html
2. アップロードディレクトリを確認する
ls -la /var/www/html/wp-content/uploads/
ディレクトリはWebサーバーユーザー(Ubuntu/Debianでは www-data、CentOS/RHELでは apache)が所有者となっており、書き込みパーミッションが設定されている必要があります。
3. PHPの一時ディレクトリを確認する
php -r "echo ini_get('upload_tmp_dir') ?: sys_get_temp_dir();"
返ってきたパスをメモしておきます。次のステップに進む前に、そのディレクトリがWebサーバーユーザーによって書き込み可能であることを確認してください。
修正方法
修正1:アップロードディレクトリのパーミッションを正す(約90%のケースで解決)
まず、実際のWebサーバーユーザーを確認します:
# Ubuntu/Debian
ps aux | grep -E '(apache|nginx|php-fpm)' | grep -v root | head -1
# またはPHP-FPMプール設定を確認
grep -r "user = " /etc/php/*/fpm/pool.d/
次に所有者とパーミッションを修正します:
# www-data を実際のWebサーバーユーザーに置き換えてください
sudo chown -R www-data:www-data /var/www/html/wp-content/uploads/
sudo chmod -R 755 /var/www/html/wp-content/uploads/
PHPが自分のユーザーアカウントで動く共有ホスティング環境では、通常775が適切な選択です:
sudo chmod -R 775 /var/www/html/wp-content/uploads/
修正2:アップロードディレクトリが存在しない場合は作成する
sudo mkdir -p /var/www/html/wp-content/uploads
sudo chown -R www-data:www-data /var/www/html/wp-content/uploads/
sudo chmod -R 755 /var/www/html/wp-content/uploads/
WordPressはディレクトリ構造を自動的に再作成することもできます。wp-adminの 設定 → メディア に移動して保存をクリックすると、アップロードパスが見つからない場合にWordPressが作成を試みます。
修正3:PHPの一時ディレクトリのパーミッションを修正する
アップロードディレクトリは問題ないのにエラーが続く場合は、WordPressがファイルを移動しようとする前に一時書き込みのステップが失敗している可能性が高いです。
# PHPが使用している正確な一時パスを取得する
php -r "echo ini_get('upload_tmp_dir') ?: sys_get_temp_dir();"
# /tmp が返ってきた場合は修正する
sudo chmod 1777 /tmp
PHP-FPMプール設定でカスタムの一時ディレクトリを使っている場合は、そのパスを直接修正します:
grep upload_tmp_dir /etc/php/*/fpm/pool.d/*.conf
sudo chown www-data:www-data /path/to/custom/tmp
sudo chmod 755 /path/to/custom/tmp
修正4:デバッグログを有効にして失敗している正確なパスを特定する
まだ解決しない場合は、wp-config.php に一時的にデバッグログを有効にします:
define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
define('WP_DEBUG_DISPLAY', false);
再度アップロードを試みてください。その後 wp-content/debug.log を開くと、WordPressが書き込もうとした正確なファイルパスが完全なPHPエラーとして記録されており、問題の原因がすぐにわかります。
CentOS/RHEL:SELinuxを確認する
CentOSまたはRHELでは、SELinuxが隠れた原因になっていることがよくあります。Unixパーミッションは正しく見えるのに、書き込みがサイレントに失敗し続けることがあります。
# SELinuxが強制モードかどうか確認する
getenforce
# アップロードディレクトリに正しいSELinuxコンテキストを復元する
sudo restorecon -Rv /var/www/html/wp-content/uploads/
# またはWebサーバーがファイルを広範に書き込めるようにする
sudo setsebool -P httpd_unified 1
修正を確認する
- wp-adminで メディア → 新規追加 に移動する
- テスト用の画像をアップロードする
- サムネイルが生成された状態でメディアライブラリに表示されることを確認する
- ファイルがディスクに保存されたことを確認する:
ls -la /var/www/html/wp-content/uploads/$(date +%Y/%m)/
ファイルが存在し、www-data が所有者になっているはずです。
予防策
ディレクトリのパーミッションを調整する際は、ToolCraftのUnix Permissions Calculator を使ってchmod値を実行前に確認しています。チェックボックスから正確な8進数が表示されるので、深夜2時に自信が持てないときに重宝します。ブラウザ上で動作し、何もアップロードされません。
cronにディスク容量モニターを設定しておくと、クォータ問題が障害を引き起こす前に検知できます:
#!/bin/bash
THRESHOLD=85
USAGE=$(df /var/www/html | awk 'NR==2 {print $5}' | sed 's/%//')
if [ "$USAGE" -gt "$THRESHOLD" ]; then
echo "Disk at ${USAGE}% on $(hostname)" | mail -s "[Alert] Disk Space" admin@yourdomain.com
fi
# cronに追加する
*/30 * * * * /usr/local/bin/check-disk.sh
もう一点:古い一時ファイルを削除するクリーンアップスクリプトから uploads ディレクトリを除外してください。誤ったパスを指定した過激なログローテーションスクリプトが、アップロードフォルダ全体を削除してしまったケースがあります。それは痛い経験として学ぶ教訓です。

