How to Install and Create a Blog with Hexo on Ubuntu 20.04

Hexo is a static blogging framework built on Node.js. Hexo allows you to write posts in Markdown format. These blog posts are processed and converted into static HTML files using pre-defined themes.

It is different from the usual blogging software like WordPress as it generates static files. WordPress loads the blog dynamically by running PHP code every time you reload the site which makes it susceptible to vulnerabilities.

In this tutorial, you will learn how to Install Hexo and use it to create a blog on Ubuntu 20.04 based server.


  1. Ubuntu 20.04 based server with a non-root user with sudo privileges.

  2. Git should be installed. If you don't have git installed, you can do it via following commands.

    $ sudo apt install git
    $ git config --global "Your Name"
    $ git config --global "[email protected]"
  3. An account on Github.

Configure Firewall

Ubuntu 20.04 comes with Uncomplicated Firewall(UFW) by default. In case it is not, install it first.

$ sudo apt install ufw

Enable SSH port.

$ sudo ufw allow "OpenSSH"

Enable the firewall.

$ sudo ufw enable

Enable the port 4000 which is used by the Hexo server.

$ sudo ufw allow 4000

Also, open the HTTP and HTTPS ports which we will need later.

$ sudo ufw allow http
$ sudo ufw allow https

Check the firewall status.

$ sudo ufw status
Status: active

To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere
80/tcp                     ALLOW       Anywhere
4000                       ALLOW       Anywhere
443/tcp                    ALLOW       Anywhere
OpenSSH (v6)               ALLOW       Anywhere (v6)
80/tcp (v6)                ALLOW       Anywhere (v6)
4000 (v6)                  ALLOW       Anywhere (v6)
443/tcp (v6)               ALLOW       Anywhere (v6)

Install Node.js

Since Hexo is based on Node.js, you need to install it first.

Run the following command to add Node.js Repository.

$ curl -sL | sudo -E bash -

Install Node.js.

$ sudo apt-get install nodejs

Confirm if it is installed properly.

$ node --version

Install Hexo

Run the following command to install the Hexo package.

$ sudo npm install hexo-cli -g

The -g parameter installs the hexo-cli package globally which will allow you to install Hexo blog in any directory of your choice.

Create the directory to install Hexo in.

$ sudo mkdir -p /var/www/hexo

Set the required permissions and ownership.

$ sudo chown -R $USER:$USER /var/www/hexo
$ sudo chmod -R 755 /var/www/hexo

Next, you need to initialise and set up the necessary files for the Hexo blog. To do that, switch to the directory you just created.

$ cd /var/www/hexo

Initialise the Hexo blog.

$ hexo init
INFO  Cloning hexo-starter
INFO  Install dependencies
added 185 packages from 430 contributors and audited 191 packages in 6.47s

14 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

INFO  Start blogging with Hexo!

Install Hexo.

$ npm install
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: [email protected] (node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for [email protected]: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})

added 5 packages from 1 contributor and audited 191 packages in 1.567s

14 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

You can now check the directory structure.

$ ls
_config.yml  node_modules  package-lock.json  package.json  scaffolds  source  themes

The _config.yml file holds the configuration for your Hexo blog. Most of the blog settings can be changed from here.

The node_modules directory holds all the packages Hexo needs and the ones that it depends on.

The package.json file contains a list of all the packages and their version numbers that Hexo needs.

The package-lock.json file is automatically generated by npm every time you perform an installation or a change to the Hexo package. It contains information about packages and the versions that were installed or changed.

The scaffolds directory contains the templates on which your blog posts and pages will be based.

The source directory contains the actual site content in HTML/CSS format which is then published on to the web. Any folder or file prefixed with _(underscores) is ignored by Hexo except the _posts folder. For now, the directory is empty because we haven't written or published anything.

The themes directory contains your Blog themes.

Configure Hexo

Open the _config.yml file for editing.

$ nano _config.yml

Check the section of the file titled Site

# Hexo Configuration
## Docs:
## Source:

# Site
title: Hexo
subtitle: ''
description: ''
author: John Doe
language: en
timezone: ''

The options are pretty self-explanatory. Change the name of your site, set a subtitle if you like. Add a description of your site and some keywords to describe it. Change the author name and the time-zone for your site.

Next, check the URL section of the file.

## If your site is put in a subdirectory, set url as '' and root as '/child/'
root: /
permalink: :year/:month/:day/:title/
  trailing_index: true # Set to false to remove trailing 'index.html' from permalinks
  trailing_html: true # Set to false to remove trailing '.html' from permalinks

Change the URL of your site to your domain name. Make sure you use HTTPS in your URL since we will install SSL later.

If you don't want your site URL to show index.html at the end of each page, you can change both the options trailing_index and trailing_html to false.

There are a few more settings you should turn on.

