New post: Deploy a Hugo Website with GIT
Signed-off-by: Ettore <noettore@gmail.com>
This commit is contained in:
113
content/blog/deploy-hugo-git.md
Normal file
113
content/blog/deploy-hugo-git.md
Normal file
@@ -0,0 +1,113 @@
|
||||
---
|
||||
title: "Deploy a Hugo Website with GIT"
|
||||
tags: ["hugo", "gogs", "git", "deploy", "webhook"]
|
||||
categories: ["recipe"]
|
||||
description: "How to deploy a hugo-powered static website to a webserver with Gogs"
|
||||
date: 2019-05-27T20:34:30+02:00
|
||||
author: "Ettore Dreucci"
|
||||
draft: false
|
||||
---
|
||||
|
||||
## [[recipe]({{< ref "/categories/recipe" >}})]: How to deploy a hugo-powered static website to a webserver with GIT
|
||||
|
||||
[This](https://ettore.dreucci.it) website is powered by [Hugo](https://gohugo.io/), an open-source static website generator written in [Go](https://golang.org/). I can write pages and posts in [Markdown](https://daringfireball.net/projects/markdown/) and then generate some static .html pages to upload to a webserver.
|
||||
|
||||
For this project, as I usually do, I push every change to a self-hosted [GIT](https://git-scm.com/) server with [Gogs](https://gogs.io/) (another open-source, golang written GIT server), so why not use webhooks to automate the deployment?
|
||||
|
||||
Gogs, as GitHub, GitLab and other well-known services provides webhooks to notify other services of changes in a repository: they are basically HTTP callbacks triggered by some user-defined events such as a push or a pull request. Each time you, for instance, push to a repo, Gogs will send a **HTTP POST** payload to the webhook’s configured URL: the payload will contain the relevant event information.
|
||||
|
||||
To protect from unauthorized requests you could tell Gogs to send, in the header of the POST request, a `X-Gogs-Signature` that contains the **HMAC hex digest of the payload** generated using the `sha256` hash function and a **secret** as the HMAC key.
|
||||
|
||||
My event-chain is the following: I push the new content to the repo, Gogs trigger a webook that send a HTTP POST payload to a .php page in the webserver. The php-page pulls the repo to the server, generates the static website with `hugo` and copies the newly generated `public` directory to the document root of the webserver.
|
||||
|
||||
#### So, let’s see the practical part:
|
||||
|
||||
1. Add in the Gogs repository configuration an ssh *Deploy Key*, to pull the repo in the webserver. The *deploy key* will have read-only access.
|
||||
You can generate the ssh key with `ssh-keygen` but keep it password-less to make the pull completely automated.
|
||||
|
||||
2. Clone the repo in the document root with
|
||||
````
|
||||
git clone user@git.server:repo /var/www/
|
||||
````
|
||||
|
||||
3. Insert in your `.htaccess` file the secret like that:
|
||||
````
|
||||
SetEnv GOGS_DEPLOY_SECRET y0uRs3cRetC0d3
|
||||
````
|
||||
|
||||
4. Create a `deploy.php` page that will pull the repo, generate the website and deploy it when called.
|
||||
You can use the following script:
|
||||
````
|
||||
<?php
|
||||
/**
|
||||
* Automated deploy from Gogs
|
||||
*
|
||||
* Template from ServerPilot (https://serverpilot.io/community/articles/how-to-automatically-deploy-a-git-repo-from-bitbucket.html)
|
||||
* Hash validation from liogate (https://github.com/gogs/gogs/issues/4233#issue-211797295)
|
||||
*/
|
||||
|
||||
// Variables
|
||||
$secret = getenv('GOGS_DEPLOY_SECRET');
|
||||
$repo_dir = '/path/to/repo/';
|
||||
$web_root_dir = '/var/www/';
|
||||
$rendered_dir = '/public';
|
||||
$hugo_path = '/usr/local/bin/hugo';
|
||||
|
||||
// Validate hook secret
|
||||
if ($secret !== NULL) {
|
||||
// Get signature
|
||||
$gogs_signature = $_SERVER['HTTP_X_GOGS_SIGNATURE'];
|
||||
|
||||
// Make sure signature is provided
|
||||
if (!isset($gogs_signature)) {
|
||||
file_put_contents('deploy.log', date('m/d/Y h:i:s a') . ' Error: HTTP header "X-Gogs-Signature" is missing.' . "\n", FILE_APPEND);
|
||||
die('HTTP header "X-Gogs-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.');
|
||||
}
|
||||
|
||||
// Get payload
|
||||
$payload = file_get_contents('php://input');
|
||||
|
||||
// Calculate hash based on payload and the secret
|
||||
$payload_hash = hash_hmac('sha256', $payload, $secret, false);
|
||||
|
||||
// Check if hashes are equivalent
|
||||
if (!hash_equals($gogs_signature, $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 Gogs hook payload
|
||||
$data = json_decode($_POST['payload']);
|
||||
|
||||
$commit_message;
|
||||
if (empty($data->commits)){
|
||||
// When merging and pushing to Gogs, 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 pull, run Hugo, and copy files to public directory
|
||||
exec('cd ' . $repo_dir . ' && git pull');
|
||||
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);
|
||||
}
|
||||
````
|
||||
|
||||
5. In the Gogs repository webpage, activate a webhook, specifying the `deploy.php` URL, the content type (`application/json`) and a secret. Then select the event(s) that will trigger the webhook.
|
||||
|
||||
6. You’re done! Write a new post, push it and see the magic ;)
|
||||
|
Reference in New Issue
Block a user