============
== adstew ==
============
chronically online

Diving Into the Indieweb

indieweb

The web used to be fun. I remember spending countless hours on internet forums, interacting with the various homegrown cultures and communities cultivated there. My favorite part of the “old web” was that you didn’t have to log on every day in order to keep up. All the forum threads and blog posts would still be there, easily accessible in reverse-chronological order, for you to catch up on at your convenience. The centralization of all web content has turned it increasingly ephemeral, incentivizing users to be always online for the fear of missing out. I no longer want a part in it, but I still want to be able to interact with other interesting people on the web. This is where IndieWeb comes into play: a set of web technologies to enable social features across the entire Internet, putting you back in control of your content, while also separating the posting of content from the consumption of content. This is how I created my web site and became a citizen of the IndieWeb.

This site is powered by Hugo, a static site generator written in Go. I went with a static site generator over something like WordPress because static sites are fast and I can maintain my content with files, instead of messing around with a database. Which means I can manage the files with git and edit my posts in vim! A programmer’s dream. I went with Hugo simply because I’ve used it before and I like the CLI. I’m using the smol theme, which is perfect for my vision of how the web should be: all black text on white background (or vice versa). To get it online, I provisioned a virtual machine on DigitalOcean (they like to call them droplets) for $5/month, and set up Apache on it. They have a great tutorial on how to do that. Next was setting up HTTPS, for which there is also a great tutorial. Once that was done all I had to do was copy the public directory generated by Hugo to the appropriate Apache directory.

My resulting publishing workflow looks like this:

  1. Write post on my personal PC
  2. Push changes to GitHub
  3. Pull changes on cloud VM
  4. Generate the site
  5. Copy the public directory

This process is currently manual but I took care to set up the process such that I can automate this all once I find the time.

After getting my web site published, the next step was adding all the fun IndieWeb stuff. I’m certainly not an expert on how all these technologies work yet, but that’s part of the fun. This post is part tutorial and part documentation for myself. I’d like to give a special thank you to the authors of the following posts, which helped me figure out how to get this all working with Hugo. These posts all cover this more in-depth than I could, so check them out for further details.

Links:

IndieWeb Groundwork

This is all fairly simple, it just requires modifying your Hugo templates, which took me about an hour. First I enabled IndieAuth, a way to authenticate through your website. This enables signing into the IndieWeb wiki and some services I set up later. This is achieved by including links to some of your other profiles that include a rel="me" tag, like so. Unfortunately, Twitter has changed so IndieAuth won’t work anymore, so I used GitHub instead.

<a rel="me" href="https://github.com/stewartad"><b>GitHub</b></a>.

I used Hugo’s menus feature for my profile links so I could modify them and add new ones in the future by editing the config.toml file, rather than hardcoding them into my template.

config.toml

[menu]
...
# Footer
# Use menu.footer for regular footer links, menu.me for rel="me" links
  [[menu.me]]
    name = "Twitter"
    url = "https://twitter.com/_adstew"
    weight = 1

  [[menu.me]]
    name = "GitHub"
    url = "https://github.com/stewartad"
    weight = 2

partials/footer.html

{{- range .Site.Menus.me }}
  <a rel="me" href="{{ .URL }}"><b>{{ .Name }}</b></a>.
{{- end}}
{{- range .Site.Menus.footer }}
  <a href="{{ .URL }}"><b>{{ .Name }}</b></a>.
{{- end }}

Then I added an authorization endpoint to the <head> of my theme

<link rel="authorization_endpoint" href="https://indieauth.com/auth">

And done! IndieAuth is enabled. If you’re following along, you can check that it works using indiewebify.me.

Next is creating an h-card, which is just a way of marking up your profile information so that other software can parse it. You can read more about it on the microformats2 wiki. I put mine in a partial so that I could reuse it, then included it in my main template.

partials/h-card.html

<p class="footer-divider">---</p>
<p class="h-card vcard">
        <a style="text-decoration: none" href={{ .Site.BaseURL }} class="p-name u-url url author metatag" rel="me"> {{ .Site.Author.name }} </a> /
        <a class="p-nickname u-email email metatag" rel="me" href="mailto:{{ .Site.Author.email }}">{{ .Site.Author.nick }}</a> /
        <span class="p-note">Software developer. I like games and toy robots. Currently obsessed with #fabtcg</span>
	<img class="u-photo" src="/images/me.jpg" alt="me" />
