Technology Encyclopedia Home > How to Set Up a Hexo Static Blog on a Cloud Server — Fast, Developer-Friendly Publishing

How to Set Up a Hexo Static Blog on a Cloud Server — Fast, Developer-Friendly Publishing

I write in Markdown. I think in Markdown. Having to go through a web CMS to publish felt like an extra step that was getting in the way of actually writing.

Hexo fits the way I naturally work: write a .md file in my editor, run one command, and the site updates. The generated output is plain static HTML that Nginx serves at full speed — no PHP, no database, no application server to manage. My Hexo blog consistently loads in under a second even from regions far from the server.

The part of this setup I'm most pleased with is the automated deployment pipeline: write on my laptop, push to GitHub, and the server pulls and rebuilds automatically. I only touch the server once to set it up.

I run this on Tencent Cloud Lighthouse. Hexo generates static files — the entry-level plan handles this perfectly, since serving static HTML with Nginx uses almost no server resources. The fixed monthly bandwidth allowance means traffic spikes from a viral post won't generate surprise bills. For readers in different regions, adding Tencent Cloud EdgeOne as a CDN layer delivers blog content from nodes close to each reader, significantly improving load times globally.


Table of Contents

  1. Why Hexo?
  2. Prerequisites
  3. Part 1 — Set Up the Server
  4. Part 2 — Configure Git and the Bare Repository
  5. Part 3 — Configure Nginx
  6. Part 4 — Set Up Hexo Locally
  7. Part 5 — Write and Deploy Your First Post
  8. Part 6 — Enable HTTPS
  9. Part 7 — Automate Deployment with GitHub Actions
  10. Part 8 — Themes and Customization
  11. The Gotcha: Public Path and Broken Links
  12. Common Hexo Commands

  • Key Takeaways
  • Use the appropriate Lighthouse application image to skip manual installation steps where available
  • Lighthouse snapshots provide one-click full-server backup before major changes
  • OrcaTerm browser terminal lets you manage the server from any device
  • CBS cloud disk expansion handles growing storage needs without server migration
  • Console-level firewall + UFW = two independent protection layers

