How to Grant www-data Permission to Execute a Specific Shell Script on Nginx Server


3 views

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