When working with PHP on an Nginx server, you might encounter permission issues when trying to execute shell scripts. The www-data user (Nginx's default user) often lacks sufficient permissions to run scripts, especially when security measures are in place.
The "Operation Not Permitted" error typically occurs when:
- You don't have sudo privileges
- The file system is mounted with noexec option
- SELinux or AppArmor is enforcing strict policies
Here's how to safely grant www-data permission to execute only boot.sh:
# First, check current permissions
ls -la /path/to/boot.sh
# Make sure the script is executable
sudo chmod +x /path/to/boot.sh
# Change group ownership to www-data
sudo chgrp www-data /path/to/boot.sh
# Set appropriate permissions (owner: rwx, group: r-x, others: ---)
sudo chmod 750 /path/to/boot.sh
For more granular control, you can configure sudo to allow www-data to run only this specific script:
# Edit sudoers file
sudo visudo
# Add this line at the bottom
www-data ALL=(ALL) NOPASSWD: /path/to/boot.sh
Then in your PHP code:
<?php
// Execute the script with sudo
shell_exec('sudo /path/to/boot.sh');
?>
When implementing this solution:
- Always validate and sanitize any input passed to the script
- Regularly audit the script for vulnerabilities
- Consider using a dedicated system user instead of www-data for critical operations
If you still face issues:
# Check if the filesystem is mounted with noexec
mount | grep noexec
# Verify SELinux/AppArmor status
sestatus # For SELinux
aa-status # For AppArmor
When trying to execute shell scripts from PHP (particularly under Nginx with www-data user), permission issues frequently arise. The error Operation Not Permitted
typically indicates either:
- Incorrect ownership of the script file
- Missing execute permissions
- SELinux/AppArmor restrictions (on some systems)
Here's the proper way to set permissions without compromising security:
# First check current permissions
ls -la /path/to/boot.sh
# Set ownership to root:www-data
sudo chown root:www-data /path/to/boot.sh
# Set restrictive permissions (750 = owner RWX, group RX, others nothing)
sudo chmod 750 /path/to/boot.sh
# Verify changes
ls -la /path/to/boot.sh
From PHP, you can execute the script using several approaches:
// Method 1: shell_exec
$output = shell_exec('/path/to/boot.sh 2>&1');
// Method 2: exec with full path
exec('/usr/bin/sudo -u www-data /path/to/boot.sh', $output, $return_var);
// Method 3: Symfony Process component (recommended)
use Symfony\Component\Process\Process;
$process = new Process(['/path/to/boot.sh']);
$process->run();
If you still encounter problems:
# Check if www-data is in the correct group
groups www-data
# Verify script has proper shebang
head -1 /path/to/boot.sh # Should show #!/bin/bash or similar
# Test direct execution as www-data
sudo -u www-data /path/to/boot.sh
For RHEL/CentOS systems:
# Check current context
ls -Z /path/to/boot.sh
# Set proper context
sudo chcon -t httpd_sys_script_exec_t /path/to/boot.sh
- Never set 777 permissions
- Validate all input if passing parameters to the script
- Consider using sudoers to limit www-data's capabilities
- Log all script executions
# Example sudoers entry (via visudo)
www-data ALL=(root) NOPASSWD: /path/to/boot.sh