How I Built a Hugo Website and Automated Publishing from Obsidian (With Plenty of “Oh Shit” Moments)
Let’s be real: setting up a Hugo website on Linux is supposed to be easy. But if you’re anything like me, “easy” usually means “I’ll screw up at least twice before it works.” And then, because I can’t leave well enough alone, I decided to automate publishing from Obsidian using a Go daemon. Here’s how it all went down—warts, wins, and warnings included.
Step 1: Setting Up Hugo on Linux (or, How I Learned to Stop Worrying and Love the Extended Version)
I started with the official Hugo Quick Start guide, thinking, “How hard can this be?” If you’re on Linux, here’s the first trap: there are three Hugo versions—
- Standard: No SCSS/SASS. Useless if your theme is even slightly fancy.
- Extended: SCSS/SASS support and Hugo Pipes. This is what you want.
- Extended/Deploy: Same as Extended, plus deploy commands for AWS/Google/Azure. I didn’t need this.
TL;DR: If you’re using a theme (and you probably are), just get Hugo Extended.
Prerequisites
You’ll need Git and Go:
git --version
go --version
sudo apt install golang-go
No need to install Dart Sass separately—Hugo Extended has it built in. (Ask me how long I spent Googling that before I realized.)
How I Screwed Up: The Full Hugo Install Fiasco
So here’s how it actually went down:
-
First try:
sudo apt install hugo
It installed! I was feeling smug—until I realized it was ancient. My theme broke instantly. Oh shit.
-
Second try:
“No problem,” I thought, “I’ll just grab the latest from the Hugo releases page.”
Downloaded the first Linux binary I saw, manually installed it, and…
Surprise! I’d just installed the Standard edition. Still no SCSS/SASS, still broken themes. Double oh shit. -
Third time’s the charm:
At this point, my system had both the apt version and the manually installed Standard edition floating around. I had to go through and clean up the mess:sudo apt remove hugo sudo rm /usr/bin/hugo
Then, finally, I did what I should have done from the start:
cd /tmp wget https://github.com/gohugoio/hugo/releases/download/v0.128.1/hugo_extended_0.128.1_Linux-64bit.tar.gz tar -xzf hugo_extended_0.128.1_Linux-64bit.tar.gz sudo mv hugo /usr/bin/ hugo version
If you see “extended” in the version output, you’re golden. If not, congrats, you get to do this dance again.
Step 2: Creating the Site and Picking a Theme (and Breaking It Immediately)
hugo new site quickstart
cd quickstart
git init
I browsed Hugo Themes and picked Hugo Book. Added it as a submodule:
git submodule add https://github.com/alex-shpak/hugo-book themes/hugo-book
echo "theme = 'hugo-book'" >> hugo.toml
Ran hugo server
and—oh shit, error. Turns out I’d installed the Standard version again. (Why is this so easy to mess up?) Downloaded the Extended binary, replaced it, and finally got the local server running.
Step 3: Adding Content (and Theme-Specific Headaches)
Created my first post:
hugo new content/posts/my-first-post.md
nano content/posts/my-first-post.md
Front matter was in YAML, but the docs showed TOML. My theme wanted draft: true
, not draft = true
. Nothing showed up until I figured that out. Oh shit, again.
Preview drafts with:
hugo server --buildDrafts
Step 4: Pushing to GitHub and Deploying (or, How to Break Netlify)
Moved my project, set up a GitHub repo, and pushed:
mv ./quickstart ./jacoblindqvist
sudo apt install gh
gh auth login
git add .
git commit -m "Initial Commit"
git branch -M main
git remote add origin https://github.com/yourusername/website.git
git push -u origin main
Chose Netlify for hosting. Imported the repo, set build command to hugo
, publish directory to public
. First deploy failed—Netlify couldn’t find Hugo. Oh shit.
Fixed it by adding a netlify.toml
:
[build]
publish = "public"
command = "hugo"
[build.environment]
HUGO_VERSION = "0.148.2"
Pushed again. Success!
Step 5: Changing Themes (Because Why Not Break Everything Again?)
Decided I wanted Lotusdocs instead. Removed the old theme, updated hugo.toml
:
[module]
[[module.imports]]
path = "github.com/colinwilson/lotusdocs"
disable = false
[[module.imports]]
path = "github.com/gohugoio/hugo-mod-bootstrap-scss/v5"
disable = false
Deleted old theme files, ran hugo server -D
, and—nothing. Forced a hard refresh in the browser (Ctrl+Shift+R). Boom, new theme.
git add .
git commit -m "Changed to lotusdocs theme"
git push
Should I be pushing to main all the time? Probably not. Do I care? Not right now. If it breaks, well, that’s tomorrow’s problem.
Step 6: Automating Publishing from Obsidian (aka, “Vibe Coding” a Go Daemon)
Now for the fun part. I wanted my website to have autosave: write in Obsidian, tag with #publish
, and the note appears on my site. Remove the tag, and it’s gone. No more copy-pasting, no more “oh shit, did I forget to update the docs?”
What Problems Does This Solve?
- Zero manual exporting: Obsidian is the source of truth.
- No broken links: Only published notes get converted.
- Safety net: Everything waits in a draft branch for review.
- Automatic clean-up: Unpublished notes and empty sections disappear.
Building the Daemon
I “vibe coded” this with AI help. The first version worked—sort of. Every note went to a pull request. Oops. Tweaked the prompt, fixed it. Then it copied the entire vault path into content/docs
. Oh shit. Fixed that too.
Warning: This is “vibe coded.” I haven’t done a deep code review. Use at your own risk, and back up your vault. Code’s here: https://github.com/jacoblindqvist/obsidian-hugo-sync.
Step 7: Running the Daemon as a Service (So I Can Forget About It)
I want this thing running in the background, starting with my computer. Here’s how I did it on Linux Mint:
Copy the binary:
sudo cp obsidian-hugo-sync /usr/bin/
Create the service file:
sudo nano /etc/systemd/system/obsidian-hugo-sync.service
Paste:
[Unit]
Description=Obsidian Hugo Sync
After=basic.target
[Service]
ExecStart=/usr/bin/obsidian-hugo-sync --vault /home/joakim/vault/vault --repo /home/joakim/jacoblindqvist/
Restart=always
User=joakim
[Install]
WantedBy=multi-user.target
Reload and start:
sudo systemctl daemon-reload
sudo systemctl enable obsidian-hugo-sync
sudo systemctl start obsidian-hugo-sync
Check status:
sudo systemctl status obsidian-hugo-sync
journalctl -u obsidian-hugo-sync -f
Final Thoughts (and a Final “Oh Shit”)
While writing this, I found a nasty bug—a race condition that deleted files instead of publishing or unpublishing them. Oh shit. Patched it, but let this be a warning: don’t trust this code blindly. Always back up your vault before experimenting.
I’ll keep updating the repo as I find and fix more bugs. Happy publishing—and remember, if you’re not breaking things, you’re probably not learning anything new.