Apache runs PHP as www-data, not as your user. SSH keys and file permissions that work perfectly in your terminal will silently fail when Apache tries to use them. This article explains why, and how to fix it correctly.
The Problem
# As your user (deploy): works fine
ssh git@github.com # succeeds
php webhook.php # succeeds
# Apache (www-data): silent failure
# Apache tries to use /var/www/.ssh/id_rsa owned by deploy:deploy with permissions 600
# www-data cannot read the key → authentication fails with a cryptic error
The failure manifests as: "Permission denied (publickey)" or "Could not create directory '/var/www/.ssh'" — depending on which step fails first.
SSH Key Ownership
# Option 1: Give www-data its own SSH key
sudo -u www-data ssh-keygen -t ed25519 -f /var/www/.ssh/id_ed25519 -N ""
# Register the public key where needed (GitHub, server, etc.)
# Verify permissions (SSH requires these exact permissions)
ls -la /var/www/.ssh/
# drwx------ 2 www-data www-data 4096 id_ed25519
# -rw------- 1 www-data www-data 411 id_ed25519
# -rw-r--r-- 1 www-data www-data 97 id_ed25519.pub
# Configure SSH to use this key
echo "Host *" > /var/www/.ssh/config
echo " IdentityFile /var/www/.ssh/id_ed25519" >> /var/www/.ssh/config
chmod 600 /var/www/.ssh/config
chown www-data:www-data /var/www/.ssh/config
File Permission Strategies for Shared Access
When both your user and www-data need to read/write the same directory (e.g., /var/log/the legal SaaS platform), use a shared group:
# Create a shared group
sudo groupadd webteam
sudo usermod -aG webteam www-data
sudo usermod -aG webteam deploy
# Set the directory to group-writable with sticky bit
sudo chown root:webteam /var/log/the legal SaaS platform
sudo chmod 2775 /var/log/the legal SaaS platform # setgid: new files inherit the group
# Log files created by www-data will be group:webteam, readable by deploy
Why CLI Tests Pass but Web Requests Fail
When you run php test.php from the terminal, the script runs as you (deploy). When Apache runs the same script, it runs as www-data. Any resource the script accesses — files, SSH keys, environment variables, system calls — is accessed as www-data.
Test as www-data to reproduce the exact failure:
sudo -u www-data php /var/www/webhook.php
sudo -u www-data curl http://localhost:9010/health
sudo -u www-data ls /var/log/the legal SaaS platform
What to Watch For
- HOME environment variable — When PHP runs as www-data,
getenv('HOME')returns '/var/www' or is unset. Tools that look for config in~/.configwill look in/var/www/.config— which usually doesn't exist. - ACLs for fine-grained access — If group-based sharing is too coarse, use POSIX ACLs:
setfacl -m u:www-data:rw /path/to/file. More precise but harder to audit.