After modifying the theme to fit my aesthetics, then adding a nice portfolio layout (which required writing and modifying a couple of plgugins), it was time to add a commenting system to my blog. Now, it’s not that I write a lot of blog posts, but for some projects I want to write some sort of how-to, or some sort of a thought process documentation - and for those, I really do wish for people to interact with me. Now, Minima already comes with a layout ready for adding Disqus comments. But I don’t really like relying on the free tier of a paid service, so I did a quick search and found Staticman, which is a self hosted solution. I think Staticman works in quite a clever way, using Jekyll’s own structure to save the comments as data files. Staticman’s back end is a self hosted endpoint which receives a POST request of the comment from a form displayed on each post. It then opens a Pull Request on the repository containing the blog with a new data file containing the comment - which in turn will be rendered with the related post when the site re-renders.
Staticman’s Github repository lists a couple of useful links for setting those up, which I followed. The first is Travis Downs’ tutorial, which is great, and the second is Michael Rose’s blog post documenting how he implemented Staticman in his own theme. I followed these two, adjusting as I went along to fit with my blog’s layout.
Required changes:

  • Include files comments.html, comment.html, and comment_form.html. If my memory serves me right, I copied these from Michael Rose’s blog post (MadeMistakes).
  • Rewrite JS to not require JQuery. That was done since that’s the only part in my site that uses JQuery, so that’s an unnecessary dependency. Since I don’t want this blog post to be entirely about that, I’ll just mention that I used the fetch API to send the comment to the Staticman endpoint, and you can find the code here.
  • Substitute colors in comment-styles.scss to work with Minima’s skins.
  • Add comments tag to _layouts/post.html as in adding the following to the bottom of the file:
  {%- if page.comments == true -%}
    {%- include comments.html -%}
  {%- endif -%}
  • Add the comments tag to the front matter of the posts I want to have comments on. I also found that using the Heroku deploy button does not work correctly with my browser, so I followed issue #394 on the Staticman repo. I used Heroku for the first deployment, but since the free tier is long gone, I did not use it for a good while. Since I recently got a VPS, I decided to deploy Staticman on it. I’ll document that process in the next section.

Deploying Staticman on a VPS

I looked online for resources on how to deploy Staticman on a VPS, using Dokku, and found this blog post. Reading through it, I decided I didn’t like the idea of setting up Node.JS and NPM, so I re-read the post and found there’s a link to another post, on another blog, that used the Docker image which Staticman ships with. So, I decided to document my own experience, to save myself the future headache of when I try to re-deploy it (which I know will happen sometime in the future, when I change VPS providers or something).
Here’s what I did:

  • Created a new app on my Dokku instance.
    dokku apps:create staticman
    
  • Set up a URL for the app.
    dokku domains:set staticman staticman-subdomain.domain.com
    
  • Set up letsencrypt for the app.
    dokku letsencrypt:set staticman email yourname@domain.com
    dokku letsencrypt:enable staticman
    
  • Create a GitHub token, from my existing bot account (I used the same account for the Heroku deployment).
    • Go to Settings -> Developer settings -> Personal access tokens -> Generate new token.
    • Select the ‘Tokens (classic)’ option.
    • Give the token a name, and select the repo scope.
    • Copy the token.
  • Create a RSA key pair for the app.
    • It’s important to use the -m PEM flag, since the default is OPENSSH.
      ssh-keygen -m PEM -t rsa -b 4096 -C "yourname@domain.com" -f ~/.ssh/staticman_rsa.pem 
      # copy the public key to the clipboard (pbcopy works on MacOS)
      cat ~/.ssh/staticman_rsa.pem.pub | pbcopy
      
  • Add the public key to the GitHub bot account.
    • Go to Settings -> SSH and GPG keys -> New SSH key.
    • Paste the public key.
    • Give the key a name.
    • Click Add SSH key.
  • Set up the required environment variables.
    • I scp‘d the private key to the Dokku instance from my local machine (scp ~/.ssh/staticman_rsa.pem user@ip:~) and then added it to the app.
      dokku config:set staticman RSA_PRIVATE_KEY="$(cat staticman_rsa.pem)"
      dokku config:set staticman GITHUB_TOKEN=your_github_token
      
  • Deploy the app (from my local machine).
    git clone https://github.com/eduardoboucas/staticman.git
    cd staticman
    git remote add dokku dokku@yourserver:staticman
    git push dokku master
    
  • Test the app exists.
    curl https://staticman-subdomain.domain.com:port
    # Should return 'Hello from Staticman version 3.0.0!'
    
  • Invite the bot to the repository.
    • Go to the repository settings.
    • Go to Manage access.
      • In my had to delete the bot’s access, since I had previously added it to the repository to work with Heroku.
      • Click Delete on the bot’s username.
    • Click Invite a collaborator.
    • Paste the bot’s username.
    • Click Add.
  • Accept the invitation using the Staicman app.
    curl https://staticman-subdomain.domain.com/v2/connect/github/your_github_username/your_repository_name
    # Should return 'OK'
    # If it returns 'Invitation not found' it might be that you've already accepted the invitation manually, or that your GITHUB_TOKEN is not right.
    
  • Add (or modify) the existing _config.yml file in the Jekyll blog to point to the correct Staticman endpoint.
    • I decided to stick to the v2 endpoint, since I was using it before. From what I understand, the v3 endpoint requires a GitHub app, which I did not want to set up at this point in time.
      staticman_url: https://staticman-subdomain.domain.com:port/v2/entry/your_github_username/your_repository_name/master/comments
      
  • Test the configuration.
    • Add a comment to a post.
    • If the comment does form does not seem to work, check the browser’s console for errors.
    • In my case, I noticed that in the ‘network’ tab, I got a ‘500’ error. I checked for possible causes until I remembered I had to set the ‘reCpatcha’ keys in the Staticman app correctly. Since I didn’t remember how I initially set them, a great help here was this blog post, which I mentioned earlier, and another post I stumbled upon when trying to figure things up.
  • Set up the reCaptcha keys.
    • Go to the reCaptcha admin console.
    • Register a new site.
    • Copy the site key to both the _config.yml file and the staticman.yml in the Jekyll blog.
    • Copy the secret key, and go to https://staticman-subdomain.domain.com/v2/encrypt/[recaptcha-secret-key] in your browser to get the encrypted key.
    • Copy the encrypted key to both the _config.yml file and the staticman.yml in the Jekyll blog.
  • Save and re-deploy the Jekyll blog.
  • Test the comment form again.
    • If the comment form does not work, check the browser’s console for errors.
    • If the comment form does work, check the repository for the new pull request.

I suppose that’s it. I really hope this post helps someone in the future, or at least helps me when I need to re-deploy Staticman. I’m really happy with how it turned out, and I’m looking forward to interacting with people on my blog. I’m also looking forward to writing more blog posts, and maybe even finishing some of the drafts I have lying around.