Skip to main content

How I Made This Site (This Time)

Someone on the Fediverse was curious how I made this site, since I mentioned using Emacs org-mode, and their own site is built using org-roam and Hugo.

It's not that much different from the more complicated process I was using before, on GitHub Pages. This one is simpler in one respect: I'm deploying directly to my own host, so I don't have to use the more complicated nikola deploy_github configuration, which requires separate source and deployment Git branches.

For reference, here's my original post on how to get Nikola and nikola.el working with GitHub Pages:

Publishing with Nikola in Emacs

This time, I'm going to take the reader through the setup, step-by-step.

Requirements

Here are the things you'll need for this tutorial. I'll show you some steps.

  • Emacs: Obviously. With Org Mode.
  • Git: Git and a private Git repository.
  • Nikola: Nikola is a static site generator, with an orgmode plugin.
  • nikola.el: nikola.el is an Emacs package that wraps Nikola functions.
  • Webserver: This setup assumes you have your own private webserver for deployment, but Nikola has a test server.

Install and Configure Nikola

From Nikola's installation instructions, slightly tweaked to use v8.2.4:

python3 -m venv nikola-env
cd nikola-env
bin/python -m pip install -U pip setuptools wheel
bin/python -m pip install 'Nikola[extras]==8.2.4'

You can now use Nikola by launching the script directly:

bin/nikola

Or you can activate the environment before working with Nikola and use the nikola command:

source bin/activate
nikola

Install Nikola add-ons

Now you need the Nikola orgmode plugin.

nikola plugin -i orgmode

And you need to install a Nikola theme. I chose the hack theme, but you can pick another.

nikola theme -i hack

Init Local Blog

Nikola sites require a particular directory and file structure, and it has a command to create that for us. Let's use that method, rather than more complicated options.

See Nikola's instructions, here. Here's what I recommend:

nikola init --demo <directory_name>
cd <directory_name>
git init

This creates the Blog structure, and also initializes the directory as a Git repository. You should continue and connect it to your Git repository, and push an initial commit.

The --demo option will fill in some blanks in your configuration file, and is recommended the first time.

Configure Nikola

Nikola settings live in the conf.py file that was created when you initialized your blog.

You can view the demo conf.py online, here.

Most of the settings are self-explanatory, and many of them have defaults. However, we do need to change a few things for our theme and the orgmode plugin.

Configure orgmode

At the bottom of conf.py, add the following:

# Add orgmode to compilers dict
COMPILERS["orgmode"] = [".org"]

# Add org files to posts and pages
POSTS = POSTS + (("posts/*.org", "posts", "post.tmpl"),)
PAGES = PAGES + (("stories/*.org", "stories", "story.tmpl"),)

This will allow you to write posts and pages for your blog in org-mode, with everything that comes with that.

Configure theme

Each theme may have particular settings to configure, but here are the ones for the "hack" theme.

Uncomment GLOBAL_CONTEXT, and set:

THEME = "hack"
# ...snip...
GLOBAL_CONTEXT = {}
GLOBAL_CONTEXT['HACK_VARIANT'] = 'dark'

I also have these additional settings:

DATE_FANCINESS = 2

# For Hack theme
NAVIGATION_LINKS = {
    DEFAULT_LANG: (
	('/index.html', 'Home'),
	('/archive.html', 'Archives'),
	('/categories/index.html', 'Tags'),
	('/stories/about-me', 'About Me'),
	('/rss.xml', 'RSS'),
    ),
}

Configure deployment

You will probably want to configure this after you've successfully built and deployed manually by your usual methods, so that you get the command right, but here's what mine looks like:

DEPLOY_COMMANDS = {
    'default': [
	"rsync -rav --delete output/ root@notroot:/var/www/blog.notroot.online",
    ]
}

I have my host notroot configured in my .ssh/config.

Install and Configure nikola.el

It's a bit outdated, and I can't get M-x nikola-deploy to work, but otherwise we want this.

Simplest thing is to use use-package. Here's my config:

;; Nikola.el config
(use-package nikola
  :config
  (setq nikola-output-root-directory "~/Dev/mine/notroot-blog/")
  (setq nikola-verbose t)
  (setq nikola-webserver-auto t)
  (setq nikola-new-post-extension "org")
  (setq nikola-new-page-extension "org"))

Then from inside your init.el buffer, do M-x load-file RET RET to install and configure nikola.el.

Write a Blog Post in Emacs

Now we can write a blog post, like this one, in Emacs org-mode. Super easy!

Just do M-x nikola-new-post to create a new posts, or M-x nikola-new-page to create a new page, like my "About Us" page.

Emacs will give you an *.org file, but will also create a *.meta file. Most things will be preset, but you will probably want to add tags. Here's the meta file for this blog post:

.. title: How I Made This Site (This Time)
.. slug: how-i-made-this-site-(this-time)
.. date: 2024-04-07 18:29:06
.. tags: nikola,emacs,org-mode,blogging,tutorial

And here's a screenshot of me writing this post! Talk about "meta" heheh:

nil

Preview and Build

You can also preview your work.

Do M-x nikola-webserver-start and navigate to the URL shown in the mini-buffer.

To see changes in the blog post, you will need to stop it with M-x nikola-webserver-stop, and restart it. Nikola does not rebuild on save.

Run M-x nikola-build. You can watch the progress in the *Nikola* buffer.

How Nikola Builds

One of the nice things about Nikola is that it builds using Emacs org-mode export to HTML directly, rather than translating to another markdown format, first. No pandoc is involved. No intermediary *.md files.

The benefit is obvious: the HTML will exported from your org files pretty much how you expect.

The one exception I've found is that inter-org file links like [[file:another-blog-post.org]] will be turned into <img> tags, not <a> tags, which is too bad. That's because the slugs Nikola uses don't match org-mode's own. I'm sure there's an elisp workaround, but I haven't played with it, yet.

Fortunately, this is org-mode! If you need to link from one blog post to another, just do something like:

#+begin_export html
<a href="/posts/publishing-with-nikola-in-emacs/">Publishing with Nikola in Emacs</a>
#+end_export

Deploy Your Blog

The nikola-deploy command is, unfortunately, not working for me. I have forked this old project, and at some point I'll try to fix it, but for now, I just use the shell command in Emacs.

Do M-! nikola deploy to upload your site to your webserver.

Then browse to your new blog. If everything is working, you should be live!

Conclusion

Once you get Nikola and nikola.el working, this is a very easy way to blog, if you're an Emacs person. It's intuitive and highly configurable.

For example, Nikola does it's own syntax highlighting, but I'll be adding something like highlight.js down the road. I can add comments sections, and I've barely touched the possible Nikola add-ons.

If you're an Emacs person, I think this is one of the more flexible, but robust, SSG integrations out there. I, too, love the idea of publishing natively using only Emacs, but one of the great features of Emacs is also its ability to compose cleanly with other commandline tools.

Comments

With an account on the Fediverse or Mastodon, you can respond to this post. Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one. Known non-private replies are displayed below.