GitLab CI + aaPanel: how I deploy Laravel without drama on a single VPS

Short answer: I deploy aviwebsquad.in with GitLab CI into timestamped release folders on aaPanel, symlink current, and keep .env + storage in a shared tree—no Kubernetes, no blue-green cluster, just disciplined bash.

If you read my CI/CD pipeline overview, this is the specific implementation on a ₹-friendly VPS—not theory.

Why not “just git pull” on the server?

I tried that on early projects. It fails quietly when:

Aviwebsquad uses scripts/deploy_production.sh with:

/releases/{sha}-{pipeline}/
/shared/.env
/shared/storage
/current -> latest release

Each pipeline run is immutable. Rollback = repoint symlink.

GitLab shell runner on aaPanel

aaPanel ships PHP at /www/server/php/84/bin/php—not on PATH for the gitlab-runner user. CI failed with php: command not found until I added scripts/ci-env.sh:

export PATH="/www/server/php/84/bin:$PATH"

That one line is now sourced in .gitlab-ci.yml test/build/deploy jobs. See also Pest tests before deploying CMS changes—tests run in the same PATH context.

Deploy steps that actually matter

  1. Build assets on CI (npm ci && npm run build) so the server never compiles Vite under traffic.
  2. Rsync release excluding node_modules, including public/build.
  3. php artisan migrate --force only after symlink swap (or with maintenance mode— I prefer a 2-second window).
  4. php artisan optimize + Horizon restart if queues changed.

What I deliberately skip

Relationship to preview environments

Preview environments with GitHub Actions is the pattern for PRs. Production stays GitLab → aaPanel because that is where the domain already lives.

FAQ

Is this zero-downtime?

Near-zero. Requests during symlink swap might hit old or new release—both must boot. I run smoke Pest tests post-deploy.

aaPanel vs Laravel Forge?

Forge is smoother; aaPanel is what this VPS already had. The release-folder pattern works on both.

Where do MCP content writes fit?

Content agents hit Sanctum APIs—deploy does not touch posts. See securing the MCP content API.

Maintenance note (Sep 2026)

Re-checked this runbook against the current aviwebsquad.in production host after the VPS move to Hostinger (72.61.235.205). Steps above still match the live deploy path under /www/wwwroot/aviwebsquad.in.