obsidiangopher.png

Intro

I’ve been a user of obsidian for my notes for just a little while, but already I love its open source nature, it has so many cool plugins, and that the notes are just plain text/markdown… I hadn’t ever used markdown before but quickly fell in love with it.. Which got me thinking… I’ve wanted to make a blog/repository of development notes for a while, what if there was a way I could publish the markdown of some of my notes to a webpage! Turns I’m not as unique a thinker as I thought I was, and there are many tools to accomplish this sort of thing, so here’s what I went with.

  • Hugo generates static pages from markdown and has cool theming and other cool customization options, it also uses go and compiles the pages wicked fast.
  • Nginx with Let’s encrypt for https and reverse proxy, which I remember being a pain to set up before when I’d tried it in the past, but this time I found…
  • Docker images for nginx and let’s encrypt and Hugo, made setting it up super easy, and easy to deploy wherever.
  • Linode VPS made it cheap and easy to host, and set up the domain name
  • Obsidian-github-publisher plugin <- this…. I looked at like 10 different tools to try and find something that could do what this plugin does and was close to deciding I would have to do it either manually or code up some scripts myself, but then I found this. It lets you tag notes to share and it connects to your repository and coverts the obsidian note to normal markdown before merging it in wherever you choose. I set up a GitHub actions that auto pulls the changes to my server and ta-da, they show up on the deployed site.

Walkthrough

Make a new project folder, I called mine hugoblog. You will make two folders inside, one for your hugo project, and one for the nginx project. And don’t forget to git init.

Setting up Nginx with Docker

Lets start with nginx. Make a new docker-compose.yml in your nginx folder. Here’s what it looks like (courtesy of John):

 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
version: '3'
services:
  nginx-proxy:
    restart: always
    image: jwilder/nginx-proxy
    container_name: nginx-proxy
    security_opt:
      - 'label:type:docker_t'
    ports:
      - '80:80'
      - '2222:2222'
      - '443:443'
    volumes:
      - '/var/run/docker.sock:/tmp/docker.sock'
      - './certs:/etc/nginx/certs:ro'
      - './vhost:/etc/nginx/vhost.d'
      - './html:/usr/share/nginx/html'
      - './conf:/etc/nginx/conf.d'
    labels:
      com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy: 'true'
  letsencrypt-nginx-proxy-companion:
    restart: always
    image: 'jrcs/letsencrypt-nginx-proxy-companion:latest'
    depends_on:
      - nginx-proxy
    security_opt:
      - 'label:type:docker_t'
    environment:
      NGINX_PROXY_CONTAINER: nginx-proxy
    volumes:
      - '/var/run/docker.sock:/var/run/docker.sock:ro'
      - './certs:/etc/nginx/certs'
      - './vhost:/etc/nginx/vhost.d'
      - './html:/usr/share/nginx/html'
networks:
  default:
    external:
      name: nginx-proxy

That’s basically it for the nginx side of things. Before running the docker compose, we need to create the docker network:

1
2
docker network create nginx-proxy
docker-compose up -d

Before you commit anything, here’s what I have in my .gitignore, don’t want to upload anything unnecessary or secret…

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Generated files by hugo
/public/
/resources/_gen/
/assets/jsconfig.json
hugo_stats.json


# Executable may be added to repository
hugo.exe
hugo.darwin
hugo.linux

# Temporary lock file while building
/.hugo_build.lock

# Generated nginx files
nginx/certs
nginx/conf
nginx/html
nginx/vhost

# Generated hugo files
blog/output

Setting up Hugo with Docker

Now that that’s good to go, we can start the hugo site. First clone this repo to the root of your project and rename it to whatever (in my case /blog):

1
git clone https://github.com/jojomi/docker-hugo.git blog

This docker image is hosted as jojomi/hugo:latest but the repo is a year ahead of what is hosted, so I strongly recommend cloning and building the docker image yourself.

I also went ahead and deleted the .git folder that was created when I cloned, so I don’t have nested git repositories in my main project.

