Altoplace

Add Comments to Your Hugo Site with Remark42

Tags:
Update key on a keyboard.
Image by Tumisu from Pixabay

After I moved from WordPress to Hugo, I was missing a commenting system. Actually, I never did receive that many comments when using WordPress, but I still want to give folks the ability to leave comments. I was looking for a simple, self-hosted solution that would work with my VPS. My VPS provider does not permit root access, so that was an additional restriction. My VPS does support using a “rootless” version of Docker, and I learned that Remark42 will work with it.

This post describes how to set up a self-hosted Remark42 commenting system, using Docker, on a Hugo website. My Hugo website and the Remark42 system runs on my Vultr self-managed host. I also include notes about how to use Docker. This was a big learning curve for me, so I am hoping that this post might help others.

Note

I have been experimenting with the Remark42 and Comentario commenting systems; I am currently using Remark42. I also wrote a post about how to use Comentario.

Privacy-focused Lightweight Commenting Engine

In a nut shell, that describes Remark42. You can go to their excellent website to see a list of features. Their system is well documented. I am going to hit on the highlights about what I did to integrate their system with my Hugo website. You can also read about how they value privacy. Their system supports various ways to login and leave a comment. You can configure various social logins such as Google and GitHub. You can login via an email address (which is not displayed). And there is even optional anonymous access. I chose to use Google, GitHub, and email access. I do not allow anonymous access; I was afraid that method would create a lot of spam comments.

They also have an active support community that quickly answered my question about Remark42 working in a Docker environment. I am also using a reverse proxy.

Set Up Your Environment

You need to ensure that docker and docker-compose is working on your host. There are many excellent Docker tutorials on the net, so I will not cover the details of installing and using it. You can refer to the Docker Docs to get started. After Docker is installed, you can run docker run hello-world to verify your installation.

Next, you need to configure a subdomain, such as remark42.example.com, to host your commenting system. I enabled “https” and a reverse proxy on my remark42 subdomain. The reverse proxy maps to http://localhost:8080.

Install the Remark42 Docker Image

You are going to use docker compose to install and manage your Remark42 commenting system (don’t use docker-compose). Do the following to verify that docker compose is installed and working:

$ docker compose version
Docker Compose version v2.29.1
Note

On my host, Docker is running in rootless mode, because my VPS provider does not allow root access.

Next, in my remark42 subdomain root, I created a docker-compose.yml file that defines my Remark42 Docker configuration. The Remark42 GitHub repository provides an example docker-compose.yml file that you can customize to your needs. Here’s what my docker-compose.yml looks like:

---
name: remark42
services:
  remark42:
    image: ghcr.io/umputun/remark42:latest
    container_name: "remark42"
    hostname: "remark42"
    restart: always

    ports:
      - "127.0.0.1:8080:8080"

    environment:
      - REMARK_URL=https://remark42.example.com
      - SITE=example
      - ALLOWED_HOSTS=example.com, stage.example.com
      - DEBUG=false
      - SECRET=a-long-random-string
      - STORE_BOLT_PATH=/srv/var/db
      - BACKUP_PATH=/srv/var/backup
      - EMOJI=true
      - AUTH_ANON=false
      - AUTH_GITHUB_CID=your-github-cid
      - AUTH_GITHUB_CSEC=your-github-secret
      - AUTH_GOOGLE_CID=your-google-cid
      - AUTH_GOOGLE_CSEC=your-google-secret
      - SMTP_HOST=mail.your-smtp-server.com
      - SMTP_PORT=465
      - SMTP_TLS=true
      - SMTP_USERNAME=smtp-user@example.com
      - SMTP_PASSWORD=smtp-password
      - AUTH_EMAIL_FROM=your-auth-user@example.com
      - NOTIFY_USERS=email
      - NOTIFY_ADMINS=email
      - AUTH_EMAIL_ENABLE=true
      - NOTIFY_EMAIL_FROM=your-notify-user@example.com
      - ADMIN_SHARED_EMAIL=your-admin-user@example.net
      - ADMIN_SHARED_ID=your-admin-shared-id (See notes below)

    volumes:
      - data:/srv/var

    networks:
      - proxy

    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "5"

volumes:
  data:

networks:
  proxy:

You can read about the interface parameters at the Remark42 site. They show the minimal docker-compose.yml file with all the required parameters. I have added a few additional ones for my application. The networks section creates a named internal Docker network; otherwise, Docker creates a long default network name. The volumes section is more important, especially if your Docker system is running in a rootless mode. I am creating a named volume to store comment data instead of a bind mount as shown in the Docker minimal configuration.

