Laravel: automated deployment using a GitHub webhook


Make a git push to GitHub deploy the new modifications to a remote server.

How it works

  • GitHub sends a POST request to a specific URL on the server
  • That URL triggers the execution of a deployment shell script.

Deployment shell script

First, create the shell script. At the root of your Laravel application, add


# activate maintenance mode
php artisan down

# update source code
git pull

# update PHP dependencies
export COMPOSER_HOME='/tmp/composer'
composer install --no-interaction --no-dev --prefer-dist
	# --no-interaction	Do not ask any interactive question
	# --no-dev		Disables installation of require-dev packages.
	# --prefer-dist		Forces installation from package dist even for dev versions.

# update database
php artisan migrate --force
	# --force		Required to run when in production.

# stop maintenance mode
php artisan up

Create a GitHub webhook

On GitHub, on your repository page, select the Settings tab, then Webhooks in the left navigation. Or go directly to the URL:<your account>/<your repository>/settings/hooks

Click Add webhook:

  • Payload URL: http://<>/deploy
  • Secret: A long random string. You'll also need it in the next section.

Add the webhook secret to Laravel

In config/app.php, add:

'deploy_secret' => env('APP_DEPLOY_SECRET'),

In your .env file, add your webhook secret:


Controller method

Create a controller method to launch the deployment shell script.

use Illuminate\Http\Request;
use Symfony\Component\Process\Process;
class UtilController extends Controller
    public function deploy(Request $request)
        $githubPayload = $request->getContent();
        $githubHash = $request->header('X-Hub-Signature');
        $localToken = config('app.deploy_secret');
        $localHash = 'sha1=' . hash_hmac('sha1', $githubPayload, $localToken, false);
        if (hash_equals($githubHash, $localHash)) {
            $root_path = base_path();
            $process = new Process('cd ' . $root_path . '; ./');
            $process->run(function ($type, $buffer) {
                echo $buffer;


  • the HTTP header X-Hub-Signature is verified to make sure the request comes from GitHub. It's a hash of the request body (payload) using the webhook secret.
  • the Process class, included with Laravel is used to easily launch the shell script.

Add a route for the controller method

Let's add the route used by the GitHub webhook and link it to the controller method.

In routes/api.php, add:

Route::post('deploy', 'UtilController@deploy');

In app/providers/RouteServiceProvider.php, to remove the need for /api as URL prefix, change the function mapApiRoutes() to:

protected function mapApiRoutes()


  • we use api.php instead of web.php to avoid the CSRF token verification.
  • removing the need for the /api prefix is just a personal choice :)

Change the Unix group of your web folder to www-data

This was necessary on my production server for the shell script to run properly. You might not need it.

sudo chgrp -R www-data .


That's it! The different code snippets are also available there: