logo in Go

December 24, 2017 by Noah

As of a few minutes ago, I've swapped out the Python backend of with a new Go backend that I've been rewriting from scratch the past few months.

The Go codebase is a little rough around the edges and I'll be refactoring it over time. This is the first blog post on the new platform, so let me tell you about my open source Go blog!

Changes on & User Privacy

As well as the backend, I've also made some tweaks to my frontend to make my website more privacy-conscious:

No Google Ads or Analytics

I have removed all advertising from my site. My Google AdSense ads were only making me about $100 every 3 months or so, which wasn't really worth it.

I've also gotten rid of Google Analytics, because I never actually check those things. If I get curious in the future, I'll install a self-hosted analytics app.

No Storing IP Addresses

The new Blog code doesn't store IP addresses in any of its database files. I don't want to know your IP.

I'm taking my own advice from my recent blog post about storing IP addresses.

Good Old HTTP

I've always been a proponent of keeping web apps simple and accessible. I don't take it to the extreme of The Motherfucking Website, but I'm a believer that web apps should speak HTTP, send server-rendered HTML pages, have <form>s that actually POST, and not require the user to enable JavaScript to function.

An example of this is with the ACE Code Editor that I'm using in the Blog and Page Editor views: when the page loads by default, the CSS instructs it to render a plain old <textarea> with the page's contents. And then a JavaScript initializes ACE and toggles things around to enhance the experience, but the page is perfectly serviceable without scripts. The form POSTs to the back-end and gets an HTML response, none of that Single Page App, ajaxy stuff.

I'll write a dedicated post on this idea sometime later.

The New Blog

Quick Start

I've designed my Go Blog to be ridiculously easy to use. All you need is the binary, and you run it while giving it the path to your site's document root. The document root doesn't need to exist; it will be created as needed.

If you have a Go dev environment set up:

export GOPATH="${HOME}/go"
export PATH="${PATH}:${GOPATH}/bin"

go get -u
cd ~/go/src/  # enter the blog's source folder*
blog /path/to/document/root

# * The blog uses a dual template system where it checks your custom document
#   root first and then its built-in files. But the command's working directory
#   currently needs to be the Blog git root, where the "./root" folder is
#   available. This will be fixed shortly.

That's it! The blog uses a JSON database, which it will store in your ${document_root}/.private directory (HTTP requests for dotfiles are prohibited by the Go server), and the website configures itself. All you need to do is just point it to a folder and visit it in your web browser at localhost:8000 to set it up.

If you don't have a Go dev environment set up, wait a while and I'll post binary releases when the code is more polished.

See blog -help for other command line options, such as binding to a different port number or enabling debug logging.

Features vs. Rophako

Compared to my Python blog, Rophako, my Go blog is either less ambitious or more focused:

  • No photo albums (but Photo Blog support on the To-Do list)
    • My old /photos/* URIs will now 404 - oh well! I may bring them back another day.
  • No wiki support -- but there's a built-in page editor, so the entire website becomes the wiki!
    • The Rophako DB migrator program converts your Wiki pages into flat Markdown files at the /wiki/ directory.
  • Zero configuration
    • Just run the blog command and give it a Document Root directory to serve your custom web files from. This directory doesn't even have to exist!
    • No databases to worry about: the JSON DB is stored inside the Document Root.
    • The website securely configures itself by generating session secret keys automatically on first boot.
    • Use the web front-end to create the admin account and configure the website.
  • Dual template system
    • When the Blog wants to render a template, it checks your Document Root first (the directory you gave on the command line) for it before falling back on the Core Root, its cache of built-in files. The Core Root has all of the pages necessary for a complete blog with the default theme, but you may override pages to customize your site. For example, you can modify .layout.gohtml to change the overall web design layout.
  • Blog engine
    • Write posts in GitHub Flavored Markdown or HTML.
    • ACE Code Editor on the blog edit page: syntax highlighting and rich code editing features.
    • Post privacy options: Public, Draft, Private & Unlisted
    • Tagging and archive support
    • Blog posts have friendly URLs at the root of your site, like /blog-title-name
    • Every blog post may have comments on them unless you disable them on a per-post basis.
  • Comment engine
    • Users may leave comments in GitHub Flavored Markdown format.
    • Gravatar support if users leave their email address.
    • Users may subscribe to future comments on the same page, with support to unsubscribe from threads (links in the email) and globally unsubscribe from all threads through the privacy page.
  • Page editor

    • Admin UI to edit any pages, JavaScript or CSS files in your Document Root.
    • It lists the files available in your User Root as well as the Core Root (built-in files). If you click to edit a Core Root file and save it, it will be saved into your User Root -- thus overriding the core file. This way you can customize the website completely through the front-end! Be careful when editing .layout.gohtml, as a Go templating error might lock you out of the front-end completely! For that I'd recommend editing the template outside of the frontend.
    • Pages don't have comment forms by default, but you can add them with a Go template directive:

      {{ RenderComments "Subject Line" "unique-thread-name" }}

Things in Common

It shares a lot in common with Rophako:

  • JsonDB: pretty much an identical implementation, except I was able to use Mutexes for locking due to the fact that Go can be a single process handling all the requests whereas Python needed to be load balanced (and used a hacky Redis lock solution that I didn't want to implement in Go)
  • Pages may be in HTML or Markdown format. Templated pages need to be in .gohtml, otherwise the HTML page will be served as-is (without the .layout.gohtml wrapper). This is because Go templates are very fragile and you wouldn't want HTML pages that don't know they're templates to be unable to render!
  • Most of the same pages are in the same places.

Performance Comparison

Both Rophako and the new Go Blog support showing how long it took a page to render on the page itself.

Rophako consistently took about 0.103 seconds to load the home page with the five blog entries and such. Using the same data, the Go Blog was able to render the homepage in 0.0020 seconds. That Super Scientifically Measuredâ„¢ benchmark shows that Go runs circles around Python, but I already knew that.

The To-Do List

So, why'd I rewrite my blog in Go? It wasn't just for the fun of it. Go will let me do some more creative things with my blog in the future, like:

  • Goroutines let me run background tasks super easily in a way that's not easy in Python.
  • I could support my blog being able to syndicate RSS feeds of other blogs, and have a Goroutine keep track of refreshing it.
  • If you don't have Redis configured, I can implement an in-Go-memory cache instead to keep the JsonDB still performant without Redis. With Goroutines I can support auto-expiring cache keys!
  • I want to implement Go plugin support (Linux only) to inject custom routes at runtime. This way I can add custom routes specifically for and bring my TTF to EOT converter in to Go and stop running Perl scripts on my web server. :)
  • An RSS and/or Atom feed for the blog.


There is 1 comment on this page. Add yours.

Avatar image
Anonymous posted on December 25, 2017 @ 03:05 UTC

So responsive. I like it. Will you marry me?

Add a Comment

Used for your Gravatar and optional thread subscription. Privacy policy.
You may format your message using GitHub Flavored Markdown syntax.