DEV Community

Cover image for Automate Your Laravel Deployment on a VPS Using GitHub Actions: A Beginner's Guide
Samson Ojugo
Samson Ojugo

Posted on

Automate Your Laravel Deployment on a VPS Using GitHub Actions: A Beginner's Guide

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.

  1. SSH into your VPS:
 ssh youruser@your-vps-ip 
Enter fullscreen mode Exit fullscreen mode
  1. Generate an SSH key pair (accept defaults or add a passphrase for extra security):
 ssh-keygen -t ed25519 -C "your_email@example.com" 
Enter fullscreen mode Exit fullscreen mode

This creates ~/.ssh/id_ed25519 (private key) and ~/.ssh/id_ed25519.pub (public key).

  1. Add the public key to ~/.ssh/authorized_keys:
 cat ~/.ssh/id_ed25519.pub >> ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys 
Enter fullscreen mode Exit fullscreen mode
  1. Copy the private key for GitHub Secrets:
 cat ~/.ssh/id_ed25519 
Enter fullscreen mode Exit fullscreen mode

Save this securely—you’ll need it in Step 4.

  1. Test SSH locally to ensure it works:
 ssh -i ~/.ssh/id_ed25519 youruser@your-vps-ip 
Enter fullscreen mode Exit fullscreen mode

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 . 
Enter fullscreen mode Exit fullscreen mode

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 
Enter fullscreen mode Exit fullscreen mode

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.

  1. In /var/www/your-app, create the script:
 nano deploy.sh 
Enter fullscreen mode Exit fullscreen mode
  1. 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!" 
Enter fullscreen mode Exit fullscreen mode
  1. Make it executable:
 chmod +x deploy.sh 
Enter fullscreen mode Exit fullscreen mode
  1. Test it manually:
 ./deploy.sh 
Enter fullscreen mode Exit fullscreen mode

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.

  1. In your local repo, create the directory and file:
 mkdir -p .github/workflows touch .github/workflows/deploy.yml 
Enter fullscreen mode Exit fullscreen mode
  1. 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 
Enter fullscreen mode Exit fullscreen mode
  1. Commit and push:
 git add .github/workflows/deploy.yml git commit -m "Add GitHub Actions deployment workflow" git push origin main 
Enter fullscreen mode Exit fullscreen mode

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:

  1. Go to your GitHub repo > Settings > Secrets and variables > Actions > New repository secret.

  2. 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

  1. Make a small change locally (e.g., update a view).
  2. Commit and push to main:
 git commit -m "Test deployment" git push origin main 
Enter fullscreen mode Exit fullscreen mode
  1. Go to your repo > Actions tab to monitor the workflow.

  2. 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)