Hey there, developers! 👋 I'm Ojugo Samson, a Lead Software Engineer, I build scalable solutions with PHP and Laravel.
Deploying code manually—logging into a server, pulling changes, running migrations—can be a hassle, especially for frequent updates. In this guide, I’ll show you how to automate deployments for your Laravel app on a Virtual Private Server (VPS) using GitHub Actions. This approach uses a secure SSH connection to trigger a deployment script on your server whenever you push to the main
branch.
This tutorial is beginner-friendly, but I’ll assume you know the basics of Laravel, Git, and SSH. If you’re new to VPS, I recommend providers like DigitalOcean, Linode, or AWS Lightsail. Let’s get started!
Why Use GitHub Actions for Deployment?
- Automation: Push to GitHub, and your server updates automatically.
- Security: Store sensitive data like SSH keys in GitHub Secrets.
- Flexibility: Customize workflows for testing, staging, or production.
- Visibility: Track deployment status in GitHub’s Actions tab.
We’ll deploy a sample Laravel app (like my VerifyPlug project), but this works for any Laravel-based repo.
Prerequisites
Before we begin:
- A GitHub repository with your Laravel project (e.g., on the
main
branch). - A VPS with Ubuntu (or similar Linux distro), PHP 8.3+, Composer, Git, and Laravel’s requirements installed.
- Your Laravel app cloned and running on the VPS (e.g., in
/var/www/your-app
). - Nginx or Apache configured for your site.
- Supervisor or similar for queue workers (if using queues).
If your VPS isn’t set up, check Laravel’s deployment docs for setup basics.
Step 1: Set Up SSH Keys for Secure Access
To let GitHub Actions connect to your VPS securely, generate an SSH key pair on your VPS and add the public key to GitHub Secrets.
- SSH into your VPS:
ssh youruser@your-vps-ip
- Generate an SSH key pair (accept defaults or add a passphrase for extra security):
ssh-keygen -t ed25519 -C "your_email@example.com"
This creates ~/.ssh/id_ed25519
(private key) and ~/.ssh/id_ed25519.pub
(public key).
- Add the public key to
~/.ssh/authorized_keys
:
cat ~/.ssh/id_ed25519.pub >> ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys
- Copy the private key for GitHub Secrets:
cat ~/.ssh/id_ed25519
Save this securely—you’ll need it in Step 4.
- Test SSH locally to ensure it works:
ssh -i ~/.ssh/id_ed25519 youruser@your-vps-ip
Step 2: Clone Your Repository on the VPS (If Not Already Done)
Navigate to your web directory and clone your repo:
sudo mkdir -p /var/www/your-app sudo chown -R $USER:www-data /var/www/your-app cd /var/www/your-app git clone git@github.com:yourusername/your-repo.git .
Replace your-app
, yourusername
, and your-repo
with your details.
Install dependencies and configure:
composer install --optimize-autoloader --no-dev cp .env.example .env php artisan key:generate php artisan migrate
Ensure your .env
is set up with database credentials and other configs.
Step 3: Create the Deployment Script
We’ll create a deploy.sh
script on the VPS to handle pulling code, updating dependencies, and restarting services.
- In
/var/www/your-app
, create the script:
nano deploy.sh
- Add the following:
#!/bin/bash set -e echo "Deployment started..." # Navigate to project directory cd /var/www/your-app # Enter maintenance mode (ignore if already down) (php artisan down --message "The app is being updated. Please try again in a minute.") || true # Pull the latest code from the main branch git fetch origin main git reset --hard origin/main # Install Composer dependencies composer install --no-dev --no-interaction --prefer-dist --optimize-autoloader # Clear and recreate caches php artisan cache:clear php artisan config:cache php artisan route:cache php artisan view:cache # Run database migrations php artisan migrate --force # Restart queue workers (if using database queue) php artisan queue:restart # Exit maintenance mode php artisan up # Reload PHP-FPM to update opcache (adjust version if needed) echo "" | sudo -S service php8.3-fpm reload echo "Deployment finished!"
- Make it executable:
chmod +x deploy.sh
- Test it manually:
./deploy.sh
Fix any issues (e.g., permissions for www-data
or PHP-FPM version).
This script handles maintenance mode, code updates, dependency installation, cache management, migrations, and service restarts.
Step 4: Set Up GitHub Actions Workflow
We’ll create a .github/workflows/deploy.yml
file in your repository to automate the deployment.
- In your local repo, create the directory and file:
mkdir -p .github/workflows touch .github/workflows/deploy.yml
- Add the following content:
name: Deploy to Production on: push: branches: - main jobs: deploy: runs-on: ubuntu-latest steps: - name: Checkout Repository uses: actions/checkout@v3 - name: Setup SSH uses: webfactory/ssh-agent@v0.5.4 with: ssh-private-key: ${{ secrets.DEPLOY_SERVER_KEY }} - name: Deploy to VPS uses: appleboy/ssh-action@master with: host: ${{ secrets.DEPLOY_SERVER_IP }} username: ${{ secrets.DEPLOY_SERVER_USER }} key: ${{ secrets.DEPLOY_SERVER_KEY }} script: | cd ${{ secrets.DEPLOY_PATH }} ./deploy.sh
- Commit and push:
git add .github/workflows/deploy.yml git commit -m "Add GitHub Actions deployment workflow" git push origin main
This workflow triggers on pushes to main
, checks out the code, sets up SSH, and runs deploy.sh
on your VPS.
Step 5: Configure GitHub Secrets
To securely store sensitive data, add the following to your repo’s Settings > Secrets and variables > Actions > Secrets:
Go to your GitHub repo > Settings > Secrets and variables > Actions > New repository secret.
-
Add these secrets:
-
DEPLOY_SERVER_KEY
: The private SSH key from Step 1 (id_ed25519
content). -
DEPLOY_SERVER_IP
: Your VPS IP address (e.g.,192.168.1.1
). -
DEPLOY_SERVER_USER
: Your VPS username (e.g.,youruser
). -
DEPLOY_PATH
: The full path to your app (e.g.,/var/www/your-app
).
-
Step 6: Test the Deployment
- Make a small change locally (e.g., update a view).
- Commit and push to
main
:
git commit -m "Test deployment" git push origin main
Go to your repo > Actions tab to monitor the workflow.
Check
/var/www/your-app
on the VPS to confirm updates. Debug using the Actions logs or by adding> deploy.log 2>&1
to the script step for output.
Common issues:
- SSH errors: Verify the private key and
authorized_keys
setup. - Permissions: Ensure
www-data
has access to/var/www/your-app
. - PHP-FPM version: Adjust the
php8.3-fpm
service name if using a different version.
Best Practices
- Test First: Use a
staging
branch to test deployments. - Backups: Snapshot your VPS and database before migrations.
- Monitoring: Use tools like Sentry for error tracking.
- Zero-Downtime: For production, explore tools like Laravel Forge or Envoyer.
- Security: Restrict SSH access to your GitHub Actions runner IP range.
This setup powers my projects like VerifyPlug, saving hours of manual work!
Wrapping Up
You’ve now automated your Laravel app’s deployment with GitHub Actions! Push to main
, and your VPS updates seamlessly. If you hit issues, check the Actions logs or reach out on LinkedIn.
Happy coding! 🚀
Ojugo Samson
Lead Software Engineer @ Cargoplug | Techstars '24
LinkedIn: samsonojugo
GitHub: quitenoisemaker
Top comments (0)