Change the value of the default_layout variable from post to draft. This will create new posts as drafts so you will need to publish them before they appear on the blog.

Change the value of the post_asset_folder variable to true. This will allow you to have individual image folders for each post instead of a single image folder for all posts.

Save the file by pressing Ctrl+X and entering Y when prompted.

Installing a Theme

Hexo ships with a default theme named Landscape. You can switch to a different theme by installing another Hexo theme available from its Themes page.

All the Hexo themes are available via Github so you need to clone the theme's Github repository.

For our tutorial, we are installing the Next theme. Switch to the Hexo directory and Clone the theme's Github repository into the themes directory.

$ cd /var/www/hexo
$ git clone themes/next

Change the /var/www/hexo/_config.yml file to change the theme from Landscape to Next.

$ nano _config.yml

Make the change to the theme variable to switch the theme.

# Extensions
## Plugins:
## Themes:
theme: next

You can change the theme settings by modifying the /var/www/hexo/themes/next/_config.yml file.

Create and Publish a Post

Time to create our first post.

$ hexo new first-post
INFO  Validating config
INFO  Created: /var/www/hexo/source/_drafts/

Open the new post for editing.

$ nano ./source/_drafts/

Every post needs to have its front-matter set up. Front-matter is a short block of JSON or YAML that configures essential details like the title of the post, published date, categories, tags, etc. Replace the default data with the correct options.

title: Howtoforge's First Post
  - test
  - Hexo
comments: true
date: 2020-11-14 00:00:00

## Markdown goes here.

**This is our first post!**

If you want to insert an image in your post, add the following code in your post.

{% asset_img "example.jpg" "This is an example image" %}

After that, copy the file example.jpg to the \source\_posts\first-post directory which is where all images for your first post will be retrieved from.

Save the file by pressing Ctrl+X and entering Y when prompted once you are finished writing the post.

Next, publish the post.

$ hexo publish first-post
INFO  Validating config
INFO  Published: /var/www/hexo/source/_posts/

This post will be visible once we host the blog.

Installing a Plugin

Hexo has few hundred plugins that you can install. You can install one or more plugins depending upon your usage.

All the Hexo plugins are Node.js packages and hosted on Github where you can find their installation and configuration details.

For our tutorial, we will install the hexo-filter-nofollow plugin.

Make sure you are in the hexo directory first and then install the plugin.

$ cd /var/www/hexo
$ npm i hexo-filter-nofollow --save

Open the Hexo configuration file for editing.

$ sudo nano _config.yml

Paste the following code at the end of the file.

  enable: true
  field: site
    - ''
    - ''

The enable option enables the Plugin. The field option defines the scope of the plugin where site adds nofollow attribute to the external links on the entire site and post adds nofollow attribute only to the links in the posts. The exclude option whitelists domains on which nofollow attribute won't be added.

Test Server

Hexo ships with a basic web server. Now that our post is published, it is time to start the Hexo test server.

$ hexo server

You can now launch the URL http://yourserverIP:4000 in your browser and you will see the following page.

Hexo Blog Homepage

Exit the server by pressing Ctrl + C at the terminal.

Generate Hexo Static files

The Test server of Hexo can serve the blog dynamically as well as through the static files. The above command served the blog dynamically.

There are several ways to serve Hexo blog publicly. For our tutorial, we will serve Hexo's static files using Nginx server.

Run the following command to generate the static files.

$ hexo generate

The above command generates static files which are stored in the /var/www/hexo/public folder. We will use Nginx server to serve files from this folder.

Install and Configure Nginx

Install Nginx server.

$ sudo apt install nginx

Create and open the Hexo configuration file for Nginx.

$ sudo nano /etc/nginx/sites-available/hexo.conf

Paste the following code in it.

