Using Commento with Hugo

An experiment with self-hosted comments

Although this site has never received much comment volume, there have been occasions where comments have been quite valuable. One popular solution for static sites is to use Disqus, which is a fully hosted comment system that many Hugo themes support right out of the box. Disqus is free, but you pay for it with lost privacy, third-party trackers, and bloat.

I’ve decided instead to use Commento. There’s a cheap hosted version of Commento, but why not try out the fully self-hosted version?

What follows are some notes on how I got Commento working and integrated with Hugo.

Setting up a dedicated database

Even though Commento is small, it requires a PostgreSQL database. That’s a bit of overkill for a small blog like this one, but considering a single Commento server could potentially handle dozens if not thousands of domains, it’s not an unreasonable choice.

I decided to use Docker to run a PostgreSQL database dedicated to this purpose. First, I installed postgresql-client and postgresql-common on my host, and took advantage of that creating a postgres user and group for me.

The initial startup looked like this:

docker run -e POSTGRES_PASSWORD=censored -it --rm -v commento-postgres:/var/lib/postgresql/data postgres
.. wait for the container to settle down ..

This created a docker volume called commento-postgres to hold the database and initialized a postgres user in the database engine.

I then changed the permissions on the data, where 113:120 is the user:group of my host’s postgres user:

docker run -it --rm -v commento-postgres:/var/lib/postgresql/data bash chown -R 113:120 /var/lib/postgresql/data

Commento wants TLS

I’ll save you a bit of trial-and-error here. It turns out Commento expects to connect to the database using TLS. It doesn’t care if the cert is self-signed or not, so I made one and stuffed it into my commento-postgres volume:

openssl req -x509 -newkey rsa:1024 -nodes -keyout key.pem -out cert.pem -days 3650

(Use docker volume inspect commento-postgres if you’re not sure where the volume is mounted.)

While I was there, I edited postgresql.conf to enable TLS:

ssl = on
ssl_cert_file = 'cert.pem'
ssl_key_file = 'key.pem'

Note that this database isn’t accessible over the Internet or even the LAN, thanks to iptables rules that aren’t shown here.

Starting the database

docker run -d \
    --restart=always \
    --name=commento-postgres \
    --user 113:120 \
    -p5432:5432/tcp \
    -v commento-postgres:/var/lib/postgresql/data \

Testing the connection and creating a commento database

# psql -h localhost -p 5432 -U postgres
Password for user postgres:
psql (10.6 (Ubuntu 10.6-0ubuntu0.18.04.1), server 11.2 (Debian 11.2-1.pgdg90+1))
WARNING: psql major version 10, server major version 11.
         Some psql features might not work.
SSL connection (protocol: TLSv1.2, cipher: ECDHE-RSA-AES256-GCM-SHA384, bits: 256, compression: off)
Type "help" for help.

postgres=# create database commento;

You can see above that the connection used TLS, which is good. I also created the database.

Starting commento

First, I created a system user and group for commento.

I went through a ton of trial-and-error here as well, and the details aren’t that interesting, so here is what I ended up with:

docker run -d \
    -p 8080:8080 \
    -e COMMENTO_POSTGRES=postgres://postgres:censored@docker_host_ip:5432/commento \
    -e \
    -e \
    -e COMMENTO_GOOGLE_KEY=censored \
    -e COMMENTO_GOOGLE_SECRET=censored \
    -e COMMENTO_TWITTER_KEY=censored \
    --dns=my_dns_server_ip \
    --user=122:122 \
    --name commento \
    --restart=always \

Some important notes:

  • I published a DNS record for COMMENTO_ORIGIN
  • I configured an NGINX reverse proxy to add TLS and expose Commento on port 443.
  • The first time running this, don’t set COMMENTO_FORBID_NEW_OWNERS. Register a user through the web portal, then restart it with new owners disabled.
  • To test SMTP, use the “forgot password” workflow, and docker logs commento to check for errors (and, obviously, look for the email.)
  • All of the SMTP parameters are necessary. If your SMTP relay doesn’t use SASL authentication, make sure it doesn’t offer it, and just use a bogus SMTP username and password. If your relay is Postfix, take a look at smtpd_sasl_exceptions_networks.
  • I highly recommend using a local SMTP relay to store and forward emails.
  • You can get OAuth keys from Google and Twitter pretty easily. The callbacks are /api/oauth/google/callback and /api/oauth/twitter/callback. Github and Gitlab are also supported using the same pattern.

Putting the pieces together

Create layouts/partials/commento.html:

<div id="commento"></div>
<script defer

Copy themes/<your-theme>/layouts/_default/single.html to layouts/_default/single.html and add {{ partial "commento.html" . }} right around where the Disqus comment code is.

What’s left to figure out?

  • How to automate database dumps for backups
  • Investigate ways to import old WordPress comments

I’ll come back and update this post as I make progress.

Enjoy some comment spam.

That’s roughly it. I’d like to thank oct8l for his helpful blog post on the same subject!

Feedback is welcome. Add a comment below!