CI/CD with Docker and GitHub Actions: From Push to Production for Laravel Developers
Modern web development demands speed, consistency, and automation — and that's where CI/CD (Continuous Integration and Continuous Deployment) comes in. If you're tired of manual deployments, broken production setups, or environment mismatches, it's time to embrace a workflow that truly works.
This guide will walk you through building a complete CI/CD pipeline using Docker and GitHub Actions, specifically tailored for Laravel developers. From pushing code to GitHub to seeing your app live in production—fully automated—you'll learn exactly how it works, step by step.
Organize Your Project: The Folder Structure
A well-organized project structure is crucial. It separates your Laravel code from infrastructure and CI/CD configurations, making your application easier to scale and manage across different environments.
your-project/
├── app/
├── docker/
│ ├── nginx/
│ └── php/
├── docker-compose.yml
└── .github/
└── workflows/
└── deploy.yml
Why Docker with Laravel?
Docker ensures your application runs consistently across all environments: local development, staging, and production. You'll no longer have to worry about version mismatches, missing PHP extensions, or server misconfigurations.
Here's an example docker-compose.yml
that defines Laravel's essential services:
version: '3.8'
services:
app:
build: ./docker/php
volumes:
- ./app:/var/www/html
depends_on:
- db
web:
image: nginx:latest
volumes:
- ./app:/var/www/html
- ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
ports:
- "80:80"
depends_on:
- app
db:
image: mariadb:10.6
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: laravel
In this setup, each service (PHP, NGINX, and MariaDB) runs in its own isolated container. Your Laravel application (app/
) is mounted into both the app
(PHP-FPM) and web
(NGINX) services, allowing seamless interaction.
Setting Up GitHub Actions for CI/CD
GitHub Actions allows you to automate your entire deployment pipeline every time you push code to your repository. This means fewer manual steps and more reliable deployments.
Here's a basic .github/workflows/deploy.yml
file to get you started:
name: Deploy Laravel App
on:
push:
branches:
- main # This workflow triggers on pushes to the 'main' branch
jobs:
deploy:
runs-on: ubuntu-latest # The job will run on a fresh Ubuntu virtual machine
steps:
- name: Checkout code
uses: actions/checkout@v3 # Fetches your repository's code
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2 # Essential for building multi-platform Docker images
- name: Build and bring up Docker containers locally
run: |
docker build -t laravel-app ./docker/php # Builds your PHP application image
docker-compose -f docker-compose.yml up -d --build # Starts your services defined in docker-compose.yml
- name: Deploy to Remote Server
uses: appleboy/ssh-action@v1 # A popular action for connecting to remote servers via SSH
with:
host: ${{ secrets.SERVER_IP }} # Your server's IP address
username: ${{ secrets.SSH_USER }} # SSH username on your server
key: ${{ secrets.SSH_KEY }} # Your private SSH key for authentication
script: |
cd /var/www/your-project # Navigate to your project directory on the server
git pull origin main # Pull the latest code from GitHub
docker-compose down # Stop and remove existing Docker containers
docker-compose up -d --build # Rebuild and start new Docker containers
This pipeline efficiently handles the following:
- Triggers on push to the
main
branch, initiating the deployment process automatically. - Builds Docker images locally within the GitHub Actions runner.
- Connects to your remote server via SSH using securely stored credentials.
- Pulls the latest code to your server and restarts Docker containers, ensuring your live application is always up-to-date.
Securing Secrets in GitHub
Never hardcode sensitive information directly into your workflow files. Instead, leverage GitHub's built-in secrets management system.
Navigate to your repository settings:
Settings > Secrets and variables > Actions
Add the following repository secrets:
SERVER_IP
: The IP address of your production server.SSH_USER
: The SSH username for connecting to your server.SSH_KEY
: Your private SSH key (ensure it's properly formatted with-----BEGIN OPENSSH PRIVATE KEY-----
and-----END OPENSSH PRIVATE KEY-----
or-----BEGIN RSA PRIVATE KEY-----
and-----END RSA PRIVATE KEY-----
headers and footers).
These values will be securely injected into your workflow at runtime, providing a robust and safe deployment mechanism.
Benefits of This Setup
Adopting this CI/CD pipeline offers significant advantages for Laravel developers:
- Automated Deployments: Save considerable time and drastically reduce the risk of human error by eliminating manual deployment steps.
- Consistency Across Environments: Docker guarantees your application behaves identically across local development, staging, and production.
- Visibility and Control: GitHub Actions provides a clear, step-by-step overview of each deployment, making it easy to monitor progress and troubleshoot issues.
- Easier Rollbacks: If something goes wrong, rolling back to a previous stable version is much faster and simpler.
Final Thoughts
Setting up CI/CD with Docker and GitHub Actions might require a small upfront investment of time, but the payoff is immense. Once in place, every push to your GitHub repository can instantly trigger testing, building, and deployment to production. Your deployments become repeatable, reliable, and stress-free.
This guide lays the groundwork for a highly scalable and robust Laravel deployment pipeline. You can further extend it with advanced features like:
- Automated testing: Integrate unit, feature, and end-to-end tests into your pipeline.
- Staging environments: Deploy to a staging server for final testing before production.
- Notifications: Set up Slack or email notifications for deployment status updates.
- Advanced rollback strategies: Implement more sophisticated rollback mechanisms.
If you're serious about modern Laravel development, embracing CI/CD is undoubtedly one of the smartest moves you can make to streamline your workflow and deliver applications faster and more reliably.