What is a CI/CD pipeline and how do I set one up with GitHub Actions?
CI/CD (Continuous Integration/Continuous Deployment) is a software practice that automatically builds, tests, and deploys code changes every time a developer pushes to a repository, eliminating manual deployment steps and catching bugs before they reach production.
DETAILED EXPLANATION:
CI (Continuous Integration): Every code push triggers an automated pipeline that: checks out code, installs dependencies, runs unit tests, runs integration tests, builds artifacts. If any step fails, the push is rejected and the developer is notified.
CD (Continuous Deployment): After CI passes, the artifact is automatically deployed to staging, then production — or CD (Continuous Delivery) deploys to staging automatically but requires manual approval for production.
Benefits: Smaller, safer deployments; faster bug detection; consistent deployment process; full audit trail of what deployed when.
WHEN TO USE:
- Any development team with more than one developer
- Applications with tests that can be automated
- Systems requiring deployment traceability
- SaaS products needing frequent updates
STEP-BY-STEP — GitHub Actions CI/CD for PHP/WordPress to Connect Quest VPS:
# .github/workflows/deploy.yml
name: Deploy to Production
on:
push:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: "8.1"
- name: Install dependencies
run: composer install --no-interaction --prefer-dist
- name: Run PHPUnit tests
run: ./vendor/bin/phpunit
deploy:
needs: test
runs-on: ubuntu-latest
if: github.ref == "refs/heads/main"
steps:
- uses: actions/checkout@v4
- name: Deploy to VPS via SSH
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.VPS_HOST }}
username: deploy
key: ${{ secrets.VPS_SSH_KEY }}
script: |
cd /var/www/myapp
git pull origin main
composer install --no-dev --optimize-autoloader
php artisan migrate --force
php artisan config:cache
php artisan route:cache
sudo systemctl reload nginx
REAL EXAMPLES:
# Store secrets in GitHub: Settings > Secrets > Actions
# VPS_HOST = your-server-ip
# VPS_SSH_KEY = private SSH key content
# View workflow runs in GitHub Actions tab
# Green = all tests passed + deployed
# Red = failed - click to see which step
FLOW:
[ git push main ] → GitHub Actions triggered → Run Tests → Tests pass? → SSH deploy to VPS → nginx reload → [ New version live ]
KEY POINTS:
- Store server credentials as GitHub Secrets (never in code)
- Add health check after deploy: curl https://yoursite.com/health
- Blue-green deployment: deploy to staging, verify, swap DNS
- Connect Quest VPS supports GitHub Actions deployments natively via SSH
COMMON MISTAKES:
- Deploying without running tests first
- Using root SSH user for deployments (use dedicated deploy user)
- Not having rollback plan (tag releases, keep previous build)
QUICK FIX:
Deployment failing → Check GitHub Actions logs. Most common: wrong SSH key, server disk full, composer timeout. Add --timeout flag to composer commands.
DIFFICULTY: Intermediate
RELATED: Docker, VPS Hosting, Git, Linux Server
DETAILED EXPLANATION:
CI (Continuous Integration): Every code push triggers an automated pipeline that: checks out code, installs dependencies, runs unit tests, runs integration tests, builds artifacts. If any step fails, the push is rejected and the developer is notified.
CD (Continuous Deployment): After CI passes, the artifact is automatically deployed to staging, then production — or CD (Continuous Delivery) deploys to staging automatically but requires manual approval for production.
Benefits: Smaller, safer deployments; faster bug detection; consistent deployment process; full audit trail of what deployed when.
WHEN TO USE:
- Any development team with more than one developer
- Applications with tests that can be automated
- Systems requiring deployment traceability
- SaaS products needing frequent updates
STEP-BY-STEP — GitHub Actions CI/CD for PHP/WordPress to Connect Quest VPS:
# .github/workflows/deploy.yml
name: Deploy to Production
on:
push:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: "8.1"
- name: Install dependencies
run: composer install --no-interaction --prefer-dist
- name: Run PHPUnit tests
run: ./vendor/bin/phpunit
deploy:
needs: test
runs-on: ubuntu-latest
if: github.ref == "refs/heads/main"
steps:
- uses: actions/checkout@v4
- name: Deploy to VPS via SSH
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.VPS_HOST }}
username: deploy
key: ${{ secrets.VPS_SSH_KEY }}
script: |
cd /var/www/myapp
git pull origin main
composer install --no-dev --optimize-autoloader
php artisan migrate --force
php artisan config:cache
php artisan route:cache
sudo systemctl reload nginx
REAL EXAMPLES:
# Store secrets in GitHub: Settings > Secrets > Actions
# VPS_HOST = your-server-ip
# VPS_SSH_KEY = private SSH key content
# View workflow runs in GitHub Actions tab
# Green = all tests passed + deployed
# Red = failed - click to see which step
FLOW:
[ git push main ] → GitHub Actions triggered → Run Tests → Tests pass? → SSH deploy to VPS → nginx reload → [ New version live ]
KEY POINTS:
- Store server credentials as GitHub Secrets (never in code)
- Add health check after deploy: curl https://yoursite.com/health
- Blue-green deployment: deploy to staging, verify, swap DNS
- Connect Quest VPS supports GitHub Actions deployments natively via SSH
COMMON MISTAKES:
- Deploying without running tests first
- Using root SSH user for deployments (use dedicated deploy user)
- Not having rollback plan (tag releases, keep previous build)
QUICK FIX:
Deployment failing → Check GitHub Actions logs. Most common: wrong SSH key, server disk full, composer timeout. Add --timeout flag to composer commands.
DIFFICULTY: Intermediate
RELATED: Docker, VPS Hosting, Git, Linux Server