Hexo in a container

Hexo in docker or podman

A bit of context

It’s July 2024 and I finally decided to create my personal blog using a static website builder.
For that, I want to develop a simple tool to ease the workflow.
With the help of containerization and make, I aim to abstract away the complexities of setting up the development environment across different computers.
Here is what I did:

Prerequisites

We need to have the following tools in our environment beforehand:

Setting up the environment

I have previous experience with HEXO static website generator and I decided to use it for this task.

I explored what Hugo and Jekyll have to offer before choosing HEXO, but I didn’t find any compelling reasons to switch to either of them.
While I might consider them for learning purposes in the future, for now, HEXO does the job just fine!

To get everything up and running, we’ll need to create a total of four different files (Yes, just 4 files and we are ready to rock with HEXO!)

For the Docker image

The Dockerfile is relatively simple. we just have to install hexo-cli globally in the node:lts-alpine image.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Use an official Node.js runtime as a parent image
FROM node:lts-alpine

# Install Hexo CLI
RUN npm install -g hexo-cli

# Set the user and group IDs (very useful for file permissions between the host and the container)
USER 1000:1000

# Create app directory
RUN mkdir /app
WORKDIR /app

# Expose Hexo server port
EXPOSE 4000

I purposefully omitted the command to run the HEXO server here because we will also use this image to create the hexo project.
This part will be handled by the docker-compose.yml file.

The environment config file

The .env file will contains our blog name, and is used by docker-compose.yml and Makefile

1
BLOG_NAME=my_blog

As a commun sense, avoid using blank spaces in the naming.

For docker-compose

1
2
3
4
5
6
7
8
9
10
11
12
version: '3'
services:
hexo:
build: .
container_name: hexo_dev
ports:
- "4000:4000"
volumes:
- ./${BLOG_NAME}:/app/${BLOG_NAME}
env_file:
- .env
command: sh -c "cd ${BLOG_NAME} && if [ ! -d node_modules ]; then npm install; fi && hexo server -i 0.0.0.0"

As mentionned previously, this file contains the command to be run by the image once the container is created and started.
In our case either npm install or hexo server.

Makefile

The real magic happens with Make tool!
In the Makefile we abstract away the complexities of Docker (or Podman) and HEXO commands.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
include .env
#---DOCKER---#
ifeq ($(shell where podman 2> NUL),)
DOCKER_COMPOSE = docker compose
#DOCKER_COMPOSE = docker-compose
else
DOCKER_COMPOSE = podman-compose --project-name hexo-dev
endif
DOCKER_COMPOSE_DOWN = $(DOCKER_COMPOSE) down
DOCKER_COMPOSE_UP = $(DOCKER_COMPOSE) up -d
#DOCKER_COMPOSE_UP = $(DOCKER_COMPOSE) up
DOCKER_COMPOSE_BUILD = $(DOCKER_COMPOSE) build
DOCKER_COMPOSE_RUN = $(DOCKER_COMPOSE) run --rm hexo
EXEC = $(DOCKER_COMPOSE) exec --workdir /app/${BLOG_NAME} hexo
NEW = $(EXEC) hexo new
#------------#

%:
@true

from-scratch:
@echo "Creating new Hexo project: $(BLOG_NAME)"
$(DOCKER_COMPOSE_BUILD)
@mkdir -p ${BLOG_NAME}
$(DOCKER_COMPOSE_RUN) hexo init ${BLOG_NAME}
.PHONY: from-scratch

build:
@echo "Building the container"
$(DOCKER_COMPOSE_BUILD)
.PHONY: build

start:
@echo "Starting Hexo server for project: $(BLOG_NAME)"
$(DOCKER_COMPOSE_UP)
.PHONY: start

stop:
@echo "Stopping Hexo server for project: $(BLOG_NAME)"
$(DOCKER_COMPOSE_DOWN)
.PHONY: stop

restart: # restart env
$(DOCKER_COMPOSE_DOWN)
$(DOCKER_COMPOSE_UP)
.PHONY: start

new-post: #create new post
$(NEW) post "$(filter-out $@, $(MAKECMDGOALS))"
.PHONY: new-post

new-page: #create new page
$(NEW) page "$(filter-out $@, $(MAKECMDGOALS))"
.PHONY: new-page

generate: #generate
$(EXEC) hexo generate
.PHONY: generate

deploy: #deploy
$(EXEC) git config --global user.email "docker@docker.home"
$(EXEC) git config --global user.name "docker"
$(EXEC) hexo clean
$(EXEC) hexo deploy
.PHONY: deploy

How to use the tool

Once the Makefile done, it is very straightforward to use:

  • To create hexo website project from scratch, change the name in the .env file then run:
1
make from-scratch
  • To start an existing project, assuming the project is in the directory and set the .env file accordingly, then we run:
1
make start

It will run an npm install on the project before running the HEXO server

The website should then be available on http://localhost:4000.

Everything is in place and ready to be used. Good luck!

  • Eventually if we need to build or rebuild the container:
1
make build

The rest of the commands in Makefile follows the same logic

End Notes

This is my current setup. It’s sure not perfect but it is good enough for my use case.
In my mind, if I can forget the tools and just focus on the content then I’m happy.
And happy I am :) !