Why Hexo? {#why}

Feature Hexo WordPress Ghost
Database required No (static) Yes Yes
Server resources Minimal (Nginx + static files) High Medium
Writing experience Markdown in any editor Browser/Gutenberg Browser
Build time Very fast (seconds) N/A N/A
Themes 300+ open-source themes Thousands Hundreds
Comments Via Disqus/utterances Built-in Built-in
Best for Developers, technical blogs General websites Newsletters

Prerequisites {#prerequisites}

Requirement Notes
Cloud server Tencent Cloud Lighthouse Ubuntu 22.04
Local machine Node.js 16+ installed
A domain name For HTTPS

Part 1 — Set Up the Server {#part-1}

ssh ubuntu@YOUR_SERVER_IP
sudo apt update && sudo apt upgrade -y
sudo apt install -y git nginx nodejs npm

sudo ufw allow ssh
sudo ufw allow 'Nginx Full'
sudo ufw enable

# Create web root
sudo mkdir -p /var/www/hexo
sudo chown ubuntu:www-data /var/www/hexo
sudo chmod 755 /var/www/hexo

Part 2 — Configure Git and the Bare Repository {#part-2}

The deployment workflow: your local Hexo project pushes generated HTML to a "bare" Git repository on the server. A Git hook copies the files to the Nginx web root automatically.

Create a git user (optional but recommended)

sudo adduser git
sudo mkdir -p /home/git/.ssh
sudo chmod 700 /home/git/.ssh

Copy your SSH public key to the git user:

# Paste your public key content
sudo nano /home/git/.ssh/authorized_keys
sudo chmod 600 /home/git/.ssh/authorized_keys
sudo chown -R git:git /home/git/.ssh

Create the bare repository

sudo -u git bash
mkdir ~/hexo-blog.git
git init --bare ~/hexo-blog.git

Create the post-receive hook

nano ~/hexo-blog.git/hooks/post-receive
#!/bin/bash
GIT_REPO=/home/git/hexo-blog.git
TMP_DIR=/tmp/hexo-deploy
DEPLOY_DIR=/var/www/hexo

rm -rf $TMP_DIR
git clone $GIT_REPO $TMP_DIR
rsync -av --delete $TMP_DIR/ $DEPLOY_DIR/
rm -rf $TMP_DIR

echo "Hexo blog deployed to $DEPLOY_DIR"
chmod +x ~/hexo-blog.git/hooks/post-receive
exit  # Back to ubuntu user

Part 3 — Configure Nginx {#part-3}

sudo nano /etc/nginx/sites-available/hexo
server {
    listen 80;
    server_name yourdomain.com www.yourdomain.com;

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

    access_log /var/log/nginx/hexo_access.log;
    error_log  /var/log/nginx/hexo_error.log;

    location / {
        try_files $uri $uri/ =404;
    }

    # Custom 404
    error_page 404 /404.html;

    # Cache static assets
    location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff|woff2|svg)$ {
        expires 30d;
        add_header Cache-Control "public, no-transform";
    }

    # Gzip compression
    gzip on;
    gzip_types text/plain text/css application/json application/javascript text/xml;
    gzip_vary on;
}
sudo ln -s /etc/nginx/sites-available/hexo /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

Part 4 — Set Up Hexo Locally {#part-4}

On your local machine:

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

# Create a new blog
hexo init my-blog
cd my-blog
npm install

# Install the Git deployment plugin
npm install hexo-deployer-git --save

Edit _config.yml:

# Site info
title: My Developer Blog
subtitle: "Notes on code and infrastructure"
description: "Personal blog about software development"
author: Your Name
language: en
timezone: America/New_York

# URL
url: https://yourdomain.com

# Deploy configuration
deploy:
  type: git
  repo: git@YOUR_SERVER_IP:/home/git/hexo-blog.git
  branch: master
  message: "Deploy: {{ now('YYYY-MM-DD HH:mm:ss') }}"

Test the local server:

hexo server
# Visit http://localhost:4000

Part 5 — Write and Deploy Your First Post {#part-5}

Create a new post

hexo new post "My First Blog Post"
# Creates: source/_posts/my-first-blog-post.md

Edit the file:

---
title: My First Blog Post
date: 2026-04-20 10:00:00
tags:
  - tech
  - tutorial
categories:
  - Cloud
cover: /images/cover.jpg
---

This is my first post on my self-hosted Hexo blog, running on Tencent Cloud Lighthouse.

<!-- more -->

The rest of the post appears after the "Read more" fold.

## Section Heading

Content continues here...

Build and deploy

# Generate static files
hexo clean && hexo generate

# Deploy to server
hexo deploy

# Or both in one command:
hexo clean && hexo g -d

Visit http://yourdomain.com — your post should appear.


Part 6 — Enable HTTPS {#part-6}

sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com

Update the URL in your local _config.yml:

url: https://yourdomain.com

Redeploy: hexo clean && hexo g -d


Part 7 — Automate Deployment with GitHub Actions {#part-7}

For automatic deployment when you push to GitHub (building on the server avoids Hexo dependency on your local machine):

Add Node.js to the server

curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs
npm install -g hexo-cli

Update the post-receive hook to build on server

sudo -u git nano ~/hexo-blog.git/hooks/post-receive
#!/bin/bash
GIT_REPO=/home/git/hexo-blog.git
TMP_DIR=/tmp/hexo-source
DEPLOY_DIR=/var/www/hexo

rm -rf $TMP_DIR
git clone $GIT_REPO $TMP_DIR
cd $TMP_DIR

# Build Hexo on the server
npm install 2>/dev/null
hexo generate

# Deploy to web root
rsync -av --delete $TMP_DIR/public/ $DEPLOY_DIR/
rm -rf $TMP_DIR

echo "Hexo blog built and deployed"

GitHub Actions (push Markdown source, build on server)

Push your source (not the generated public/ folder) to GitHub, then trigger a server build:

name: Deploy Hexo Blog

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Trigger server build
        uses: appleboy/ssh-action@v1.0.0
        with:
          host: ${{ secrets.SERVER_IP }}
          username: ubuntu
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          script: |
            cd /tmp
            git clone git@localhost:/home/git/hexo-blog.git hexo-temp
            cd hexo-temp && npm install && hexo generate
            rsync -av --delete public/ /var/www/hexo/
            rm -rf /tmp/hexo-temp

Part 8 — Themes and Customization {#part-8}

Install a theme

# Example: Fluid theme (clean, modern)
npm install --save hexo-theme-fluid

# In _config.yml:
theme: fluid

Create a theme config file

cp node_modules/hexo-theme-fluid/_config.yml _config.fluid.yml

Edit _config.fluid.yml to customize:

  • Navigation bar
  • Homepage banner image
  • Social links
  • Code highlighting
  • Comment system (Disqus, utterances, Valine)
npm install hexo-generator-searchdb --save
# In _config.yml:
search:
  path: search.xml
  field: post

If your blog URL has a subfolder (e.g., yourdomain.com/blog/), all generated asset paths must include that prefix. Update in _config.yml:

url: https://yourdomain.com/blog
root: /blog/

For a root deployment (yourdomain.com), leave root: / (the default).

Missing this causes broken CSS, JavaScript, and image links on the deployed site. Always match url and root to your actual deployment path.


Common Hexo Commands {#commands}

# Local development
hexo server          # Start local dev server at localhost:4000
hexo server -p 4001  # Custom port

# Build
hexo clean           # Remove generated files
hexo generate        # Generate static files (hexo g)
hexo g -d            # Generate and deploy

# Posts
hexo new post "Title"      # Create new post
hexo new page "about"      # Create new page
hexo new draft "Title"     # Create draft (not published)
hexo publish "Title"       # Move draft to posts

# Deploy
hexo deploy              # Deploy to configured destination (hexo d)

Troubleshooting {#troubleshooting}

Issue Likely Cause Fix
Connection refused Service not running or wrong port Check systemctl status SERVICE and verify firewall rules
Permission denied Wrong file ownership or permissions Check file ownership with ls -la and use chown/chmod to fix
502 Bad Gateway Backend service not running Restart the backend service; check logs with journalctl -u SERVICE
SSL certificate error Certificate expired or domain mismatch Run sudo certbot renew and verify domain DNS points to server IP
Service not starting Config error or missing dependency Check logs with journalctl -u SERVICE -n 50 for specific error
Out of disk space Logs or data accumulation Run df -h to identify usage; clean logs or attach CBS storage
High memory usage Too many processes or memory leak Check with htop; consider upgrading instance plan if consistently high
Firewall blocking traffic Port not open in UFW or Lighthouse console Open port in Lighthouse console firewall AND sudo ufw allow PORT

Frequently Asked Questions {#faq}

How long does it take to set up Hexo blog on a cloud server?
With the appropriate Lighthouse application image (if available), setup takes 10–30 minutes. Manual installation from a plain Ubuntu image typically takes 30–90 minutes following this guide.

What server specifications do I need for Hexo blog?
Check the prerequisites section of this guide for specific requirements. As a general rule: start with the minimum recommended spec, monitor actual usage, and upgrade from the Lighthouse console if needed.

How do I keep Hexo blog updated?
Follow the update procedure specific to how it was installed (package manager, Docker pull, or binary replacement). Take a Lighthouse snapshot before any major update as a safety net.

How do I back up Hexo blog data?
Use Lighthouse snapshots for full-server recovery plus the application's own export/backup mechanism for granular recovery. Both together provide comprehensive backup coverage.

Can I run Hexo blog alongside other services on the same server?
Yes, with sufficient resources. Docker-based setups provide good isolation. Monitor resource usage with htop and expand the server spec or attach CBS storage as needed.

Start your developer blog today:
👉 Tencent Cloud Lighthouse — Ubuntu VPS for static sites
👉 View current pricing and promotions
👉 Explore all active deals and offers