2026年5月17日

2026年5月17日

WordPressのアップロードディレクトリのパーミッションエラーを解決する方法

はじめに

WordPressでメディアをアップロードしようとした際に「Unable to create directory wp-content/uploads/2026/05. Is its parent directory writable by the server?」というエラーが表示されることがあります。これはWebサーバーのプロセスがアップロードディレクトリへの書き込み権限を持っていないことが原因です。本記事ではパーミッション・所有者の修正から、カスタムディレクトリの設定・セキュアな管理方法まで解説します。

症状・原因

  • 画像や動画のアップロード時に「Unable to create directory」エラーが出る
  • wp-content/uploads ディレクトリの所有者が Web サーバーのユーザー(www-data など)ではない
  • ディレクトリのパーミッションが 700 など、サーバープロセスからアクセスできない設定になっている
  • FTP でファイルを転送したため所有者が FTP ユーザーになっている
  • SELinux や AppArmor がファイルへのアクセスをブロックしている

解決手順

ステップ1:現在の所有者とパーミッションを確認する

# wp-content/uploads の所有者とパーミッションを確認する
ls -la /var/www/html/wp-content/
# 出力例:
# drwxr-xr-x  2 ftpuser ftpuser  4096 May 16 10:00 uploads
# ↑ 所有者が ftpuser になっていて、www-data が書き込めない

# Webサーバーが動いているユーザーを確認する
# Apache の場合
ps aux | grep apache | head -1
# Nginx + PHP-FPM の場合
ps aux | grep php-fpm | head -1
# 一般的な値:www-data(Ubuntu/Debian)、nginx(CentOS)、apache(RHEL)

# WordPress が期待するアップロードパスを確認する
wp eval 'print_r( wp_upload_dir() );'
# basedir と baseurl が正しいか確認する

# SELinux の確認(CentOS/RHEL の場合)
getenforce
ls -Z /var/www/html/wp-content/uploads/

ステップ2:ディレクトリとファイルのパーミッションを正しく設定する

# ディレクトリに 755、ファイルに 644 を設定する(推奨構成)

# uploads ディレクトリ以下の全ディレクトリを 755 に設定
find /var/www/html/wp-content/uploads -type d \
    -exec chmod 755 {} \;

# uploads ディレクトリ以下の全ファイルを 644 に設定
find /var/www/html/wp-content/uploads -type f \
    -exec chmod 644 {} \;

# uploads ディレクトリ自体のパーミッションも確認
chmod 755 /var/www/html/wp-content/uploads

# WordPress コアファイルの推奨パーミッション
# ディレクトリ:755
# ファイル:644
# wp-config.php:600(最小権限)
chmod 600 /var/www/html/wp-config.php

# パーミッション設定後に確認する
ls -la /var/www/html/wp-content/uploads/

ステップ3:所有者を Web サーバーのユーザーに変更する

# Ubuntu/Debian(Apache または Nginx + PHP-FPM)の場合
sudo chown -R www-data:www-data /var/www/html/wp-content/uploads

# CentOS/RHEL(Apache)の場合
sudo chown -R apache:apache /var/www/html/wp-content/uploads

# CentOS/RHEL(Nginx + PHP-FPM)の場合
sudo chown -R nginx:nginx /var/www/html/wp-content/uploads

# 所有者変更後に確認する
ls -la /var/www/html/wp-content/

# WordPress ルート全体の所有者を修正する場合(注意して実行)
# FTP ユーザーも書き込める構成にする場合(グループを活用)
sudo usermod -aG www-data ftpuser
sudo chown -R ftpuser:www-data /var/www/html/wp-content/uploads
find /var/www/html/wp-content/uploads -type d -exec chmod 775 {} \;
find /var/www/html/wp-content/uploads -type f -exec chmod 664 {} \;

# SELinux の場合:コンテキストを修正する
sudo semanage fcontext -a -t httpd_sys_rw_content_t \
    '/var/www/html/wp-content/uploads(/.*)?'
sudo restorecon -Rv /var/www/html/wp-content/uploads

