Writing a blog could be much easier with a blogging platform like Wordpress, but then there wouldn't be a reason to create this post. I prefer writing my blog posts like I write documentation in markdown, versioned and self hosted. There's no need to have a big platform running just to serve simple static files.

I use hexo, gitlab and rsync in my build process.

Blogging with Hexo

Hexo is a simple, blog-aware static website framework built on top of Node.js.

Installation

$ npm install hexo-cli -g

Quick Start

Setup your blog

$ hexo init blog
$ cd blog

Start the server

$ hexo server

Generate static files

$ hexo generate

Versioning and Continuous Deployment with Gitlab

Create repository

Initialize a repository in blog and push your first commit.

git init
git remote add origin [email protected]:<user>/<project_name>.git
git add .
git commit -m "Initial commit"
git push -u origin master

Setup Continuous Deployment

Whenever you push new commits, gitlab looks for a file named .gitlab-ci.yml and fires CI/CD pipelines that build, test and deploy your code. Read rest on Gitlab.

  • Create .gitlab-ci.yml file. And fill like in example:
image: node:latest
cache:
  paths:
    - node_modules/
stages:
  - build
  - deploy
job 1:
  stage: build
  script:
    - npm install
    - npm run generate
  artifacts:
    paths:
    - public/
job 2:
  stage: deploy
  script:
    - sshpass -V
    - sshpass -e rsync -r -a -v -e 'ssh -o StrictHostKeyChecking=no -p '$SSH_PORT --delete public $REMOTE_SERVER:/var/www/html/$DIR
  • Notice that $SSH_PORT, $REMOTE_SERVER, and $DIR are not set. One more variable needed by sshpass is $SSHPASS. To setup environment variables, navigate to your repository Settings > CI / CD..
  • Git commit and push. Head over to your repository CI / CD > Jobs to check on deployment progress..

Serve static files

I use nginx to serve https://www.amarjanica.com. Configuration is something like:

server {
  listen 80; 
  server_name .<host_name>;
  root /var/www/html/<my_directory>;
  index index.php index.html index.htm;
}

Gitlab Continuous Deployment

Instead of running software installations on each build, you could save your installs and settings to a Dockerfile, and serve the image with Gitlab's container registry.

Create docker file

Create your docker file in root of your project.

FROM node:latest
ENV LANG C.UTF-8

Build image

Log in to GitLab’s Container Registry using your GitLab username and password.

docker login registry.gitlab.com

Once you log in, you’re free to create and upload a container image using the common build and push.

docker build -t registry.gitlab.com/<user>/<repository> .
docker push registry.gitlab.com/<user>/<repository>

Reference image in ci

Edit gitlab-ci.yml and reference your docker image:

image: registry.gitlab.com/<user>/<repo>:latest
cache:
  paths:
    - node_modules/
stages:
  - build
  - deploy
  ....

Troubleshoot

i/o timeout on docker push

Try changing /etc/resolv.conf nameserver to 8.8.8.8 and try again.

Permission denied

If you get permission denied when trying to rsync with remote server, then you need to add your user to www-data group.
Login to your server and change group ownership and permissions of /var/www/html:

sudo chgrp -R www-data /var/www/html
sudo gpasswd -a  www-data
sudo chmod -R 775 /var/www/html

Try creating a file in /var/www/html. If you still get permission denied, you'll probably need a new login session, or a server restart.