CI/CD and Deployment: How We Ship Without Drama
The best deploy is the one nobody notices. No downtime window, no "it works on my machine", no 2 AM rollback. That's the standard we hold every SrcTeam project to, and it doesn't require a fancy platform — just a pipeline that's boring on purpose.
The pipeline in one paragraph
Push to master → GitHub Actions runs the build → artifacts are synced to the VPS over SSH → post-deploy steps run (migrations, cache rebuild) → the app process restarts. Total time: about two minutes, fully unattended.
What we automate
- Tests and linting on every pull request — broken code never reaches master.
- The build — frontend assets compiled, dependencies installed, on a clean runner.
- The sync —
rsyncwith--delete, so removed files don't linger on the server. - Post-deploy steps —
optimize:clear,migrate --force, and cache rebuilds, run in order. - The restart — the SSR process is bounced so the new build is live immediately.
A minimal workflow looks like this:
name: deploy
on:
push:
branches: [master]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci && npm run build
- run: |
rsync -az --delete --exclude '.env' \
./dist/ deploy@server:/var/www/app/
- run: ssh deploy@server 'php artisan migrate --force && php artisan optimize'
What stays manual
Automation is a tool, not a religion. Three things are deliberately human:
- Secrets —
.envnever enters the repository. It lives on the server, excluded from every sync. - Risky migrations — a migration that rewrites a large table gets a review and a maintenance window, not an automatic run.
- The rollback plan —
git revert+ push is the fastest way back, and it's rehearsed, not improvised.
Why a VPS instead of a managed PaaS
Managed platforms are convenient until they aren't — vendor lock-in, surprise pricing, and a ceiling on what you can tune. A plain VPS with SSH, rsync, and a process manager covers 90% of real-world apps with full control and predictable cost. Docker is an option when isolation matters, but for many projects it's unnecessary complexity: a systemd unit and a synced directory are enough.
Rules we keep
- Deploy from
masteronly — no ad-hoc server edits. - Small, descriptive commits; the changelog is the git log.
- A health check after every deploy — the pipeline isn't done until the site answers.
- If a deploy breaks, revert first, debug second.
A good pipeline doesn't make shipping exciting. It makes shipping safe — and that's exactly the point. When deploying is boring, your team spends its energy on the product, not on firefighting.