site logo

Marico's space

如何使用 GitHub Actions 自动部署 Laravel 应用到 DigitalOcean

AI技术与应用 2026-05-17 12:05:21 17

如何使用 GitHub Actions 自动部署 Laravel 应用到 DigitalOcean

手动部署 Laravel 应用这事儿,一旦项目频繁更新,就会变成纯粹的体力活。每次都要 SSH 连上服务器跑一堆命令,久了真的烦。最近折腾了一下 GitHub Actions 的 CI/CD(持续集成/持续部署),把整个流程自动化了,这篇把踩过的坑和具体做法说清楚。

本文要实现的目标很简单:当你往 main 分支推送代码时,GitHub Actions 自动完成整个部署流程。

整个流程走下来是这样的:

推送到 main 分支 → GitHub Actions 启动 → SSH 连接到服务器 → 拉取最新代码 → 安装依赖 → 构建前端资源 → 执行数据库迁移 → Laravel 优化 → 重启队列处理器

准备工作

开始之前,确保你已经有这些:

  • 一个托管在 GitHub 上的 Laravel 应用

  • 一台运行 Ubuntu 的 DigitalOcean 云服务器

  • Laravel 应用已经在服务器上跑起来了

  • Nginx 或 Apache 已经配置好

  • 服务器上安装了 PHP、Composer、Node.js 和 npm

  • .env 文件里数据库连接已经配好

  • 会用 GitHub 仓库的基本设置

为了安全起见,建议创建一个专门的部署用户,而不是直接用 root。不过这篇文章为了简化演示,我会用 root 来说明。如果是生产环境的项目,还是建议单独建一个有限权限的用户来做部署。

第一步:创建 Laravel 部署脚本

先在 package.json 里写一个 deploy 命令。这样 GitHub Actions 只需要在服务器上执行一条命令就行,不用把一堆部署命令都写在工作流文件里。

打开 package.json,加上这个脚本:

"scripts": { "deploy": "git pull && COMPOSER_ALLOW_SUPERUSER=1 composer install --no-dev --optimize-autoloader && npm ci && npm run build && php artisan migrate --force && php artisan config:cache && php artisan route:cache && php artisan view:cache && php artisan optimize"
}

如果你的项目没有 package-lock.json 文件,把 npm ci 换成 npm install

"scripts": { "deploy": "git pull && COMPOSER_ALLOW_SUPERUSER=1 composer install --no-dev --optimize-autoloader && npm install && npm run build && php artisan migrate --force && php artisan config:cache && php artisan route:cache && php artisan view:cache && php artisan optimize"
}

每个命令的作用

命令 作用
git pull 从 GitHub 拉取最新代码
COMPOSER_ALLOW_SUPERUSER=1 composer install --no-dev --optimize-autoloader 安装生产环境 PHP 依赖,并优化 Composer 自动加载
npm ci 根据 lock 文件安装 JavaScript 依赖,保证构建一致性
npm run build 构建生产环境的前端资源
php artisan migrate --force 强制执行生产环境的数据库迁移
php artisan config:cache 缓存 Laravel 配置
php artisan route:cache 缓存路由
php artisan view:cache 编译并缓存 Blade 模板
php artisan optimize 运行 Laravel 优化命令

注意:执行 php artisan migrate --force 会修改数据库结构。部署之前一定要确保迁移脚本在测试环境跑过,而且要有数据库备份策略。

第二步:创建 GitHub Actions 工作流

接下来在 Laravel 项目里创建 GitHub Actions 工作流文件。

新建这个文件:

.github/workflows/deploy.yml

然后填入以下内容:

name: Deploy to Production on: push: branches: - main jobs: deploy: runs-on: ubuntu-latest steps: - name: Deploy via SSH uses: appleboy/ssh-action@v1.2.0 with: host: ${{ secrets.DROPLET_HOST }} username: ${{ secrets.DROPLET_USER }} key: ${{ secrets.DROPLET_SSH_KEY }} script: | cd /var/www/your-app npm run deploy php artisan queue:restart