</p>

_default/baseof.html

...
<body>
	{{ partial "header" . }}
	{{ block "main" . }}{{ end }}
	{{ partial "h-card" . }}
	{{ partial "footer" . }}
</body>
...

That was easy enough. Finally I needed to add some tags to my content to make it parseable as well. This is done through another microformat, h-entry. I wanted my site to differentiate between long-form posts (like this one) and short-form notes, essentially tweets. To do this, I created a directory for each in my content directory. Hugo will then consider them different kinds of post, so then I just needed to modify my templates to reflect the differences, using partials.

_default/single.html

{{ define "main" }}

{{ if or (eq .Section "posts") (eq .Section "") }}
<main>
	{{ partial "post.html" . }}
</main>
{{else}}
<main>
	{{ partial "note.html" . }}
</main>
{{end}}
{{ partial "sidebar.html" . }}
{{ end }}

partials/post.html

<article class="h-entry">
    <h1 class="p-name">{{ .Title }}</h1>
    <b><a class="u-url" href="{{ .Permalink }}"><time class="dt-published">{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" }}</time></a></b>
    <a style="text-decoration:none;color:black;" href="{{ .Site.BaseURL }}" rel="author" class="p-author h-card"><img style="display:inline" class="u-photo" src="/images/me.jpg" width="10px" height="10px" />{{ .Site.Author.nick }}</a>
    {{ range .Params.tags }}
         <a class="p-category" href="{{ "/tags/" | relLangURL }}{{ . | urlize }}">{{ . }}</a>
    {{ end }}
    <div class="e-content">
        {{ .Content }}
    </div>i
    {{ with .Params.syndication }}
        {{ range . }}
            <a href="{{ . }}" class="u-syndication"></a>
        {{ end }}
    {{ end }}
</article>

partials/note.html

<article class="h-entry">
    <b><a class="u-url" href="{{ .Permalink }}"><time class="dt-published">{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" }}</time></a></b>
    <a style="text-decoration:none;color:black;" href="{{ .Site.BaseURL }}" rel="author" class="p-author h-card"><img style="display:inline" class="u-photo" src="/images/me.jpg" width="10px" height="10px" />{{ .Site.Author.nick }}</a>
    <div class="e-content">
        {{ .Content }}
    </div>
    {{ with .Params.syndication }}
        {{ range . }}
            <a href="{{ . }}" class="u-syndication"></a>
        {{ end }}
    {{ end }}
</article>

Posts have more metadata associated with them, so that template has a little more going on. For notes I wanted only the publication date and the content itself.

Connecting with the rest of the IndieWeb

The most interesting part of the IndieWeb to me is the webmention standard. Think of Twitter @ mentions but across the entire web. You can notify a website that you have linked to it by sending a webmention, and other websites can do the same to you. They can even be displayed on your website to show comments, likes, etc. on your posts, similar to traditional social media. There are two parts to implementing webmentions, sending them and receiving them. Sending them automatically is a little difficult for my static website, since there isn’t any software running on the server, just files. Luckily you can send webmentions manually, which is what I will do for now until I can automate it. Receiving webmentions is easier since it can be offloaded to a 3rd party service. I’m using the excellent webmention.io. Just sign in with IndieAuth, get the endpoint URL, put it into your site’s <head>, and you’re good to go. You’ll be able to see all your webmentions on webmention.io itself or you can add a way to display them on your site. For the latter I’m using webmention.js, which is quite simple to set up following the documentation.

Now that I can receive webmentions, I could set up Bridgy to syndicate my content to Twitter and display responses back on my website. In my post and note templates, you may have noticed a section for syndication. This allows me to implement POSSE by placing links to syndicated copies of my content in the front matter of each post, and lets Bridgy notify me of replies on external websites via webmention. Currently syndicating is a manual process, but since all of the front matter is formatted in yaml, I will be able to automate it later.

That is how I spent a weekend setting up an IndieWeb site. My next steps are to automate all the manual parts of the process and add more robust support for webmentions, likely with my own implementation.

Till next time.

Austen Stewart / adstew / Software developer. I like games and toy robots. Currently obsessed with #fabtcg me