Automated Laravel Deployment with a Self-Hosted GitHub Actions Runner
Posted on April 13, 2025 (Updated: April 13, 2025)
Automated Laravel Deployment with a Self-Hosted GitHub Actions Runner
In this setup, I configured a GitHub Actions runner to live inside my Laravel container. This allows code pushed to the main
branch to automatically update the application without needing exposed SSH ports or any manual steps.
Environment
- Laravel app running in an LXC container
- Hosted on a Proxmox server
- Code stored in a GitHub repository
- Deployment triggered by GitHub Actions via a self-hosted runner
1. Create a GitHub Runner User
A dedicated user for the runner avoids using root:
adduser github-runner
2. Install GitHub Actions Runner
From GitHub:
- Go to the repository
- Settings → Actions → Runners → New self-hosted runner
Follow the instructions, selecting Linux and x64.
Example steps:
cd /home/github-runner
mkdir actions-runner && cd actions-runner
curl -o actions-runner.tar.gz -L https://github.com/actions/runner/releases/download/v2.323.0/actions-runner-linux-x64-2.323.0.tar.gz
tar xzf actions-runner.tar.gz
./config.sh --url https://github.com/your-user/your-repo --token YOUR_TOKEN
3. Fix Permissions
The Laravel project directory was originally owned by root. To avoid Git errors:
chown -R github-runner:github-runner /var/www/laravel
Also added this to the workflow:
- name: Trust repo directory
run: git config --global --add safe.directory /var/www/laravel
4. GitHub Actions Workflow
.github/workflows/MainBranchDeploy.yml:
name: Deploy Laravel App
on:
push:
branches:
- main
jobs:
deploy:
runs-on: self-hosted
steps:
- name: Pull latest code
run: |
cd /var/www/laravel
git pull origin main
- name: Install PHP dependencies
run: |
cd /var/www/laravel
composer install --no-interaction --prefer-dist --optimize-autoloader
- name: Run database migrations
run: |
cd /var/www/laravel
php artisan migrate --force
- name: Optimize Laravel config
run: |
cd /var/www/laravel
php artisan config:cache
php artisan route:cache
php artisan view:cache
5. Run the Runner as a Service
To keep the runner running and start it on boot:
Create /etc/systemd/system/github-runner.service
:
[Unit]
Description=GitHub Actions Runner
After=network.target
[Service]
User=github-runner
WorkingDirectory=/home/github-runner/actions-runner
ExecStart=/home/github-runner/actions-runner/run.sh
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
Enable and start it:
systemctl daemon-reexec
systemctl daemon-reload
systemctl enable github-runner
systemctl start github-runner
Result
Now, when I push code to the main
branch on GitHub, the runner inside the container automatically pulls the latest code, runs Composer, handles migrations, and rebuilds Laravel’s cache.
This setup avoids opening ports or using remote SSH connections, and keeps deployment contained within the homelab.
May revisit this later to isolate the runner into its own container or set up a staging environment.