Every developer knows the feeling: you push code, something breaks in production, and the whole team is firefighting at 11pm. A CI/CD pipeline solves this — but most tutorials assume you have a 50-person DevOps team. This guide is for the rest of us.
What is CI/CD and Why Does It Matter?
CI/CD stands for Continuous Integration and Continuous Deployment. In plain English:
- CI (Continuous Integration): Every time a developer pushes code, automated tests run immediately to catch errors before they reach production.
- CD (Continuous Deployment): Once tests pass, the code is automatically deployed to your server — no manual FTP uploads, no “who deployed what” confusion.
For a small team, this means fewer bugs reaching clients, faster releases, and no more deployment anxiety.
What You Need Before Starting
- A GitHub repository (free tier works perfectly)
- A server with SSH access (any cPanel/VPS hosting works)
- Basic comfort with YAML files
- About 45 minutes
Step 1: Create Your GitHub Actions Workflow File
In your repository, create this file at .github/workflows/deploy.yml:
name: Deploy to Production
on:
push:
branches: [ main ]
jobs:
test-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Set up PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
- name: Install dependencies
run: composer install --no-dev --optimize-autoloader
- name: Run tests
run: vendor/bin/phpunit
- name: Deploy via SSH
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
cd /public_html
git pull origin main
composer install --no-dev
php artisan migrate --force
Step 2: Add Your Server Secrets to GitHub
Go to your repository → Settings → Secrets and Variables → Actions → click “New repository secret” and add three secrets:
SERVER_HOST— your server IP or domain (e.g.server.softcrony.com)SERVER_USER— your SSH username (usuallyrootor your cPanel username)SSH_PRIVATE_KEY— your private SSH key (runcat ~/.ssh/id_rsato get it)
Never commit passwords or keys directly in your YAML file. GitHub Secrets encrypts them safely.
Step 3: Set Up SSH Access on Your Server
On your server, add your GitHub Actions public key to authorized_keys:
# On your server via SSH:
echo "your-public-key-here" >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
To generate a dedicated keypair for deployments (recommended):
ssh-keygen -t ed25519 -C "github-actions-deploy" -f ~/.ssh/deploy_key
# Add deploy_key.pub to server authorized_keys
# Add deploy_key (private) to GitHub Secrets as SSH_PRIVATE_KEY
Step 4: Add a Basic Test
A CI/CD pipeline without tests is just an automated FTP upload. Even a simple smoke test adds enormous value:
<?php
// tests/SmokeTest.php
class SmokeTest extends PHPUnit\Framework\TestCase
{
public function test_homepage_responds()
{
$response = file_get_contents('http://localhost/');
$this->assertStringContainsString('Softcrony', $response);
}
public function test_contact_page_loads()
{
$response = file_get_contents('http://localhost/contact/');
$this->assertStringContainsString('Get in touch', $response);
}
}
Step 5: Test Your Pipeline
Push any small change to your main branch and watch the magic:
- Go to your GitHub repository → Actions tab
- You’ll see your workflow running in real-time
- Green check = deployed successfully
- Red X = something failed (click to see the exact error)
Common Issues and Fixes
Permission denied on SSH: Double-check that the public key is in ~/.ssh/authorized_keys on the server and that the file has chmod 600 permissions. Composer not found: Add which composer to your script step to verify the path. On some servers you may need the full path /usr/local/bin/composer. Tests failing but code is fine: Check that your test environment matches production — PHP version, extensions, environment variables.
What to Add Next
Once your basic pipeline is running, consider adding:
- Staging deployment: Deploy to a staging server first, then manually approve production deploys
- Slack notifications: Get a message in your team channel on every deploy (success or failure)
- Database backups: Automatically backup your database before each deployment
- Code quality checks: Add PHPStan or ESLint to catch issues before tests even run
The Business Case for CI/CD
For Softcrony’s clients, we consistently see the same pattern after implementing CI/CD: deployment frequency goes from once a week to multiple times a day, deployment failures drop by over 80%, and developers spend less time on manual deployment tasks and more time building features. The initial setup takes less than a day. The time saved starts immediately. — Need help setting up CI/CD for your project? We’ve implemented automated deployment pipelines for businesses across Jabalpur and India. Get a free consultation →
Leave a comment