thetamari / laravel-hostinger
A Laravel package to deploy private GitHub repositories to Hostinger shared hosting via SSH, with automated webhook-based auto-deployment on push.
Requires
- php: ^8.1
- illuminate/console: ^10.0|^11.0|^12.0
- illuminate/routing: ^10.0|^11.0|^12.0
- illuminate/support: ^10.0|^11.0|^12.0
- phpseclib/phpseclib: ~3.0
Requires (Dev)
- orchestra/testbench: ^8.0|^9.0
- phpunit/phpunit: ^10.0|^11.0
README
A Laravel Composer package for deploying private GitHub repositories to Hostinger shared hosting via SSH, with full auto-deploy on push via GitHub webhooks.
Hostinger shared hosting does not support server-side git hooks, does not let you change the web root away from public_html, and its built-in GitHub auto-deploy only copies into public_html — making it unsuitable for Laravel. This package solves all of that.
Table of Contents
How it works
~/domains/yourdomain.com/ ← Laravel lives here (cloned from GitHub)
~/domains/yourdomain.com/public_html → symlink → ~/domains/yourdomain.com/public
When you push to GitHub, a webhook fires your Hostinger-hosted receiver, which triggers php artisan hostinger:deploy --pull-only in the background — pulling code, running composer, npm run build, migrating, and caching automatically.
Requirements
- PHP 8.1+
- Laravel 10, 11, or 12
- SSH access enabled on your Hostinger plan (Business or above)
- An SSH key pair added to Hostinger hPanel → SSH Keys
- Composer installed on Hostinger (available via hPanel)
- Node.js available via
/opt/alt/alt-nodejs24(or adjust the path in config)
Installation
- Install the package, then run the prepare command to patch your project files:
composer require thetamari/laravel-hostinger php artisan hostinger:prepare
Optionally publish the config file if you want to customize it directly:
php artisan vendor:publish --tag=hostinger-deploy-config
- Fill in your
.envwith allHOSTINGER_*values from the Configuration section below. - Important: Commit and push your project to GitHub before the next step.
- Run the deploy command locally on your computer — this SSHs into Hostinger, clones your repo, installs dependencies, and sets everything up:
php artisan hostinger:deploy
- Once the first deploy is done, set up auto-deploy on push:
php artisan hostinger:setup-webhook
From this point on, every push to your branch triggers an automatic re-deploy via the GitHub webhook.
Configuration
Add the following variables to your local .env:
# SSH HOSTINGER_SSH_HOST= HOSTINGER_SSH_PORT=65002 HOSTINGER_SSH_USER= HOSTINGER_SSH_KEY_PATH=~/.ssh/id_rsa HOSTINGER_SSH_KEY_PASSPHRASE= # optional, leave empty if key has no passphrase # Hostinger paths HOSTINGER_WEBSITE_FOLDER=yourdomain.com # folder name inside ~/domains/ HOSTINGER_PHP_BIN=/opt/alt/php85/usr/bin/php HOSTINGER_NODE_BIN=/opt/alt/alt-nodejs24/root/usr/bin/node HOSTINGER_NPM_BIN=/opt/alt/alt-nodejs24/root/usr/bin/npm # GitHub (private repo) HOSTINGER_GITHUB_PAT=github_pat_xxxx HOSTINGER_GITHUB_REPO=username/repo-name HOSTINGER_GITHUB_BRANCH=main # Webhook HOSTINGER_WEBHOOK_SECRET= # generate: openssl rand -hex 32 # Logging HOSTINGER_LOG_PATH=~/domains/yourdomain.com/storage/logs/deploy.log
GitHub PAT Permissions
Create a fine-grained PAT at github.com/settings/tokens with:
| Permission | Access |
|---|---|
| Contents | Read-only |
| Metadata | Read-only (auto-granted) |
If using a classic PAT, enable the repo scope.
Commands
Prepare your project
Run once before your first push to patch your project files:
php artisan hostinger:prepare
This adds the webhook route to your CSRF exclusions in bootstrap/app.php and adds .rnd to your .gitignore. On Laravel 10 the CSRF patch is not automatic — see the Auto-deploy setup section.
First-time deploy
Clones the repo, runs composer install, sets up .env, generates an app key, runs migrations, builds assets, and creates the public_html and storage symlinks.
php artisan hostinger:deploy
The command will pause after copying .env.example to .env so you can SSH in (or use Hostinger's file manager for your website) and fill in production values before continuing.
It will also pause if migration fails because of database connection issues and give you the opportunity to fix them then continue without starting over.
Options:
| Option | Description |
|---|---|
--skip-npm |
Skip npm install and npm run build |
--skip-migrate |
Skip database migrations |
--run-npm |
Force npm build regardless of changed files (manual override) |
--pull-only |
Pull latest code and run post-deploy steps only (no wipe/clone) |
Re-deploy (code update only)
php artisan hostinger:deploy --pull-only
Pulls the latest code, runs composer install, migrations, and rebuilds the cache. Also runs npm install and npm run build if the push includes any changes in resources/, package.json, or vite.config.js. Does not wipe the directory or touch .env.
Set up auto-deploy webhook
php artisan hostinger:setup-webhook
This prints your webhook URL, generates a secret if you don't have one, and gives you the exact GitHub settings to use.
Auto-deploy setup (after first deploy)
The webhook is a standard Laravel POST route registered by the package — no standalone PHP files, no public directory hacks.
Running hostinger:prepare automatically adds the webhook route to your CSRF exclusions in bootstrap/app.php. On Laravel 10 this is not patched automatically — add it manually to app/Http/Middleware/VerifyCsrfToken.php:
protected $except = [ 'deploy/webhook', ];
1. Run php artisan hostinger:setup-webhook — this will give you your webhook URL and secret. Use them to add a webhook in your GitHub repo → Settings → Webhooks → Add webhook:
- Payload URL:
https://yourdomain.com/deploy/webhook - Content type:
application/json - Secret: your
HOSTINGER_WEBHOOK_SECRET - Events: Just the push event
2. Push to your branch. GitHub sends a signed payload to your Laravel app, which verifies the HMAC-SHA256 signature and runs hostinger:deploy --pull-only in the background. The webhook automatically detects whether any files under resources/, package.json, or vite.config.js changed in the push — npm build only runs when needed.
Security note: The URL itself does not need to be obscure. Every request is verified against a cryptographic signature using your HOSTINGER_WEBHOOK_SECRET. Requests without a valid signature are rejected with a 403 before any deploy logic runs.
Logging
All deploy activity is logged to the remote path defined in HOSTINGER_LOG_PATH (default: ~/domains/yourdomain.com/storage/logs/deploy.log). You can tail it:
ssh -p 65002 user@yourhost "tail -f ~/domains/yourdomain.com/storage/logs/deploy.log"
Set HOSTINGER_LOG_PATH= (empty) to disable remote logging.
PHP & Node version
Hostinger uses alt-php and alt-nodejs from CloudLinux. Default paths in this package:
PHP: /opt/alt/php85/usr/bin/php
Node: /opt/alt/alt-nodejs24/root/usr/bin/node
npm: /opt/alt/alt-nodejs24/root/usr/bin/npm
If your hPanel is configured to use a different version, update HOSTINGER_PHP_BIN, HOSTINGER_NODE_BIN, and HOSTINGER_NPM_BIN accordingly.
Security
- Your GitHub PAT is used only over HTTPS and never stored on the remote server beyond the git remote URL (which is reset on each pull). Consider rotating it periodically.
- The webhook endpoint validates the
X-Hub-Signature-256header using HMAC-SHA256. Requests with an invalid or missing signature are rejected with a 403. - Never commit your
.envor expose your PAT or webhook secret.
License
MIT — see LICENSE.
Author
TheTamari · github.com/thetamari
Credits
Inspired by TheCodeHolic · github.com/thecodeholic