Self-Hosted Blogging Solution: A Deep Dive Setup Guide

Introduction#
In this post, I’ll walk you through the step-by-step process of how I set up this site as a self-hosted blogging solution. This guide covers everything from creating a lean Alpine Linux container on Proxmox, configuring the Hugo environment with all necessary packages, to automating the build and deployment process via a custom script. I’ll also share tips on using Visual Studio Code (VSC) with SSH plugins to manage your container seamlessly.
This solution was born from a desire to have full control over my content and deployment process—without relying on external, often finicky, managed platforms. Let’s dive in!
Prerequisites#
Before you begin, make sure you have:
- A Proxmox server to host your Alpine Linux container.
- An Alpine Linux container running on Proxmox.
- Basic familiarity with the command line.
- Nginx installed on your Alpine server (or a reverse proxy configured on your home server) to serve your static site.
- A domain (e.g.,
cliffixit.com
) with DNS properly configured to point to your reverse proxy. - Visual Studio Code (VSC) installed with an SSH extension (such as “Remote - SSH”) to edit files on the container.
Step 1: Setting Up the Alpine Linux Container#
- Create an Alpine Linux container on Proxmox.
- Log into the Proxmox Web UI: Open your browser and navigate to your Proxmox management interface. Navigate to Storage → Content: Click on “Templates” and download a minimal Linux template.
(Tip: For the smallest footprint, choose Alpine Linux or, if you prefer a bit more familiarity, a Debian minimal template. Allocate minimal resources such as 1 CPU core and 256–512 MB of RAM.)
- Log into the Proxmox Web UI: Open your browser and navigate to your Proxmox management interface. Navigate to Storage → Content: Click on “Templates” and download a minimal Linux template.
Detailed Steps to Create a New LXC Container
a. Click on "Create CT":
b. Start the container creation wizard.
c. General Settings: <br>
- CT ID: Pick an available ID (e.g., 101).
- Hostname: Something cool like my-blog-builder.
- Password: Set a strong password (or set up SSH
keys later if you’re into that).
d. Template Selection:
- Choose the template you just downloaded (e.g., Alpine Linux
is used in our build).
e. Root Disk:
- Set a small disk size (e.g., 2–4 GB) to keep the footprint
minimal.
f. CPU & Memory:
- Allocate 1 CPU core and about 256–512 MB of RAM—more than
enough for content creation and running Hugo.
g. Network:
- Configure your network settings (DHCP is usually fine but I
recommend setting a reservation, or assign a static IP if needed).
h. Confirm & Create:
- Review the settings and click “Finish” to create the container.
Start and Access Your Container
a. Start the Container:
b. Select your new container and click “Start.”
c. Open the Console:
d. Use the built-in Proxmox console or SSH (if configured) to log in.
Log in to your container.
a. Use VSC with the 'Remote - SSH' plugin to connect to your container.
This allows you to edit files directly on the server.
Step 2: Installing Required Packages#
Once you’re logged in, update the package index and install the necessary packages. Run the following commands:
apk update
apk add nginx hugo git glibc
(Both git and glibc are optional, however installing them and not using them has minimal impact on this lean build.)
Note: Hugo Extended is required by many themes (including the Terminal theme used on this) to compile SCSS. Verify by running
hugo version
. Also, you might need to manually installhugo
if the version available in the repositories is older.If necessary, you can manually install the latest version by checking GitHub for the latest version
- If you installed from the repository and it is an older version, remove via:
apk del hugo
- Download the Latest Hugo Extended Binary: (v0.143.1 is the latest as of today, however you should update accordingly)
wget https://github.com/gohugoio/hugo/releases/download/v0.143.1/hugo_extended_0.143.1_Linux-64bit.tar.gz -O hugo.tar.gz
- Extract the Archive:
tar -zxvf hugo.tar.gz
- Move the Hugo Binary to Your PATH:
mv hugo /usr/local/bin/hugo chmod +x /usr/local/bin/hugo
- Verify the upgrade:
hugo version
Step 3: Configuring the Hugo Environment#
Set Up Your Hugo Site Directory#
Your site should have a structure similar to:
ClifFixIT-Reloaded/
├── archetypes/
├── content/
├── data/
├── layouts/
├── static/
├── themes/
└── config.toml
Edit config.toml
#
An example configuration might be:
baseurl = "" # Input your URL in quotes. e.g., "https://cliffixit.com/"
languageCode = "en-us"
theme = "terminal"
pagination.pagerSize = 5
[markup.goldmark.renderer]
unsafe = true
[params]
contentTypeName = "posts"
showMenuItems = 2
fullWidthTheme = false
centerTheme = true
[languages]
[languages.en]
title = "My Awesome Blog!" # Change the title to something appropriate
[languages.en.params]
subtitle = "A simple, retro theme for Hugo"
keywords = ""
readmore = "Read more"
readotherposts = "Read other posts"
[languages.en.params.logo]
logoText = "My Awesome Blog!"
logoHomeLink = "/"
[languages.en.menu]
[[languages.en.menu.main]]
identifier = "about"
name = "About Me"
url = "/about/"
Create a Sample Post#
Use Hugo’s archetype mechanism to create a new post:
hugo new posts/my-first-post.md
Then edit the file in VSC as desired.
Step 4: Automating Deployment with a Custom Script#
To streamline updating your site, I created a deployment script that:
- Clears out old build artifacts.
- Runs a Hugo build with the correct production baseURL.
- Copies the generated files to the Nginx document root.
- Reloads Nginx to serve the updated content.
Below is an example deploy.sh
script that I saved to the root of the blog site:
#!/bin/bash
# deploy.sh - Automate Hugo build and deployment
echo "Cleaning up old builds..."
rm -rf public/ resources/_gen/
echo "Building the site..."
hugo --minify --baseURL "https://cliffixit.com/"
if [ $? -ne 0 ]; then
echo "Hugo build failed. Aborting deployment."
exit 1
fi
NGINX_ROOT="/var/www/cliffixit"
echo "Deploying to Nginx root: ${NGINX_ROOT}"
rm -rf "${NGINX_ROOT:?}"/*
cp -r public/* "${NGINX_ROOT}/"
echo "Reloading Nginx..."
rc-service nginx reload
echo "Deployment complete!"
Save the script in your Hugo site root (e.g., deploy.sh
).
Make it executable:
chmod +x deploy.sh
Run the script to deploy your updates:
./deploy.sh
Step 5: Using Visual Studio Code for Remote Management#
I use Visual Studio Code with the Remote - SSH extension to edit files on the Alpine container directly. This setup allows for seamless editing of Markdown files, configuration files, and deployment scripts.
Useful Extensions:#
- Remote - SSH: Connects to your container.
- Markdown Preview: Provides a live preview of your Markdown content.
- GitLens (optional): For Git integration if you decide to track changes with Git.
Conclusion#
This deep dive showed the full process of setting up a self-hosted blogging solution:

- Alpine Linux container creation on Proxmox.
- Installing necessary packages via
apk
. - Configuring Hugo with a custom
config.toml
. - Automating deployment with a custom Bash script.
- Managing content via Visual Studio Code over SSH.
Although I initially experimented with DigitalOcean’s automated deployment, its inconsistencies led me to develop this custom, script-based workflow coupled with an Nginx reverse proxy. This setup gives me full control and reliability over my site’s updates.
Thank you for reading this guide. I hope it helps you set up your own self-hosted blog with confidence. Stay tuned for more deep dives and technical insights!