Add a new docker-compose.yml:

 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
version: '3.9'
services:
  hugo:
    container_name: hugo
    build: . #build the docker image we cloned
    image: 'hugo:latest'
    volumes:
      - './src:/src' # map your main hugo project site folder here
      - './output/:/output'
    networks:
      nginx-proxy:
    environment:
      - HUGO_APPEND_PORT=false #True if you want to test locally, but if you deploy with this set to true, it will append the port to all links on the site. This variable isn't currently available in the old cloud hosted image fyi.
      - HUGO_REFRESH_TIME=3600
      - HUGO_THEME=PaperMod
      - HUGO_WATCH=1
      - HUGO_BASEURL=<https://example.com/>
      - VIRTUAL_NETWORK=nginx-proxy # network proxy we created earlier
      - VIRTUAL_PROTO=http
      - VIRTUAL_HOST=<example.com>
      - VIRTUAL_PORT=1313
      - LETSENCRYPT_HOST=<example.com>
      - LETSENCRYPT_EMAIL=<email>
    ports:
      - '1313:1313'
    expose:
      - 80
    restart: always
networks:
  nginx-proxy:
    external:
      name: nginx-proxy

Make sure to replace whatever is in the <> with your own stuff. Also in the dockerfile from the cloned repo, update your version of Hugo:

1
ENV HUGO_VERSION=0.95.0

The last thing we need to do is actually make a new Hugo project. From within the /blog run this (you will need Hugo installed):

1
hugo new site src -f yml

I will setup PaperMod as my theme, but they all usually install in a similar way.

1
2
cd src
git submodule add --depth=1 https://github.com/adityatelange/hugo-PaperMod.git themes/PaperMod

When you first clone the repo somewhere else, you may also need to run this to fetch the submodules on the new machine.

1
git submodule update --init --recursive

When you add a theme you have to set the name of the theme in the docker-compose and add this in your config.yml. Here’s the sample config PaperMod provides.

1
theme: PaperMod

You should now be able to run docker-compose up -d from within the blog folder and it should get your site up and running locally, it should also go and grab your Let’s Encrypt Certificate.

Auto deploy with GitHub Actions

Someone already wrote a thorough blog post for setting up just what we need here. Just set up the secrets and the workflow file and then come back!

So now if you push to your repo, it should get copied onto your server that you set up in the Actions. From there you can ssh into your server and run docker-compose up -d in both the nginx folder and the blog folder. (Don’t forget to also fetch the git submodules for the theme or nothing will show up). Whenever the repo is updated by the actions, the docker container will watch for changes and update your site live without having to restart!

Obsidian GitHub Plugin

Now the fun part! You just set up this plugin with your obsidian notes: Obsidian-github-publisher. Just put in the repository, give it your username and token, tell it where to put the shared files in your repo, and basically any note that has shared: true in the frontmatter of a note will be pushed and merged to GitHub, then deployed to the server with the Action, and then show up on the site. wow If you also have the templater plugin for obsidian, you can use my template that inserts the frontmatter into any note with the default values (lots of these come from PaperMod), so it’s super easy to make a new post:

 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
---
share: false #change this to true to publish to the site
draft: false
title: <% tp.file.title %> #templater auto fills the title and the date
date: <% tp.file.creation_date("YYYY-MM-DD") %>
author: "Caleb Wightman"
description:
tags: []
hidemeta: false
comments: false
#canonicalURL: "https://canonical.url/to/page"
disableShare: false
disableHLJS: false
hideSummary: false
searchHidden: false
ShowReadingTime: true
ShowBreadCrumbs: true
ShowPostNavLinks: true
ShowWordCount: true
ShowRssButtonInSectionTermList: true
UseHugoToc: true
ShowToc: false
TocOpen: false
#cover:
  #image: "<image path/url>"
  # can also paste direct link from external site
  # ex. https://i.ibb.co/K0HVPBd/paper-mod-profilemode.png
  #alt: <% tp.file.title %>
  #caption: ""
  #relative: false # To use relative path for cover image, used in hugo Page-bundles
