Add Comments to Your Hugo Site with Remark42

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.
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
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.