/var/www/your-app 换成你服务器上 Laravel 项目的实际路径:

/var/www/your-app

举个例子:

script: | cd /var/www/my-laravel-app npm run deploy php artisan queue:restart

php artisan queue:restart 这个命令会让 Laravel 队列处理器优雅重启,这样它们才能加载新部署的代码。如果你用 Supervisor 管理队列处理器,Supervisor 会自动重新启动它们。

第三步:在本地机器上生成部署用的 SSH 密钥

GitHub Actions 需要 SSH 连接到你的服务器。不要用你自己的个人 SSH 密钥,而是单独建一个专门用于部署的密钥。

在本地机器上运行:

ssh-keygen -t ed25519 -C "your-app-github-deploy" -f ~/.ssh/your-app-github -N ""

这会生成两个文件:

文件 用途
~/.ssh/your-app-github 私钥,需要添加到 GitHub Secrets
~/.ssh/your-app-github.pub 公钥,需要添加到服务器上

私钥不要泄露出去,只能存放在 GitHub Secrets 里。

第四步:把公钥添加到服务器

现在把公钥添加到服务器上,这样 GitHub Actions 才能通过 SSH 连接上来。

Mac 或 Linux

ssh-copy-id -i ~/.ssh/your-app-github.pub root@YOUR_DROPLET_IP

Windows PowerShell

type $env:USERPROFILE\.ssh\your-app-github.pub | ssh root@YOUR_DROPLET_IP "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys"

YOUR_DROPLET_IP 换成你实际的服务器 IP 地址。

可以测试一下 SSH 连接是否正常:

ssh -i ~/.ssh/your-app-github root@YOUR_DROPLET_IP

如果连接成功,说明配置没问题。私钥添加到仓库 Secrets 之后,GitHub Actions 也能正常连接。

第五步:在服务器上创建 GitHub 部署密钥

GitHub Actions 现在可以连接服务器了,但服务器也需要有权限从 GitHub 仓库拉代码。

先 SSH 登录到服务器:

ssh root@YOUR_DROPLET_IP

然后在服务器上生成一个新的 SSH 密钥:

ssh-keygen -t ed25519 -C "your-app-droplet-deploy" -f ~/.ssh/your-app-github -N ""

查看公钥内容:

cat ~/.ssh/your-app-github.pub

复制输出的内容,然后进入你的 GitHub 仓库:

Settings → Deploy keys → Add deploy key

填写部署密钥信息:

字段
Title DigitalOcean Droplet
Key 粘贴服务器上的公钥
Allow write access 不要勾选

只读权限就够了,因为服务器只需要从 GitHub 拉取代码,不需要写入。

添加完部署密钥后,配置服务器的 SSH,让它连接 GitHub 时使用这个密钥:

cat >> ~/.ssh/config <<'EOF'
Host github.com IdentityFile ~/.ssh/your-app-github StrictHostKeyChecking no
EOF chmod 600 ~/.ssh/config

测试服务器能否连接到 GitHub:

ssh -T git@github.com

如果配置正确,GitHub 会识别这个连接。

第六步:添加 GitHub 仓库 Secrets

现在把 SSH 连接信息添加到 GitHub Secrets。

进入你的 GitHub 仓库:

Settings → Secrets and variables → Actions → New repository secret

添加以下 Secrets:

Secret 名称
DROPLET_HOST 服务器 IP 地址
DROPLET_USER SSH 用户名,比如 root
DROPLET_SSH_KEY 本地私钥的完整内容

获取本地私钥内容的方法:

Mac 或 Linux

cat ~/.ssh/your-app-github

Windows PowerShell

cat $env:USERPROFILE\.ssh\your-app-github

要复制全部内容,包括这几行:

-----BEGIN OPENSSH PRIVATE KEY-----
...
-----END OPENSSH PRIVATE KEY-----

把完整私钥粘贴到 DROPLET_SSH_KEY 这个 Secret 里。

第七步:推送并测试部署

部署脚本和工作流文件都配置好后,把改动提交推送到 main 分支:

