Just some quick notes on this - as everytime I setup a new server I forget some steps!
- Stick the Hugo executable somewhere on the server.
- Use the following PHP deploy script from here, published below in case it ever goes offline.
/**
* Automated deploy from GitHub
*
* https://developer.github.com/webhooks/
* Template from ServerPilot (https://serverpilot.io/community/articles/how-to-automatically-deploy-a-git-repo-from-bitbucket.html)
* Hash validation from Craig Blanchette (http://isometriks.com/verify-github-webhooks-with-php)
*/
// Variables
$secret = getenv('GH_DEPLOY_SECRET'); # Paul note: Best to set environment variable - avoid setting here.
$repo_dir = '/home/example/git/examplerepo';
$web_root_dir = '/home/example/public_html';
$rendered_dir = '/public';
$hugo_path = '/usr/local/bin/hugo';
// Validate hook secret
if ($secret !== NULL) {
// Get signature
$hub_signature = $_SERVER['HTTP_X_HUB_SIGNATURE'];
// Make sure signature is provided
if (!isset($hub_signature)) {
file_put_contents('deploy.log', date('m/d/Y h:i:s a') . ' Error: HTTP header "X-Hub-Signature" is missing.' . "\n", FILE_APPEND);
die('HTTP header "X-Hub-Signature" is missing.');
} elseif (!extension_loaded('hash')) {
file_put_contents('deploy.log', date('m/d/Y h:i:s a') . ' Error: Missing "hash" extension to check the secret code validity.' . "\n", FILE_APPEND);
die('Missing "hash" extension to check the secret code validity.');
}
// Split signature into algorithm and hash
list($algo, $hash) = explode('=', $hub_signature, 2);
// Get payload
$payload = file_get_contents('php://input');
// Calculate hash based on payload and the secret
$payload_hash = hash_hmac($algo, $payload, $secret);
// Check if hashes are equivalent
if (!hash_equals($hash, $payload_hash)) {
// Kill the script or do something else here.
file_put_contents('deploy.log', date('m/d/Y h:i:s a') . ' Error: Bad Secret' . "\n", FILE_APPEND);
die('Bad secret');
}
};
// Parse data from GitHub hook payload
$data = json_decode($_POST['payload']);
$commit_message;
if (empty($data->commits)){
// When merging and pushing to GitHub, the commits array will be empty.
// In this case there is no way to know what branch was pushed to, so we will do an update.
$commit_message .= 'true';
} else {
foreach ($data->commits as $commit) {
$commit_message .= $commit->message;
}
}
if (!empty($commit_message)) {
// Do a git checkout, run Hugo, and copy files to public directory
exec('cd ' . $repo_dir . ' && git fetch --all && git reset --hard origin/master');
exec('cd ' . $repo_dir . ' && ' . $hugo_path);
exec('cd ' . $repo_dir . ' && cp -r ' . $repo_dir . $rendered_dir . '/. ' . $web_root_dir);
// Log the deployment
file_put_contents('deploy.log', date('m/d/Y h:i:s a') . " Deployed branch: " . $branch . " Commit: " . $commit_message . "\n", FILE_APPEND);
}
- Create webhook and secret in Github repository.
- Set
GH_DEPLOY_SECRET
as an environment variable for above script to use. - Skip for public repo, else create SSH key if needed
ssh-keygen -t ed25519 -C "githubemail@example.com"
and import key into your account on Github. - May need
eval "$(ssh-agent -s)"
and tell SSH to use the keyssh-add /path/to/key
. - Clone the repo to your web server by running in a suitable directory
git clone git@github.com:you/repo.git
don’t worry about username will authenticate with SSH key. - CD into the repo directory make sure you can run
git fetch --all
. - If this fails, may need to create personal access token in Github and specify it as part of the URL in
.git/config
inside the repo directory. - May also need to run
git config --global --add safe.directory /home/example/git/examplerepo
. - Check line 69 of deployment script and make sure origin/master is correct for your branch.
- Make sure PHP process has execute permissions on Hugo, and has read/write access to repo dir and the web server
public_html
directory, as once built intorepodir/public
it will need to be copied topublic_html
. - Check permissions on the Hugo temp folder
/tmp/hugo_cache/
. - If you can see this post, it worked!
Might write this up as more of an organised general tutorial one day, in the meantime feel free to drop any comments below.