NOTE: The easiest way to publish your vault online is by using
Obsidian Publish. I put a bunch of time into figuring out how all of this would work together, and I probably could have saved a bunch of time by just using Obsidian Publish. Either way, I’ve learned a ton in setting this up. I also have more control on what does and doesn’t get published. I have a ton of private content in my vault and I do not want that being published, which is why I went to all this trouble you’re about to see. Yes, I could use multiple vaults, but that seems annoying when you want to link to something that resides in another vault.
So you’re thinking about publishing your
Obsidian Vault online, but you’re not sure if you want to pay for Obsidian Publish or not. I’ve been there, that was the exact same situation I was in when I considered publishing my vault. Call me cheap, but I wasn’t sure if I was ready to pay $20 a month for the rest of time. Would I keep writing meaningful content, would people actually ready it? So instead, I decided I was going to figure out a way to publish my vault without the monthly fee. I now publish my vault online, and I don’t pay anything for hosting. (You are currently reading this article from the digital vault that I publish through this method)
A nice, clean-looking template for your digital garden that sits on top of Hugo. Once you get your bearings with it, you will find that it is just a Hugo site and you can customize it a ton if you would like.
A Rust based library for converting your Obsidian Vault to standards compliant Markdown that supports translating Obsidian style links to standard links that are compatible with Hugo.
Quartz and Hugo both assume that all of your files have a title attribute in their frontmatter. Unfortunately, most of my files do not have this title front matter. I have a branch of obsidian-export (linked above) that uses the file’s name to generate titles when that frontmatter is not present.
Quartz has an easy setup that allows you to commit all of your content to Github and it will compile everything via Github Actions. This is fantastic and super helpful. The issue is I have private content that I don’t want on Github.
So instead I use the obsidian-hugo library that Quartz’s Github Action uses just I use it on my local machine and precompile the filtered content before uploading to Github. This enables me to host my Digital Garden on Github (for free) without risking private content accidentally leaking out onto the internet.
This is where I publish the content that gets output. It’s all static html and is being served by Github. There is no amount of traffic I could ever manage to generate that Github couldn’t handle.
obsidian-export does a very good job of filtering out files and folders you don’t want exported
it makes me confident that there is no chance that private data gets uploaded by not even allowing that data to be in the folder that gets parsed
It handles bad or no frontmatter so that the downstream pipeline doesn’t have any issues
You can avoid a bunch of hacks to Quartz (and your layout files) by ensuring that your files have title attributes in their frontmatter. I have hacked together a fork of obsidian-export that does this automatically based on the file name when exporting.
https://github.com/brandonkboswell/obsidian-export/tree/title_frontmatter
Install Hugo for minifying and running a local server
brew install hugo
Clone obsidian-export wherever you keep libraries
Obsidian Export runs in Rust, so make sure you have Rust enabled on your machine
If I remember correctly, I ran cargo build from the obsidian-export directory to build a local binary that can be called in the compile script
Clone obsidian-hugo wherever you keep libraries
Obsidian-hugo runs in Go, so make sure you have Go enabled on your machine and in your PATH;
The watch/compile script will run go run ~/Sites/hugo-obsidian -input=/Users/brandonkboswell/Sites/quartz/content -output=/Users/brandonkboswell/Sites/quartz/assets/indices -index -root=/Users/brandonkboswell/Sites/quartz; when it compiles.
Update the compile and watch scripts for the paths of your folders
My quartz directory is at: ~/Sites/quartz
My Obsidian Vault is at (My iCloud Folder): ~/Library/Mobile\ Documents/iCloud~md~obsidian/Documents/bkb
My hugo-obsidian directory is at: ~/Sites/hugo-obsidian
Configure your configuration files
Hugo Config — quartz/config.toml file
Quartz Config — data/config.yaml
Quartz Graph Config — data/graphConfig.yaml
Add a file name .export-ignore to your Obsidian Vault
Obsidian Export will skip any files / folders you mention here and make sure they don’t get handed to Quartz
You can’t create this file in Obsidian (you likely want to use the finder or a Code Editor).
A sample of my .export-ignore file is further down in this article
Run the watch script (which will do an initial compile and then watch for changes to your Obsidian Vault)
Note that the compile script empties out your quartz/content directory so that files that may have been moved or deleted from your Obsidian Vault do not end up being pushed to the public internet. Make sure that this path is set correctly before running the watch or compile script.
Start a hugo server from your quartz directory
./serve.sh
Assuming everything worked, you should be able to preview your vault at: localhost:1313
Tinker / tweak for way too long
When you’re ready you can commit your quartz/public directory to Github pages
Verify (especially for the first commit) that there is nothing private that you don’t want uploaded to the internet.
Sometimes the server will crash while the compile script is rebuilding everything. If you wrap the hugo server code in a while loop then it will restart itself if this happens. For this I will have two terminal panes open on for the watch script and one for the hugo server. As I make changes to my Obsidian Vault or the Quartz files it will recompile the content and then hugo will recompile, at which point you can refresh your browser to see the change. Usually that will be at localhost:1313.
1
2
3
(while true;do hugo server --disableFastRender
done)&
You probably want to do your ignoring of personal files at the obsidian-export level because if a file is referenced in another file, but that file is flagged as a draft in the frontmatter then hugo-obsidian will have trouble with that and make hugo error on compile with the backlinks. Doing your ignoring of specific files in obsidian-export takes care of this.
If you’ve never used Hugo before (like I hadn’t prior to this project), you may not know that Hugo has a static folder that generates assets you want to be in any subsequent rebuilds. When I first started this project I added a bunch of lines to the compile script to create files and moving files around when all I really needed to do was add those files to my static folder.
Originally I modified hugo-obsidian to get around the no titles issue, since I now do this in obsidian-export I no longer need to maintain a fork of that code. If it’s useful to you, here is the change I made:
I had to make a minor modification to obsidian-hugo because it assumes that all of your files have a title attribute in their frontmatter. Unfortunately, most of my files do not have this title front matter. I have a branch of obsidian-hugo that uses the file’s name to generate titles if that frontmatter is not present.
https://github.com/brandonkboswell/hugo-obsidian/tree/without_titles.
As the time of this writing, that branch has not been merged into the main repo, but it may have by the time you’re reading this.