2026年7月12日

2026年7月12日

WordPressの.htaccessエラー(500エラー・パーマリンクが機能しない)を解決する方法

はじめに

WordPressの.htaccessファイルを編集したら500 Internal Server Errorになった・カスタムパーマリンクに変更したのに投稿のURLにアクセスすると404になる・WordPress管理画面の「パーマリンク設定」で「変更を保存」してもパーマリンクが機能しない・共有ホスティングで.htaccessが書き込み権限なく自動更新されないといった問題は、シンタックスエラー・mod_rewriteの無効化・AllowOverride None設定・ファイルパーミッションの不正が原因です。

症状・原因

  • .htaccessに構文エラーがありApacheが設定を読み込めない(500エラーの原因)
  • サーバーの設定でAllowOverride Noneが設定されており.htaccessが無視されている
  • mod_rewriteモジュールがApacheで有効化されていない
  • wp-content/ディレクトリの所有者がWebサーバーのユーザーと異なりファイルを書き込めない

解決手順

ステップ1:.htaccessの状態を診断する

# .htaccessの構文をApacheでテスト(root権限が必要)
# apachectl -t

# .htaccessファイルの存在と権限を確認
ls -la /var/www/html/.htaccess

# mod_rewriteが有効か確認
wp eval "
// Apache mod_rewrite の確認
if (function_exists('apache_get_modules')) {
    \$modules = apache_get_modules();
    echo 'mod_rewrite: ' . (in_array('mod_rewrite', \$modules) ? 'enabled' : 'DISABLED') . PHP_EOL;
} else {
    echo 'apache_get_modules() not available (Nginx or PHP-FPM?)' . PHP_EOL;
}
"

# .htaccessの内容を確認
wp eval "
\$htaccess = ABSPATH . '.htaccess';
if (file_exists(\$htaccess)) {
    echo file_get_contents(\$htaccess);
} else {
    echo '.htaccess does not exist!' . PHP_EOL;
}
"

# パーマリンク設定を確認
wp option get permalink_structure
wp rewrite list --format=table | head -20

ステップ2:.htaccessを正しいWordPress標準に戻す

# .htaccessを標準形式に戻す(WP-CLIで再生成)
wp eval "
global \$wp_rewrite;
\$wp_rewrite->set_permalink_structure('/%postname%/');
\$wp_rewrite->flush_rules(true);
echo 'Permalink structure reset and .htaccess regenerated.' . PHP_EOL;
"

# .htaccessの書き込み権限を修正
# chmod 644 /var/www/html/.htaccess
# chown www-data:www-data /var/www/html/.htaccess

WordPress標準の.htaccessの正しい内容:

# BEGIN WordPress
# このブロックはWordPressが自動生成します - 手動編集は上か下に追加
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress

ステップ3:Apache・Nginxの設定でmod_rewriteを有効化する

Apacheの場合(/etc/apache2/sites-available/000-default.conf):

<VirtualHost *:80>
    ServerName example.com
    DocumentRoot /var/www/html

    <Directory /var/www/html>
        Options Indexes FollowSymLinks
        AllowOverride All          # .htaccess を有効化(None → All)
        Require all granted
    </Directory>

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
# mod_rewriteを有効化してApacheを再起動(Ubuntuの場合)
# a2enmod rewrite
# systemctl restart apache2

# Apache設定テスト
# apachectl configtest

# Nginx + PHP-FPM の場合(try_files で WordPress をサポート)
# server {
#     location / {
#         try_files $uri $uri/ /index.php?$args;
#     }
# }

ステップ4:.htaccessにカスタムルールを安全に追加する

// functions.php: .htaccessにカスタムルールをWordPressのAPIで追加

// WordPress のフックを使って .htaccess に安全にルールを追加
add_filter('mod_rewrite_rules', function(string $rules): string {
    $custom = "<IfModule mod_headers.c>\n";
    $custom .= "  Header always set X-Content-Type-Options nosniff\n";
    $custom .= "  Header always set X-Frame-Options SAMEORIGIN\n";
    $custom .= "</IfModule>\n\n";
    return $custom . $rules;
});

// PHP経由で .htaccess に書き込む(insert_with_markers を使用)
add_action('admin_init', function(): void {
    if (!isset($_GET['add_htaccess_rules']) || !current_user_can('manage_options')) {
        return;
    }
    $htaccess_path = ABSPATH . '.htaccess';
    $lines = [
        'Options -Indexes',
        'ServerSignature Off',
    ];
    insert_with_markers($htaccess_path, 'Security Rules', $lines);
    wp_die('.htaccess security rules added.');
});
# .htaccess: セキュリティ強化ルール(# BEGIN WordPress の前に追加)
# PHPファイルへの直接アクセスを制限
<Files "wp-config.php">
    Require all denied
</Files>

# xmlrpc.phpを無効化(使用しない場合)
<Files "xmlrpc.php">
    Require all denied
</Files>

# .htaccessファイル自体を保護
<Files ".htaccess">
    Require all denied
</Files>

ステップ5:パーマリンクとリライトルールを最適化する

// functions.php: カスタムリライトルールの追加

// カスタムリライトルールを追加
add_action('init', function(): void {
    // /api/{endpoint} を /index.php?api_endpoint={endpoint} にマップ
    add_rewrite_rule(
        '^api/([^/]+)/?$',
        'index.php?api_endpoint=$matches[1]',
        'top'  // 優先度: 'top' または 'bottom'
    );
});

// カスタムクエリ変数を登録
add_filter('query_vars', function(array $vars): array {
    $vars[] = 'api_endpoint';
    return $vars;
});

// リライトルールが更新されているか確認してフラッシュ
add_action('init', function(): void {
    if (get_option('my_plugin_version') !== '1.0.0') {
        flush_rewrite_rules();
        update_option('my_plugin_version', '1.0.0');
    }
});
# 現在のリライトルールを確認
wp rewrite list --format=table

# リライトルールをリセット
wp rewrite flush --hard

# 特定のURLが正しくマッチするか確認
wp eval "
\$url = '/product/sample-item/';
\$request = new WP(\$url);
\$request->parse_request();
echo 'Matched: ' . print_r(\$request->query_vars, true);
"

注意事項

  • .htaccess# BEGIN WordPress# END WordPressの間のコードは編集しないでください。この範囲はWordPressが自動管理しており、パーマリンク設定保存時に上書きされます
  • AllowOverride Allはセキュリティ上のリスクがあります。本番環境では必要なディレクティブのみを許可するAllowOverride FileInfo Optionsなどの絞り込みを検討してください
  • Nginxを使用している場合は.htaccessは機能しません。Nginxの設定ファイルに直接try_files $uri $uri/ /index.php?$args;を記述する必要があります

まとめ

WordPress .htaccessエラーの解決は①apachectl -tで構文チェック・ls -laで権限確認・apache_get_modules()でmod_rewrite有効確認・wp option get permalink_structureで設定確認、②$wp_rewrite->flush_rules(true)でWordPressの標準.htaccessを再生成・chmod 644chownで権限を正しく設定、③ApacheのAllowOverride Allを設定・a2enmod rewriteでmod_rewriteを有効化・Nginxはtry_filesでWordPressをサポート、④mod_rewrite_rulesフィルターまたはinsert_with_markers()でカスタムルールを追加・wp-config.phpxmlrpc.phpへの直接アクセスをブロック、⑤add_rewrite_rule()でカスタムリライトを追加・query_varsフィルターでカスタムクエリ変数を登録・バージョン比較でflush_rewrite_rules()を一度だけ実行の手順で解決します。

お気軽にご相談ください

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