ステップ4:UPLOADS 定数と upload_dir フィルターでカスタムディレクトリを設定する

<?php
// wp-config.php でアップロード先ディレクトリを変更する
// UPLOADS は wp-config.php で設定する(wp-content/uploads がデフォルト)
// パスは WordPress のインストールディレクトリからの相対パス
define( 'UPLOADS', 'wp-content/media' ); // カスタムパスに変更

// より柔軟な設定は upload_dir フィルターを使用する(functions.php)
add_filter( 'upload_dir', 'custom_upload_directory' );

function custom_upload_directory( $dirs ) {
    // 年月サブディレクトリを使わずにフラットな構造にする
    $custom_dir = '/uploads-flat';

    $dirs['subdir'] = $custom_dir;
    $dirs['path']   = $dirs['basedir'] . $custom_dir;
    $dirs['url']    = $dirs['baseurl'] . $custom_dir;

    return $dirs;
}

// ユーザーごとに分けたアップロードディレクトリ
add_filter( 'upload_dir', 'user_specific_upload_directory' );

function user_specific_upload_directory( $dirs ) {
    $user_id = get_current_user_id();

    if ( $user_id ) {
        $subdir = '/users/' . $user_id;

        $dirs['subdir'] = $subdir;
        $dirs['path']   = $dirs['basedir'] . $subdir;
        $dirs['url']    = $dirs['baseurl'] . $subdir;

        // ディレクトリが存在しない場合は作成する
        if ( ! file_exists( $dirs['path'] ) ) {
            wp_mkdir_p( $dirs['path'] );
        }
    }

    return $dirs;
}

ステップ5:アップロードディレクトリをウェブルート外に移動してセキュリティを強化する

<?php
// wp-config.php でアップロード先をウェブルート外に設定する
// (セキュリティ上、実行可能ファイルをウェブから直接アクセスさせない)

// ウェブルート外のパス(例:/var/uploads)
define( 'UPLOADS', '../uploads' ); // ウェブルートの1つ上

// または upload_dir フィルターで絶対パスを指定する
add_filter( 'upload_dir', 'secure_upload_directory' );

function secure_upload_directory( $dirs ) {
    // ウェブルート外のディレクトリ
    $secure_dir  = '/var/wordpress-uploads';
    $secure_url  = 'https://example.com/uploads-proxy'; // プロキシ経由で配信

    $dirs['basedir'] = $secure_dir;
    $dirs['baseurl'] = $secure_url;
    $dirs['path']    = $secure_dir . $dirs['subdir'];
    $dirs['url']     = $secure_url . $dirs['subdir'];

    return $dirs;
}
# Nginx でウェブルート外のアップロードを配信するプロキシ設定
server {
    # アップロードファイルをウェブルート外から配信する
    location /uploads-proxy/ {
        alias /var/wordpress-uploads/;

        # PHP ファイルの実行を禁止(セキュリティ)
        location ~* \.php$ {
            deny all;
        }

        # SVG・HTML ファイルも制限する
        location ~* \.(html|htm|svg)$ {
            add_header Content-Type text/plain;
        }
    }
}

注意事項

  • 実行可能ファイルのアップロード: .php ファイルがアップロードされ実行されるとサーバーが乗っ取られます。アップロードディレクトリで PHP の実行を Nginx/Apache で禁止してください。
  • 777 パーミッションは使用しない: chmod 777 はすべてのユーザーに書き込み権限を与えるため非常に危険です。問題が解決しても 755/644 に戻してください。
  • バックアップ: 所有者変更の前に、現在の設定をメモまたはスクリプトで記録しておきましょう。

まとめ

アップロードパーミッションエラーは「所有者の確認→chmod/chown で修正→カスタムディレクトリの設定→セキュリティ強化」の手順で根本的に解決できます。ウェブルート外へのアップロード配置まで実施すれば、マルウェアのアップロード・実行リスクを大幅に低減できます。関連記事:WordPressのXMLRPC脆弱性を無効化してセキュリティを強化する方法

お気軽にご相談ください

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