git add .github/workflows/deploy.yml package.json
git commit -m "Add auto-deploy pipeline"
git push origin main

然后去 GitHub 仓库点开 Actions 标签页。

如果一切配置正确,应该能看到部署工作流正在运行。绿色勾勾表示部署成功。

部署流程是怎么跑的

完整流程是这样的:

你推送代码到 main 分支 ↓
GitHub Actions 启动部署工作流 ↓
GitHub Actions 通过 SSH 连接到服务器 ↓
工作流进入 Laravel 项目目录 ↓
服务器执行 npm run deploy ↓
Laravel 从 GitHub 拉取最新代码 ↓
Composer 安装生产环境依赖 ↓
Node 构建前端资源 ↓
Laravel 执行迁移和优化命令 ↓
队列处理器优雅重启 ↓
部署完成

这样一来,每次想部署更新就不用手动 SSH 连服务器了。

常见问题排查

git@github.com: Permission denied (publickey)

这通常说明服务器没有权限从 GitHub 仓库拉代码。

排查方法:

  • 确认服务器上生成了 SSH 密钥

  • 确认服务器公钥已添加到 GitHub Deploy Keys

  • 确认仓库 remote 用的是 SSH 而不是 HTTPS

检查 remote URL:

git remote -v

应该显示这样的格式:

git@github.com:username/repository.git

如果是 HTTPS 格式,改成 SSH:

git remote set-url origin git@github.com:username/repository.git

composer: Continue as root/super user [yes]?

如果用 root 部署,Composer 会弹出警告。部署脚本里已经加了这个环境变量来跳过提示:

COMPOSER_ALLOW_SUPERUSER=1

长期来看,还是建议创建一个专门的部署用户,而不是用 root

npm ci 报错

npm ci 需要有 package-lock.json 文件。如果项目里没有,先在本地生成:

npm install

然后把生成的 package-lock.json 提交到仓库。

.ssh/authorized_keys: No such file or directory

先手动创建目录和文件:

mkdir -p ~/.ssh
touch ~/.ssh/authorized_keys
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys

然后再添加公钥。

队列处理器没有加载新代码

部署后重启 Laravel 队列处理器:

php artisan queue:restart

如果用的是 Supervisor,检查 worker 状态:

sudo supervisorctl status

需要的话手动重启:

sudo supervisorctl restart all

GitHub Actions 能连接服务器但部署失败

查看 GitHub Actions 里的工作流日志。常见原因包括:

  • 工作流文件里项目路径写错了

  • 服务器上没有 Composer

  • 服务器上没有 Node.js 或 npm

  • 文件权限不对

  • 数据库迁移失败

  • 前端构建失败

  • .env 文件里环境变量缺失

也可以直接在服务器上手动跑一下部署命令:

cd /var/www/your-app
npm run deploy

如果手动跑都失败了,先把服务器上的问题解决掉,再让 GitHub Actions 重试。

安全建议

如果是简单的个人项目,用 root 部署问题不大。但如果是生产环境,建议加强安全:

  • 创建专门的部署用户,不要用 root

  • 部署用户只给它应用目录的访问权限

  • 私钥只存放在 GitHub Secrets 里

  • 不要把私钥提交到仓库

  • GitHub Deploy Keys 用只读权限

  • 确保 .env 文件不会被提交

  • 执行生产环境迁移前先备份数据库

搞定!

现在你有一套基于 GitHub Actions 和 DigitalOcean 云服务器的 Laravel 自动部署流水线了。

每次往 main 分支推送代码,GitHub Actions 就会自动连接服务器、拉取最新代码、安装依赖、构建前端资源、执行迁移、优化 Laravel、重启队列处理器。

这套方案对于不用 Kubernetes 或复杂部署平台的项目来说,是个务实的起点。随着应用规模增长,可以再加入部署通知、数据库备份、测试跑 CI、零停机部署、回滚机制这些功能。

原文链接:https://dev.to/jenuelganawed/how-to-autodeploy-a-laravel-app-to-digitalocean-using-github-actions-5dcj