Docker creates volume data under docker ownership. I discovered this when I was experimenting with Remark42, using the example configuration file. I could not delete the example volume bind-mounted data because I did not have root access. I had to contact support and ask them to delete the data for me. When using the named volume mode, you can use docker compose commands to manage the volume data, including deleting it if you need to.

To generate a “a long random string” for the SECRET parameter, I like using the Homebrew pwgen tool:

$ pwgen -s 64 1
H8qRx8F8UnypUqTU8zep8UJFH5KSm6DQHTGSCBwonilj5kSXpzzn5SfqIPAay1JQ

You can adjust the string length (64) as desired.

The Remark42 documentation provides detailed procedures for configuring OAuth providers, so I will not repeat it here.

The “ports” definition allows access to the Remark42 instance on the local host, including the reverse proxy. But it blocks access from an external IP.

ADMIN_SHARED_ID

The ADMIN_SHARED_ID was a bit tricky to get. After you have your Remark42 commenting system working with Hugo, login, for example with GitHub, and click on your user name. You will see a slide-in screen on the right with your GitHub Admin shared ID. Then you can add the ADMIN_SHARED_ID to your docker compose file (be sure to stop and start your docker container after making any changes to the config file).

Pull the Docker Remark42 Image

Ok, let’s get started. You first need to download the Remark42 image using the Docker Compose pull command. Change directory to the location of your docker compose configuration and “pull” the Remark42 image, using docker compose:

$ l
docker-compose.yml

$ docker compose pull
[+] Pulling 18/18
 ✔ remark42 Pulled                                             11.6s
   ✔ 4abcf2066143 Pull complete                                 0.8s
   ✔ d84f2b415aa0 Pull complete                                 0.9s
   ✔ c249752ae588 Pull complete                                 1.1s
   ✔ 2a2c873dc54c Pull complete                                 1.3s
   ✔ 21af0f4b4218 Pull complete                                 1.5s
   ✔ 3282bb3bf5c1 Pull complete                                 1.7s
   ✔ 2d41708e6ec1 Pull complete                                 3.1s
   ✔ 4f4fb700ef54 Pull complete                                 3.6s
   ✔ c93785f4bb21 Pull complete                                 4.1s
   ✔ ad5a2b1d4553 Pull complete                                 4.7s
   ✔ b69781e4c45d Pull complete                                 5.3s
   ✔ ae0a1c16f628 Pull complete                                 5.9s
   ✔ 79ce655ebebb Pull complete                                 6.4s
   ✔ d90e0dadcedb Pull complete                                 7.6s
   ✔ a652ff4c12f2 Pull complete                                 8.3s
   ✔ 68e9b2f0bbd2 Pull complete                                 9.6s
   ✔ 13560e2b8964 Pull complete                                10.1s

You will see each subimage being pulled down and installed. Your final pull state should look simalar to the above.

You can verify that the Remar42 image is installed:

$ docker image ls
REPOSITORY                 TAG       IMAGE ID       CREATED        SIZE
ghcr.io/umputun/remark42   latest    274272164479   9 months ago   81.2MB

Start the Remark42 Docker Container

Start the Remark42 server with:

$ docker compose up -d
[+] Running 3/3
 ✔ Network remark42_proxy  Created                              0.2s
 ✔ Volume "remark42_data"  Created                              0.0s
 ✔ Container remark42      Started                              1.5s

The first time when you run this command, the proxy network, remark42_proxy, is created. The data volume, remark42_data, is also created. These are “persistent” and will exist until deleted. You can verify that the remark42 container is running with the Docker ps command:

$ docker ps
CONTAINER ID   IMAGE                             COMMAND                  CREATED         STATUS                   PORTS                      NAMES
5c4aa4b0351a   ghcr.io/umputun/remark42:latest   "/init.sh /srv/remar…"   3 minutes ago   Up 3 minutes (healthy)   127.0.0.1:8080->8080/tcp   remark42

Your want to verify that the STATUS is “healthy”. You can also run the following “ping” command, via the curl command, to verify that you can communicate with the Remark42 container:

$ curl http://127.0.0.1:8080/ping
pong

You want to see the pong response.

You can stop and start the Remark42 with these commands:

$ docker stop remark42
remark42

$ docker start remark42
remark42

Integrate Remark42 with Hugo