server {

    root /var/www/hexo/public;
    index index.html index.htm;

    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    ssl_certificate /etc/letsencrypt/live/;
    ssl_certificate_key /etc/letsencrypt/live/;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_session_timeout 1d;
    ssl_session_cache shared:MozSSL:10m;  # about 40000 sessions
    ssl_session_tickets off;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES25>             ssl_prefer_server_ciphers off;
    ssl_dhparam /etc/ssl/certs/dhparam.pem;
    location / {
        try_files $uri $uri/ =404;
server {
    if ($host = {
        return 301 https://$host$request_uri;
    listen 80;
    listen [::]:80;
    return 404;

Save the file by pressing Ctrl+X and entering Y when prompted.

Activate the configuration.

$ sudo ln -s /etc/nginx/sites-available/hexo.conf /etc/nginx/sites-enabled/

Open the /etc/nginx/nginx.conf file for editing.

$ sudo nano /etc/nginx/nginx.conf	

Paste the following line before the line include /etc/nginx/conf.d/*.conf

server_names_hash_bucket_size 64;

Change the value of the variable types_hash_max_size from 2048 to 4096.

types_hash_max_size 4096;

Press Ctrl + X to close the editor and press Y when prompted to save the file.

Test to make sure there are no syntax errors in your configuration.

$ sudo nginx -t

If there aren't any issues, restart the Nginx server.

$ sudo systemctl restart nginx

Install SSL

It is time to install SSL using Let's Encrypt service for our hexo blog.

For that, install Certbot.

$ sudo apt install certbot

Stop Nginx because it will interfere with the Certbot process.

$ sudo systemctl stop nginx

Generate the certificate. We also need to create a DHParams certificate.

$ sudo certbot certonly --standalone -d --preferred-challenges http --agree-tos -n -m [email protected] --keep-until-expiring 
$ sudo systemctl start nginx
$ sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048

We also need to set up a cron job for renewing the SSL automatically. To open the crontab editor, run the following command.

$ sudo crontab -e
no crontab for root - using an empty one

Select an editor.  To change later, run 'select-editor'.
  1. /bin/nano        <---- easiest
  2. /usr/bin/vim.basic
  3. /usr/bin/vim.tiny
  4. /bin/ed

Choose 1-4 [1]: 1

The above command opens Crontab editor. If you are running it for the first time, you will be asked to choose the editor for editing Cron jobs. Choose 1 for the Nano editor.

Paste the following line at the bottom.

25 2 * * * /usr/bin/certbot renew --quiet --pre-hook “systemctl stop nginx” --post-hook “systemctl start nginx”

The above cron job will run certbot at 2:25 am every day. You can change it to anything you want.

Save the file by pressing Ctrl + X and entering Y when prompted.

Update Hexo

Switch to the Hexo folder.

$ cd /var/www/hexo

If you are switching to a major Hexo version, you need to update the package.json file. Open it for editing. You can skip directly to the update command for updating to minor versions.

$ nano package.json

Change the following line under the dependencies section.

"hexo": "^5.0.0",

Change the value 5.0.0 to the next version whenever it releases in the future. For example, if Hexo 6.0 is out, then change it to following.

"hexo": "^6.0.0",

Save the file by pressing Ctrl + X and entering Y when prompted.

Run the following command to update hexo.

$ npm update

Deploying Hexo

Hexo can not only be hosted directly on your server but can also be deployed directly on Git, Netlify, Vercel, Heroku, OpenShift and various other methods.

Most of the deployment plugins require you to install a plugin. For our tutorial, we will setup Hexo's deployment to Netlify. If you want to deploy to Netlify, then you don't need to follow the steps related to Nginx and SSL as Netlify comes with free SSL.

A Netlify's site is usually deployed from a Git repository. But for our purpose, we will directly publish the static site to Netlify using its CLI tool.

Install Netlify CLI.

$ sudo npm install netlify-cli -g

You can verify to see if the CLI tool was installed.

$ netlify --version
netlify-cli/2.68.5 linux-x64 node-v14.15.0

Login to Netlify.

$ netlify login
Logging into your Netlify account...

You are now logged into your Netlify account!

Run netlify status for account details

To see all available commands run: netlify help

Copy the login from the terminal in your browser and login to your Netlify account to authentifcate.

You can check if you are logged in by using the following command.

$ netlify status
 Current Netlify User ?
Name:  Your Name
Email: [email protected]
  Your Team's team: Collaborator

Switch to Hexo's public directory.

$ cd /var/www/hexo/public

Deploy the site to Netlify.

$ netlify deploy
This folder isn't linked to a site yet
? What would you like to do? +  Create & configure a new site
? Team: Navjot Singh's team
Choose a unique site name (e.g. or leave it blank for a random name. You can update the site name later.
? Site name (optional): Howtoforge

Site Created

Admin URL:
Site ID:   986c931c-3f06-40a1-a89b-59621f337c18
Please provide a publish directory (e.g. "public" or "dist" or "."):
? Publish directory /var/www/hexo/public
Deploy path: /var/www/hexo/public
Deploying to draft URL...
? Finished hashing 37 files
? CDN requesting 9 files
? Finished uploading 9 assets
? Deploy is live!

Website Draft URL:

If everything looks good on your draft URL, deploy it to your main site URL with the --prod flag.

Choose by arrow keys to create a new site and enter a name for your site. Enter . as the directory to deploy from which refers to the current directory.

You will be given a draft URL. Copy the URL and load it into a browser. If everything looks fine, then run the following command to do a production deployment.

$ netlify deploy --prod

Your site should now be live. You can add a custom domain in Netlify settings to point it into a real site.

Every time you publish a new post and generate fresh files, run the following command from Hexo's main directory to deploy the changes to Netlify.

$ netlify deploy --dir ./public --prod


This concludes our tutorial to install and create a blog using the Hexo Blog framework on Ubuntu 20.04 based server. If you have any questions, post them in the comments below.

Share this page:

0 Comment(s)