You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP通过exec执行SSH命令时的SSH密钥认证问题排查

解决PHP CLI执行SSH命令的认证问题

我之前也碰到过一模一样的问题——手动在shell里能免密SSH到目标服务器,但PHP CLI脚本执行就卡壳,还出现认证失败的日志。核心原因其实是PHP进程的运行环境和你手动打开shell时的环境不一样,导致它找不到你的SSH密钥,或者用了错误的用户身份。下面是几个亲测有效的解决方案:

1. 直接在SSH命令里指定密钥路径

PHP CLI可能没有自动加载你默认的SSH密钥(比如~/.ssh/id_rsa),最直接的办法就是在ssh命令里用-i参数明确指定密钥文件的绝对路径。修改你的$localCmd变量:

$localCmd = 'ssh -i /home/你的本地用户名/.ssh/id_rsa -o StrictHostKeyChecking=no myuser@uk-staging.internal.myhost.com "mkdir -p /home/deploy/backups/etl; rm -f /home/deploy/backups/etl/*.gz; rm -f /home/deploy/backups/etl/*.csv; sudo chown myhost:mysql /home/deploy/backups/etl"';

记得把/home/你的本地用户名/.ssh/id_rsa替换成你实际的密钥路径,比如你手动登录shell的用户是john,那路径就是/home/john/.ssh/id_rsa。

2. 确认PHP CLI的运行用户身份

有时候你以为PHP用的是当前用户,但实际可能不是。在你的serverCmd函数开头加一行代码,看看PHP到底以哪个用户运行:

private function serverCmd($server, $cmd, $exec = false) {
    // 新增:打印PHP运行的用户
    echo "PHP运行用户:" . exec('whoami') . "\n";
    $line = system("whoami");
    // ... 其余代码不变
}

如果输出的用户和你手动登录shell的用户不一样(比如你用普通用户john,但PHP用root或者www-data运行),那肯定会找不到你的密钥。这时候要么切换到正确的用户运行PHP脚本(比如su john -c "php your-script.php"),要么给那个用户配置免密登录目标服务器(生成新的SSH密钥,把公钥传到目标服务器的~/.ssh/authorized_keys里)。

3. 确保SSH密钥和目录的权限符合要求

SSH对密钥文件的权限要求非常严格,只要权限不对就会拒绝使用。执行下面的命令修复权限:

# 设置.ssh目录权限为700(只有所有者能访问)
chmod 700 /home/你的本地用户名/.ssh
# 设置密钥文件权限为600(只有所有者可读可写)
chmod 600 /home/你的本地用户名/.ssh/id_rsa
# 确保密钥文件的所有者是PHP运行的用户
chown 你的用户名:你的用户名 /home/你的本地用户名/.ssh/id_rsa

如果PHP运行的用户不是密钥的所有者,就算路径对了也读不到密钥,这一步很容易忽略!

4. 开启SSH调试模式定位问题

如果上面的办法都没用,就给SSH命令加-v参数开启调试模式,看看具体哪一步出错了。修改代码捕获详细输出:

// 把原来的system调用改成exec,同时捕获错误输出
$output = array();
exec($localCmd . ' -v 2>&1', $output);
print_r($output);

这样你就能看到SSH的完整交互日志,比如是不是找不到密钥文件、密钥被目标服务器拒绝、或者有其他认证方式的问题,根据日志就能精准定位。

5. 配置SSH Config文件(可选但推荐)

为了避免每次都手动指定密钥,你可以在~/.ssh/config里添加目标服务器的配置,让SSH自动用正确的参数连接:

Host uk-staging
    HostName uk-staging.internal.myhost.com
    User myuser
    IdentityFile /home/你的本地用户名/.ssh/id_rsa
    StrictHostKeyChecking no

然后修改你的$localCmd为:

$localCmd = 'ssh uk-staging "mkdir -p /home/deploy/backups/etl; rm -f /home/deploy/backups/etl/*.gz; rm -f /home/deploy/backups/etl/*.csv; sudo chown myhost:mysql /home/deploy/backups/etl"';

这样不管是手动shell还是PHP执行,都会用同一个配置,减少出错的概率。


最常见的问题就是PHP运行用户和你手动shell的用户不一致,或者密钥路径/权限不对。先排查用户身份,再指定密钥路径,基本就能解决问题。

内容的提问来源于stack exchange,提问作者user794846

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 04:00:23