Exactly how you do that will depend on which Hugo theme you are using. Some themes may already have Remark42 support built in. I added the following to just after the {{ .Content }} section in my layouts single.html configuration file:

{{ .Content }}

{{ if and .Site.Params.remark42.enabled (.Params.remark42 | default true) }}
  {{ partial "comments.html" . }}
{{ end }}

In my Hugo site configuration file (hugo.yaml or config.yaml), I added:

params:
  remark42:
    enabled: true
    host: "https://remark42.example.com"
    site: "example"
    locale: "en"

Note: The site parameter must match the one that you used for the SITE variable in your docker-compose.yml file. Also, be sure that host matches your REMARK_URL in docker compose configuration. You get the idea.

You might want to disable commenting for a particular post. You can add a Frontmatter variable remark42 and set it to false.

Finally, here is my remark42.html layouts partials file:

{{- with .Site.Params.remark42 -}}
<hr>
<p><b>Your comments are welcome!</b> <i>You can use your email address to Sign In (your email address is not publicly displayed), or you can use your Google or GitHub account. All comment data is hosted on Altoplace and is not tracked. Please refer to the <a href='https://remark42.com' target="_blank"><b>Remark42</b></a> <a href='https://remark42.com/privacy/' target="_blank">Privacy Policy</a> for more information.</i></p>
<div id="remark42"></div>
<script>
    var remark_config = {
        host: '{{ .host }}',
        site_id: '{{ .site }}',
        components: ['embed'],
        url: '{{ $.Permalink }}',
    };

    !function(e, n) {
        for (var o = 0; o < e.length; o++) {
            var r = n.createElement('script'),
            c = '.js',
            d = n.head || n.body;
            'noModule' in r ? (r.type = 'module', c = '.mjs') : r.async = !0, r.defer = !0, r.src = remark_config.host + '/web/' + e[o] + c, d.appendChild(r)
        }
    }(remark_config.components || ['embed'], document);

</script>
{{- end -}}

You can look below to see the final results. Better yet, try leaving a comment! There is a lot more to learn about using Remark42. You can review their extensive documentation.

How to Delete your Remark42 Installation (Optional)

This section includes additional information about how to use Docker to delete your Remark42 installation. This is what has worked for me, but I am still learning all about Docker, so your mileage may vary. My goal is to illustrate some useful Docker commands. I will show how to completely remove your Remark42 Docker installation.

First, stop the Remark42 Docker container:

$ docker stop remark42
remark42

$ docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

Next, delete the container:

$ docker ps -a
CONTAINER ID   IMAGE                             COMMAND                  CREATED         STATUS                     PORTS     NAMES
5c4aa4b0351a   ghcr.io/umputun/remark42:latest   "/init.sh /srv/remar…"   7 minutes ago   Exited (0) 3 minutes ago             remark42

$ docker rm remark42
remark42

$ docker ps -a
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

Delete the Remark42 data volume if you don’t want to keep the comment data. Careful, you will not be able to restore the data unless you made a backup!!

$ docker volume ls
DRIVER    VOLUME NAME
local     remark42_data

$ docker volume rm remark42_data
remark42_data

Delete the proxy network:

$ docker network ls
NETWORK ID     NAME             DRIVER    SCOPE
ecab21ace519   bridge           bridge    local
e8fa8c897bc8   host             host      local
4eab04d69795   none             null      local
55e527d4182c   remark42_proxy   bridge    local

$ docker network rm remark42_proxy
remark42_proxy

Finally, you can delete the Remark42 downloaded image:

$ docker image ls
REPOSITORY                 TAG       IMAGE ID       CREATED        SIZE
ghcr.io/umputun/remark42   latest    274272164479   9 months ago   81.2MB

$ docker image rmi 274272164479

That was a quick fly over; please refer to the Docker Docs for additional details.

Final Thoughts

I finally have a commenting system working with Hugo! It’s self-hosted, so I am not paying for an external 3rd party service. The comments stay on my server, under my control, so they remain private. I hope that I provided enough information for you to add commenting to your Hugo site. Please, let me know if something is not clear or you have a question. I will be happy to try to answer it. Just leave a comment below. 😄


Your comments are welcome! Use your Email Address and a Username to Sign In (your email address is not publicly displayed); you will receive an email token to confirm your email address. Or you can use your Google or GitHub account. Comment data is locally hosted via a Remark42 Docker image.

Comments are offline until I get an email server for my new self-hosted webserver. Please check back in a few days.