Troubleshooting PHP fopen() Permission Denied Errors in AWS WordPress Migration


2 views

During my recent AWS migration of WordPress sites, I encountered a stubborn issue where simple file operations kept failing with "Permission denied" errors. The problem manifested even with basic fopen() calls:

<?php 
$handle = fopen('test.txt', 'w') or die("Can't open file");
?>

First, I verified all the standard permission configurations:

  • Directory permissions set to 755 (drwxr-xr-x)
  • Correct ownership throughout the entire path (/home to target directory)
  • Confirmed working directory with getcwd()
  • PHP script has 644 permissions and matching ownership

When basic checks didn't resolve the issue, I dug deeper into server configuration:

<?php
// Check PHP safe mode status
echo 'Safe mode: ' . ini_get('safe_mode') . "\n";

// Verify disabled functions
print_r(ini_get('disable_functions'));

// Check open_basedir restrictions
echo 'open_basedir: ' . ini_get('open_basedir');
?>

The real breakthrough came when I discovered discrepancies between command line and web execution contexts:

<?php
// Better process inspection
echo exec('ps -up '.getmypid());

// Alternative UID/GID check for web context
echo "Web server user: " . exec('whoami');
?>

Key findings:

  • Files created via web had Apache ownership despite suexec configuration
  • Command line execution produced correct ownership
  • Process inspection revealed unexpected user context

After thorough investigation, these steps resolved the issue:

  1. Verify suexec configuration:
    # Check suexec compilation options
    /usr/sbin/suexec -V
  2. Adjust virtual host configuration:
    <VirtualHost *:80>
        SuexecUserGroup username groupname
        # Other directives...
    </VirtualHost>
  3. Implement proper directory structure:
    chown -R username:groupname /home/username
    chmod 755 /home/username
    chmod 755 /home/username/public_html

To avoid similar issues in future migrations:

<?php
// Safe file operations wrapper
function safe_file_create($path, $content) {
    $dir = dirname($path);
    if (!is_writable($dir)) {
        throw new Exception("Directory not writable: $dir");
    }
    
    $temp = tempnam($dir, 'tmp');
    if (file_put_contents($temp, $content) !== false) {
        if (rename($temp, $path)) {
            chmod($path, 0644);
            return true;
        }
    }
    @unlink($temp);
    return false;
}
?>

During my recent WordPress migration to AWS, I encountered a persistent fopen() permission denied error that seemed to defy all standard troubleshooting approaches. The basic test case:

<?php 
$handle = fopen('test.txt', 'w') or die('Can\'t open file');
?>

kept failing despite proper directory permissions (755) and correct ownership throughout the path.

  • Verified directory permissions with ls -la
  • Confirmed working directory with getcwd()
  • Matched script ownership with target directory
  • Disabled PHP safe mode in php.ini
  • Ensured fopen wasn't in disabled_functions
  • Disabled open_basedir restrictions

The real breakthrough came when I noticed files created via web execution had Apache ownership, while CLI execution produced correct permissions. This pointed to mod_suexec misconfiguration.

Instead of relying on getmyuid() (which shows script owner, not runtime user), use:

<?php 
echo exec('ps -up '.getmypid()); 
?>

For AWS environments running WordPress with mod_suexec, implement these steps:

  1. Verify actual runtime user:
    <?php
    // Better user detection
    function get_runtime_user() {
        return exec('whoami');
    }
    echo 'Running as: '.get_runtime_user();
    ?>
  2. Directory permission best practices:
    # Set proper ownership recursively
    chown -R www-data:www-data /var/www/html
    find /var/www/html -type d -exec chmod 755 {} \;
    find /var/www/html -type f -exec chmod 644 {} \;
  3. WordPress-specific fixes:
    # Add to wp-config.php
    define('FS_METHOD', 'direct');
    define('FS_CHMOD_DIR', (0755 & ~ umask()));
    define('FS_CHMOD_FILE', (0644 & ~ umask()));

When standard approaches fail, try these advanced methods:

<?php
// Check SELinux context (if applicable)
echo exec('ls -Z '.escapeshellarg(dirname(__FILE__)));

// Test actual write capability
$testfile = 'permission_test_'.time().'.txt';
if (file_put_contents($testfile, 'test') === false) {
    $error = error_get_last();
    echo "Write failed: ".$error['message'];
} else {
    unlink($testfile);
    echo "Write successful";
}
?>

On AWS infrastructure, additional factors may include:

  • EC2 instance IAM roles lacking write permissions
  • EBS volume mount options restricting file operations
  • Security group rules interfering with certain operations
  • CloudWatch logging conflicts

Always check AWS system logs for additional clues:

tail -f /var/log/syslog | grep -i permission