When dealing with file uploads in AWS Elastic Beanstalk PHP environments (particularly with ExpressionEngine), even properly configured PHP settings don't always guarantee successful large file transfers to S3. Here's what's happening under the hood:
While you've correctly set:
upload_max_filesize = 16M
post_max_size = 32M
max_execution_time = 300
Elastic Beanstalk adds several layers of complexity:
- NGINX/Apache reverse proxy configurations
- Elastic Load Balancer (ELB) timeouts
- S3 SDK transfer constraints
- ExpressionEngine's own file handling
Most developers miss these EB-specific settings that override PHP configurations:
# In your .ebextensions/php_settings.config
files:
"/etc/nginx/conf.d/proxy.conf":
content: |
client_max_body_size 50M;
proxy_read_timeout 600;
proxy_connect_timeout 600;
proxy_send_timeout 600;
For reliable large file uploads to S3 via ExpressionEngine, consider this custom approach:
// In your EE config
$config['s3_upload_options'] = [
'version' => 'latest',
'region' => 'us-east-1',
'http' => [
'timeout' => 600,
'connect_timeout' => 600
],
'multipart_threshold' => 8 * 1024 * 1024 // 8MB
];
// Custom upload handler
function custom_s3_upload($file_path) {
$s3 = new Aws\S3\S3Client($config['s3_upload_options']);
try {
$result = $s3->putObject([
'Bucket' => 'your-bucket',
'Key' => 'uploads/'.basename($file_path),
'Body' => fopen($file_path, 'rb'),
'ACL' => 'public-read',
'ContentType' => mime_content_type($file_path)
]);
return $result['ObjectURL'];
} catch (Aws\S3\Exception\S3Exception $e) {
error_log("S3 Upload Error: ".$e->getMessage());
return false;
}
}
Add this to your .ebextensions:
option_settings:
aws:elasticbeanstalk:environment:proxy:
Timeout: 600
aws:elasticbeanstalk:environment:processdefault:
HealthCheckTimeout: 600
Create a test endpoint to identify where the upload fails:
// Test route in EE
$config['test_upload'] = function() {
header('Content-Type: application/json');
// Test PHP settings
$php_settings = [
'upload_max_filesize' => ini_get('upload_max_filesize'),
'post_max_size' => ini_get('post_max_size'),
'max_execution_time' => ini_get('max_execution_time')
];
// Test actual file upload
$test_file = tempnam(sys_get_temp_dir(), 'upload_test_');
file_put_contents($test_file, str_repeat('0', 6 * 1024 * 1024)); // 6MB file
try {
$uploaded = move_uploaded_file($_FILES['test']['tmp_name'], $test_file);
$s3_test = custom_s3_upload($test_file);
} catch (Exception $e) {
http_response_code(500);
die(json_encode(['error' => $e->getMessage()]));
}
echo json_encode([
'php_settings' => $php_settings,
'local_upload' => $uploaded,
's3_upload' => $s3_test !== false
]);
};
- .ebextensions for proxy timeouts
- ELB timeout settings
- S3 multipart configuration
- EE file manager hooks
- PHP error logging configured
When dealing with file uploads in AWS Elastic Beanstalk environments, the most frustrating scenario occurs when:
- Progress bar completes 100%
- No explicit error appears
- Application silently redirects or fails
- Files under threshold work perfectly
While you've correctly identified the primary PHP settings, EB requires additional layers of configuration:
; PHP.ini essentials (verify via phpinfo())
upload_max_filesize = 16M
post_max_size = 32M
max_execution_time = 300
memory_limit = 128M ; Often overlooked
AWS EB Linux 2+ platforms use nginx as reverse proxy. The default client_max_body_size is 1MB:
# Create .ebextensions/01_nginx.config
files:
"/etc/nginx/conf.d/proxy.conf":
mode: "000644"
owner: root
group: root
content: |
client_max_body_size 20M;
When uploading directly to S3 via ExpressionEngine:
// Sample EE config.php adjustments
$config['s3_upload_threshold'] = 5242880; // 5MB in bytes
$config['s3_multipart_part_size'] = 5242880;
Create a test endpoint to isolate the issue:
// upload_test.php
<?php
header('Content-Type: text/plain');
echo "PHP Limits:\n";
echo 'upload_max_filesize: ' . ini_get('upload_max_filesize') . "\n";
echo 'post_max_size: ' . ini_get('post_max_size') . "\n\n";
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (empty($_FILES)) {
echo "ERROR: No file received (check nginx/client_max_body_size)";
} else {
move_uploaded_file($_FILES['file']['tmp_name'], '/tmp/test_upload');
echo "Success! File size: " . $_FILES['file']['size'] . " bytes";
}
}
?>
Check these critical logs when failures occur:
- /var/log/nginx/error.log
- /var/log/php-fpm.log
- ExpressionEngine's error log
- AWS SDK debug logs (when using S3)
ExpressionEngine has its own timeout settings separate from PHP:
// In config.php
$config['max_upload_size'] = 16000000; // ~16MB
$config['max_upload_seconds'] = 600; // 10 minutes