#editPost:
    #URL: "https://github.com/<path_to_repo>/content"
    #Text: "Suggest Changes" # edit text
    #appendFilePath: true # to append file path to Edit link%%
---

Potential Pitfalls

Here’s some frustrating things that took me too long than they should have to figure out, hopefully this saves you some time.

Hugo Docker Image

Like I said, I recommend building the image from the repo yourself, it hasn’t been updated on the site for over a year. If you use the one from the cloud it won’t have the environmental variable to turn off appending 1313 to the base URL of all your links. It will also have an old version of Hugo.

Configuring the plugin / Images not showing up

Hugo wants you to put images into it’s static folder, but then it serves them at the root of the site example.com/img.jpg instead of at example.com/static/img.jpg. If you set up the obsidian plugin to upload your images and convert the links of your markdown, it will link to /static where it won’t be found at runtime. You can fix this by putting this in your Hugo config:

1
2
3
4
module:
  mounts:
  - source: static
    target: static/static

This will nest another static path so the images are now found at example.com/static/img.jpg like the obsidian plugin expects.

You also have to enable some settings in the plugin to translate the obsidian links correctly. Here is how I configured the plugin:

 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
{
  "githubRepo": "<redacted>",
  "githubName": "<redacted>",
  "GhToken": "<redacted>",
  "githubBranch": "main",
  "shareKey": "share",
  "excludedFolder": [],
  "fileMenu": true,
  "editorMenu": true,
  "downloadedFolder": "yaml",
  "folderDefaultName": "blog/src/content/posts",
  "yamlFolderKey": "category",
  "rootFolder": "blog/src/content",
  "workflowName": "",
  "embedImage": true,
  "defaultImageFolder": "blog/src/static", //Sends images to the static folder
  "autoCleanUp": false,
  "autoCleanUpExcluded": [],
  "folderNote": false,
  "convertWikiLinks": true, //Convert the links
  "convertForGithub": true, //Add relative pathing to the links
  "subFolder": "",
  "embedNotes": false,
  "copyLink": false,
  "mainLink": "",
  "linkRemover": "",
  "hardBreak": false,
  "logNotice": false,
  "convertDataview": true,
  "useFrontmatterTitle": true,
  "censorText": [],
  "inlineTags": true, //Converts the obsidian tags into frontmatter tags for hugo
  "dataviewFields": [],
  "excludeDataviewValue": [],
  "metadataFileFields": [],
  "frontmatterTitleKey": "title",
  "shareExternalModified": false,
  "automaticallyMergePR": true,
  "metadataExtractorPath": "",
  "convertInternalNonShared": false,
  "frontmatterTitleRegex": "/[^a-zA-Z0-9]/g", // adds dashes to files with spaces in name
  "frontmatterTitleReplacement": "-", //ditto
  "ExcludedFolder": []
}

Themes/ Git Submodule

I had never used submodules before and was trying out a few themes:

  • Try not to move your .gitsubmodule file or it messes up the repository, I just keep mine in the root of the project.
  • Don’t forget to get the submodule for the theme when you first clone the repo to your host.
  • Themes look like normal Hugo projects, that’s normal, they still just nest inside your projects theme folder, but you can usually copy the themes config file as a starting point for the config inside of your Hugo project (src).
  • I tried the theme PaperModX and it broke images from showing up, not even the links would show up, and I couldn’t figure it out so I went back to normal PaperMod. I have no idea what caused it.

Obsidian Plugin

  • The first time I tried using the plugin nothing was happening, (remember to turn it on, plugins are off by default when you install them), Ctrl + shift + I and then the network tab showed lots of the requests to GitHub didn’t have the configured parameters I had entered in my plugin settings, I had to reboot the program after I changed plugin settings occasionally to get it to work.

Helpful Resources

Thanks for reading!