Comments with Staticman
The biggest problem of the blog by far were the comments.
In theory Staticman is great. The users don’t have to register. You have complete control over the HTML of your comments. The comments will be automatically committed to your GitHub repository. Each comment in its own file. So you can easily manage them.
In practice though Eduardo Bouças (the original developer) stopped working on Staticman. Others took over, but Eduardo needs to review and confirm those changes before they can be merged. I saw PRs which were not reviewed in two years and then closed again because the contributor lost interest and was not willing to solve merge conflicts anymore.
So Staticman is not perfect, but it’s still the best option I found.
My information comes from different blog posts listed at the end of this article and some GitHub issues of Staticman. Apparently everybody who starts a new blog needs some content and describes their experiences. I won’t just repeat that here, but as there was no one blog post to rule them all I’ll describe the biggest problems here.
Concept
Staticman works like this:
- your app posts a new comment to Staticman
- Staticman authenticates with GitHub and either creates a PR or merges the comment to your repo right away
- when the comment has been merged, GitHub will re-create the HTML and the comment will be shown
Until 2018 there was one public Staticman instance which handled comments for all blogs. But as it became more popular, the public instance could not run in a free tier anymore and this stopped working. Now you need to host your own Staticman instance. This was something I wanted to prevent, but it looks like there is no other way anymore.
Many different services
Staticman is a Node.js app. They recommend to run it on Heroku.
You also need spam protection or your blog will be flooded with spam comments. So you also need to register for reCAPTCHA.
If you want email notifications - and who doesn’t? - then you also need an account at Mailgun.
These services are all free and configuration is straight forward. But still it’s something you have to do and what can go wrong.
Configuring Staticman
Lets start with Staticman. As I wrote above, there are some people working on it, but the PRs take ages until they are merged in - if at all. As I ran into a problem where a PR existed but was not merged I ended up forking eduardoboucas/staticman. You don’t have to do that, but if there is any trouble, it is better to be able to change the Staticman code yourself.
Either way, you need to run the Node.js app somewhere. Staticman recommends Heroku and that’s also what I used. Go to heroku.com and sign up for a free account. Then click this link to deploy a new application with Staticman as template. If you forked Staticman, you can connect Heroku to your github repo on the Deploy page.
Staticman needs a RSA key to encrypt/decrypt some values. Depending on your OS you can create a RSA key with either ssh-keygen
or openssl genrsa
. Don’t use a passphrase.
When you have that, then open the Settings page in your Heroku Dashboard and click Reveal Config Vars. Add the variable RSA_PRIVATE_KEY
and set the value to the private RSA key without newlines.
Keep that tab open, we will need to add more variables.
Unfortunately the Staticman docs are outdated and not very exhaustive. What took me a few days and much help from Vincent Tam is to set up the authentication between Staticman and GitHub.
The docs list three options how this can be done, but they don’t mention that you have to use option 1 with Staticman v3 and option 2 with v2. When v3 was created, they broke the githubToken authentication and it was never fixed. Option 3 is not recommended, but it should work with v2 too. V1 is deprecated and should not be used anymore.
Staticman version 3
Version 3 uses a GitHub App to authenticate. This has the advantage, that you can set strict permissions for what the App (and thus Staticman) can do.
Go to your account settings / Developer Settings on GitHub and create a New GitHub App. Most of the values can remain the default. You just have to change:
GitHub App Name | anything you want |
Homepage URL | the url of your web site |
Webhook URL | https://<heroku app name>.herokuapp.com/v1/webhook |
Permissions: Content | Read & Write |
Permissions: Pull Requests | Read & Write |
After the App was created first note the App Id at the top. Go back to your Heroku tab and add the var GITHUB_APP_ID
with the 6-digit App id from your GitHub App.
Back in your GitHub App settings scroll down and Generate a Private Key. This will download a .pem file. Open that file and copy its contents to the GITHUB_PRIVATE_KEY
config var in Heroku.
Then on GitHub select Install App in the navigation and install it to your GitHub Pages repository.
In your _config.yml you need to specify these values:
comments:
provider: "staticman_v2"
staticman:
endpoint: "https://<your heroku appname>.herokuapp.com/v3/entry/github/"
The API of versions 2 and 3 are very similar. So you can set the provider to "staticman_v2"
. The endpoint
matters.
Staticman version 2
Version 2 needed a GitHub account to perform the necessary actions. This can either be your own account (option 3) or some newly created account which you can create solely for Staticman comments (option 2). The former is not recommended because in this case Staticman can do everything in all your repositories.
This is explained pretty good on this blog and I won’t repeat it here. You don’t need to install the Heroku CLI. Just copy the personal access token of your new account and use the Heroku settings to add variable GITHUB_TOKEN
there.
In your _config.yml you need to specify these values:
comments:
provider : "staticman_v2"
staticman:
endpoint: "https://<your heroku appname>.herokuapp.com/v2/entry/"
Spam protection
Once your blog is found by google it is only a question of days until you’ll get your first spam comment. Akismet has a good description about spam comments.
reCAPTCHA
The easiest part to introduce is reCAPTCHA. It is a service by Google, built in in Minimal Mistakes and everybody knows it from tons of other sites.
Go ahead and register here. I did this in 2018 and registered for v2. TBH I don’t know if v3 or Enterprise also work. I didn’t try myself and couldn’t find anybody confirming that. However, after you registered you get a Site key and a Secret. The Secret must be encrypted.
Both have to be inserted in the staticman.yml
reCaptcha:
enabled: true
siteKey: "yourSitekey"
secret: "yourEncryptedSecret"
And if you use Minimal Mistakes they also need to go to _config.yml
reCaptcha:
siteKey : "yourSitekey"
secret : "yourEncryptedSecret"
Disable the submit button
Unfortunately reCAPTCHA alone is not enough. After a few days I got my first spam message.
I found this about spam protection. It basically changes the submit button to a normal button and disables it. Once the reCAPTCHA has been checked, it updates the submit button.
In comments.html add a data-callback attribute to the reCAPTCHA and disable the submit button:
<div class="form-group">
<div class="g-recaptcha"
data-sitekey="6LdTL28UAAAAAA5yKYsc7proZtMu-54BbhvPrwpN"
data-callback="verifyCaptcha"></div>
</div>
<div class="form-group">
<button type="button" disabled="disabled" id="comment-form-submit" ...
</div>
When the reCAPTCHA is checked, it executes the verifyCaptcha function. Add it to some .js file:
var verifyCaptcha = function(response) {
if(response.length == 0) {
} else {
var _el=$('#comment-form-submit');
_el.removeAttr("disabled");
_el.addClass('button-primary dark-blue-bg');
_el.attr('aria-disabled', 'false');
_el.attr('type', 'submit');
}
};
This changes the submit button back to what it should be.
I’ll see if I still get some spams. If Yes, then I have to look into Akismet too. This also does spam prevention, but as I understood it, it is still in preview in Staticman and does not really work. PRs fixing it have not been merged.
Akismet
As you might have guessed it was still not enough. It took a few days, but the spam comments came again.
Akismet is another spam prevention service. It is mainly for WordPress and it is the default there. First I read that it was not officially supported by Staticman, but when I tried, it worked at once. It is another external service though and of course it is one more moving part which could go wrong.
Akismet tries hard to get you to pay for their service. The free option is very good hidden. You have to sign up for the personal plan to “pay what you want” and then move the slider “What is Akismet worth to you?” to the left. But this is only for personal websites without ads or any other stuff which brings you some income. If you have those, you’ll need to pay.
Unfortunately you also need a wordpress.com account. Another site where you have to register.
On the Staticman side, configuring Akismet is very easy. You just need to uncomment the akismet section in your staticman.yml.
# Akismet spam detection.
akismet:
enabled: true
author: "name"
authorEmail: "email"
# authorUrl: "url" I don't use that
content: "message"
type: "comment"
Then in Heroku you need to define two Config Vars: AKISMET_API_KEY
and AKISMET_SITE
. The AKISMET_SITE
is the url of your blog - the one you entered when registering with Akismet. And the AKISMET_API_KEY
will be sent to you via email.
And that’s actually it. You can test if Akismet works by entereing the data described in the Akismet docs.
And the good news is: after activating Akismet, I really didn’t get any spam comments anymore.
Mailgun
Mailgun can be used to notify your users of new comments via email. By default Minimal Mistakes notifies everybody who commented on the same blog post. I changed that in order that you can send an answer to a previous comment and only those receive emails who answered to the same comment.
Registering for Mailgun is quite complicated, but their docs are very good. Just start here. You need to provide your credit card info, but they will not charge anything. One problem I had (and nobody documented) was that you can choose whether you want to create your mail domain in the US or EU. As I am from Austria I chose EU and that didn’t work. By default Staticman only works with the US domain and you can’t change the region later.
There has been a PR in 2019 which enabled you to configure the API URL, but it was not merged. Fortunately it was pretty easy to make those changes in my own fork so that I could configure the apiHost
in my staticman.yml file.
I now have these settings for Mailgun in my staticman.yml:
notifications:
# Enable notifications
enabled: true
# (!) ENCRYPTED
# Mailgun API key
apiKey: "yourEncryptedMailgunApiKey"
# (!) ENCRYPTED
# Mailgun domain (encrypted)
domain: "yourEncryptedMailgunDomain"
# By default staticman can only send to the US mailGun API.
# With the PR below, it can also use the EU domain.
# See https://github.com/eduardoboucas/staticman/pull/275/files
apiHost: "api.eu.mailgun.net"
# emails will be sent from this address
fromAddress: "Michaels Blog <noreply@mg.mrumpler.at>"
Threaded comments
I want to be able to reply to previous comments. By default, this is not possible in Minimal Mistakes. You can only send comments to the whole blog post. But Michael Rose did this for his own blog and Gabriel Luci built on that. Although that is quite a lot of manual work, their description is very good. So I won’t repeat it here.
Other changes
After I did that, my comments all had an id which I could link to. As I didn’t like the standard email Staticman sends I changed that in my Staticman fork in lib/Notification.js. But unfortunately that function did not get the id of the new comment, so I also had to provide that in lib/Staticman.js. My email notifications now don’t contain a strange greeting (“Dear human”) anymore. Instead they list the name of the person who sent the new comment, the message and a direct link to the new comment.
The id in the comments also has the advantage that you can delete some comments just by deleting the file. References to other comments will still be correct.
18 Comments