关键在于app_key、ssh_key、.env三者必须在正确环节以正确方式注入:app_key需预存github secrets并注入key:generate命令,ssh_key须以pem格式存为secret用于rsync/ssh,.env需动态追加密钥而非简单复制.example,缺一即导致composer install、migrate或ssh失败。

能跑通的 Laravel + GitHub Actions 自动部署,关键不在“有没有”,而在“APP_KEY、SSH_KEY、.env 三者是否在正确环节以正确方式注入”。漏掉任何一个,就会卡在 composer install、php artisan migrate 或 SSH 连接失败上。
为什么 composer install 总是卡住或报错
Laravel 的 composer.json 通常声明了 "platform": {"php": "8.2"},但 GitHub 默认 runner 的 PHP 版本可能是 8.0 或未启用扩展。不显式指定,composer install 就会因平台不匹配失败,或因缺 ext-pdo_mysql 等扩展直接中断。
- 必须用
shivammathur/setup-php@v2(不是actions/setup-php)显式设置版本和扩展:php-version: '8.2',extensions: mbstring, pdo, mysql, curl, json, xml, ctype - 加
--ignore-platform-req=ext-*跳过扩展检查(仅限 CI,非本地开发) -
composer install --no-interaction --prefer-dist --optimize-autoloader --no-dev:禁用 dev 依赖可大幅缩短安装时间,也避免测试工具污染生产环境
php artisan migrate 执行失败的常见原因
不是数据库连不上,就是 .env 没生效——而这两者都源于环境变量没对齐。
-
.env文件不能靠cp .env.example .env生成:它没填APP_KEY、DB_PASSWORD等值,artisan 会拒绝启动 - 必须用
echo动态写入测试/部署专用.env,例如:echo "APP_KEY=${{ secrets.APP_KEY }}" >> .env,再逐行追加其他密钥 - 如果用 MySQL service(如
mysql容器),DB_HOST必须设为mysql(service 名),不是localhost;且需用wait-for-it.sh或自定义脚本轮询mysql:3306就绪,否则phpunit或migrate会因连接超时失败
如何安全地把代码推到服务器(不是上传 zip)
GitHub Actions 本身不执行远程命令,得靠 ssh + rsync 组合完成。硬编码私钥或明文写密码等于裸奔。
-
SSH_KEY必须存为 GitHub Secret,且内容是 PEM 格式私钥(含-----BEGIN OPENSSH PRIVATE KEY-----头尾) - 目标服务器必须提前配置好:用户有
www-data组权限、/var/www/example.com目录存在、storage和bootstrap/cache可写 - 推荐用 rsync 增量同步:
rsync -avz --delete -e "ssh -o StrictHostKeyChecking=no -i ${{ secrets.SSH_KEY }}" ./ user@${{ secrets.SSH_HOST }}:/var/www/example.com/current/ - 零停机发布靠软链接:
ssh -i ${{ secrets.SSH_KEY }} user@${{ secrets.SSH_HOST }} "cd /var/www/example.com && ln -nfs current release && chown -R www-data:www-data release"
容易被忽略的部署后清理动作
部署完不清理缓存、不重置权限,下次部署就可能因旧缓存或错误 owner 导致 500 错误。
- 必须在远程服务器上运行:
php artisan config:clear && php artisan cache:clear && php artisan view:clear -
chmod -R 775 storage bootstrap/cache和chown -R www-data:www-data storage bootstrap/cache不能少,尤其当部署用户不是www-data时 - 如果用了
Spatie\Permission,记得补上php artisan permission:cache-reset,否则新权限不会生效











