部署远程VPS时无法访问/var/www/todo-app目录的问题
我使用GitHub Actions将应用部署至远程VPS,在尝试访问服务器上的/var/www/todo-app目录前,所有流程均正常。该部署流水线会在名为“Docker Image CI”的工作流执行成功后触发,但执行cd /var/www/todo-app命令时失败,报错如下:
*** System restart required ***
cd: cannot access '/var/www/todo-app': No such file or directory
我以root用户身份SSH登录服务器,分别在远程服务器和GitHub Action中执行ls -l命令,输出如下:
远程服务器:
drwxr-xr-x 2 root root 4096 Jan 14 09:38 html drwxr-xr-x 5 root root 4096 Jan 15 16:27 todo-app
GitHub Action:
drwxr-xr-x 2 *** *** 4096 Jan 5 21:36 html
我可以正常访问/var/www/html,但/var/www/todo-app目录始终无法访问,尽管服务器上确实存在该Git仓库。我怀疑是路径或权限问题,尝试修改远程服务器上todo-app文件夹的权限但无效果。以下是我的ci.yml文件内容:
name: Deploy to VPS on: workflow_run: workflows: [ "Docker Image CI" ] types: - completed jobs: deploy: runs-on: ubuntu-latest if: ${{ github.event.workflow_run.conclusion == 'success' }} steps: - name: Checkout code uses: actions/checkout@v4 - name: Get SSH key and set permissions run: | mkdir -p ~/.ssh echo "${{ secrets.REMOTE_PRIVATE_KEY }}" > ~/.ssh/id_rsa && chmod 600 ~/.ssh/id_rsa ssh-keyscan -H ${{ secrets.REMOTE_HOST }} >> ~/.ssh/known_hosts - name: SSH to the server and Redeploy run: | ssh -i ~/.ssh/id_rsa ${{ secrets.REMOTE_USERNAME }}@${{ secrets.REMOTE_HOST }} cd /var/www/todo-app git pull origin main echo "DATABASE_URL=${{ secrets.PG_URL }}" > .env echo "POSTGRES_USER=${{ secrets.PG_USER }}" >> .env echo "POSTGRES_PASSWORD=${{ secrets.PG_PASSWORD }}" >> .env echo "POSTGRES_DB=${{ secrets.PG_DB }}" >> .env docker compose build docker compose up -d exit
问题核心在于SSH命令的执行逻辑:你当前的写法是先SSH登录到远程服务器,但后续的cd、git pull等命令并没有在远程服务器上执行,而是回到了GitHub Actions的runner(ubuntu-latest)环境中运行——这就是为什么你在GitHub Action的ls输出里看不到todo-app目录,因为这些命令根本没在VPS上跑。
修复方法是把所有需要在远程执行的命令通过SSH一次性传递到服务器上,推荐使用here-doc语法(可读性更好):
修改SSH to the server and Redeploy步骤的脚本为:
ssh -i ~/.ssh/id_rsa ${{ secrets.REMOTE_USERNAME }}@${{ secrets.REMOTE_HOST }} << 'EOF' cd /var/www/todo-app git pull origin main echo "DATABASE_URL=${{ secrets.PG_URL }}" > .env echo "POSTGRES_USER=${{ secrets.PG_USER }}" >> .env echo "POSTGRES_PASSWORD=${{ secrets.PG_PASSWORD }}" >> .env echo "POSTGRES_DB=${{ secrets.PG_DB }}" >> .env docker compose build docker compose up -d EOF
也可以用分号将所有命令连接,作为SSH的参数执行:
ssh -i ~/.ssh/id_rsa ${{ secrets.REMOTE_USERNAME }}@${{ secrets.REMOTE_HOST }} "cd /var/www/todo-app && git pull origin main && echo 'DATABASE_URL=${{ secrets.PG_URL }}' > .env && echo 'POSTGRES_USER=${{ secrets.PG_USER }}' >> .env && echo 'POSTGRES_PASSWORD=${{ secrets.PG_PASSWORD }}' >> .env && echo 'POSTGRES_DB=${{ secrets.PG_DB }}' >> .env && docker compose build && docker compose up -d"
额外注意事项:
- 确认
${{ secrets.REMOTE_USERNAME }}对应的用户拥有/var/www/todo-app目录的访问权限(虽然你用root测试过,但如果这里配置的是其他用户,需检查权限) - 可以在远程命令开头添加
pwd或ls /var/www,验证命令是否确实在远程服务器上执行,以及当前路径是否正确
内容的提问来源于stack exchange,提问作者twentyfourk

