pseudoyu

pseudoyu

Blockchain | Programming | Photography | Boyi
github
twitter
telegram
mastodon
bilibili
jike

Build Your Free Blog Comment System from Scratch (Remark42 + fly.io)

Introduction#

In the article "What Has Changed in My Blog in 2024", I introduced the blog system I built using a Serverless platform and some open-source projects, and I started this series of tutorials to document the entire process of building and deploying.

This article is about the comment system solution.

Iteration of Comment Systems#

remark42_comments

I often feel that comments are not just a communication interaction between readers and authors; their content itself is also part of the article. In fact, some comments and discussions can often be more valuable than the article itself. Therefore, I have always placed great importance on the comment system and have been reluctant to trust third-party hosted services. I do not want any censorship, and I want the style to be as simple as possible and consistent with my blog's style.

During the development of the blog, the comment system solution has also gone through several iterations. Regarding the types and choices of comment systems, I really like the developer reorx who has detailed introductions in "Changing Blog Comment Systems", and I won't elaborate further. This article focuses more on personal experience and the detailed building process.

Disqus#

The first comment system I used was the notorious Disqus, a bulky and privacy-invasive comment system. It loaded slowly, and the free version often came with ads, which was hard to tolerate. Moreover, at that time, there were basically no comments, so there was no migration burden, and I abandoned it shortly after.

Utterances#

Then I switched to another comment system based on GitHub issues called Utterances. It generates an issue for each article, and users can comment on the issue by authorizing GitHub login. The advantage of this method is that it only requires authorizing an utterances-bot for management, without needing to deploy services or maintain databases. However, after using it for a while, I found several shortcomings:

  • Comment management is based on the GitHub API, which may become unstable if the interface changes or if there are restrictions on this type of comment system.
  • Readers must authorize GitHub login, which is inconvenient for non-technical users or readers using mobile devices.
  • It pollutes the Issues records of the GitHub repository, making it inconvenient to migrate to other systems later.

Cusdis + Supabase + Vercel#

Cusdis is an open-source comment system created by Randy that emphasizes data privacy. It is very lightweight, approximately only 5kb after gzipping. From its name, it is clear that it is a replacement for the unbearable Disqus, and it even supports importing historical data from Disqus, which is very considerate.

I started using it in mid-2021, and it has been running steadily for three years now, except for some initial deployment platform troubles due to Heroku and Railway charging fees. However, I have encountered some issues during use:

  • Due to some modifications made by WeChat's built-in browser, the comment component is not visible when opening the blog from WeChat chats/conversations.
  • Although email input is supported, it does not allow subscribing to comment replies.
  • Comments need to be manually reviewed by the administrator, but the comment notification TG Bot often fails, causing missed comments.

Overall, it is still a highly recommended solution today: lightweight, easy to self-deploy, and with a simple and beautiful style. For the setup tutorial, refer to "Lightweight Open Source Free Blog Comment System Solution (Cusdis + Railway)".

Since Railway has canceled the Free Plan since last August, if you still want to use it completely for free, you can deploy the main project for free using Vercel/Netlify/Zeabur and deploy a free PostgreSQL database instance on Supabase, passing the link as an environment variable into the Cusdis service. The other processes are similar.

Additionally, because its core functionality has not been updated for a long time, it seems a bit rudimentary compared to other more mature comment systems. However, I have adhered to the principle of "good enough" and have not considered migration or updates, only participating in some development of the Cusdis V2 version while learning front-end at one point, but it didn't last long.

Due to repeated failures during the Vercel deployment upgrade in April, I did not receive comments for nearly a few weeks. Coupled with some functional requirements, I decided to migrate and explore new solutions.

Remark42 + fly.io#

After researching, I chose Remark42 as the final choice mentioned by reorx in "Changing Blog Comment Systems".

In terms of configuration options, it is much richer than Cusdis. I have configured several common social account logins (GitHub, Twitter, Telegram, email), allowed anonymous comments, supported email subscription reply notifications, and set up TG bot notifications. It is deployed on fly.io, using a single Go binary + a single database file, which is a very comfortable solution. For a more detailed introduction and advantages of Remark42, refer to the article mentioned above.

Although Remark42 provides some migration solutions, it does not support the Cusdis I used. Fortunately, it is written in Golang, and I added migration logic myself, seamlessly migrating the 438 comments accumulated over the years.

Remark42 + fly.io Deployment Instructions#

The Remark42 + fly.io solution only involves a single service, using boltdb mounted in a volume for the database, and all operations are within fly.io's Free Plan.

Below, I will introduce how to build this free comment system from scratch.

Remark42's code is open source — "GitHub - umputun/remark42", and it provides an officially maintained image with clear and readable documentation, allowing for configuration based on actual needs.

Install flyctl Command Line Tool#

fly.io differs significantly from the Railway, Zeabur, and others I previously used in that most operations are based on command line and configuration files rather than being managed through a web interface. Therefore, the first step is to install the flyctl command line tool according to the documentation.

For example, on macOS, I used brew to install:

brew install flyctl

Authorization Login#

Open the terminal tool and use the following command to authorize login:

flyctl auth login

fly_auth_login

fly_auth_web

Log in or create an account on the web, and after completing, click Continue as xxx to finish the authorization login for the flyctl command line.

Create Application Directory#

create_fly_config

Since I usually manage configurations manually rather than using the official template, I will create a directory like remark42-on-fly and place all configuration files, environment variables, etc., in this path.

I will use VS Code for editing (you can also use vim or other editors/IDEs).

Configuration File#

Fly.io primarily uses .toml format configuration files for service management. Below is the configuration file corresponding to the service I deployed:

app = 'yu-remark42-01'
primary_region = 'hkg'

[build]
  image = 'umputun/remark42:latest'

[[mounts]]
  source = 'remark42_data_01'
  destination = '/srv/var'

[http_service]
  internal_port = 8080
  force_https = true
  auto_stop_machines = false
  auto_start_machines = true
  min_machines_running = 1
  processes = ['app']

[env]
  REMARK_URL = 'https://yu-remark42-01.fly.dev/'
  SECRET = 'remark42-secret'
  SITE= 'remark42-demo'
  ADMIN_SHARED_ID= ''

[[vm]]
  cpu_kind = 'shared'
  cpus = 1
  memory_mb = 256

Here is a detailed explanation of the configuration:

  • app: Application name, here I used yu-remark42-01, which can be modified according to your actual situation.
  • primary_region: Deployment region, which can be selected from this list. I chose Hong Kong.
  • [build]: This section mainly contains service image-related configurations.
    • image: Service image, using the official umputun/remark42:latest. You can specify a tag version if needed.
  • [[mounts]]: This section mainly contains the configuration for mounting data volumes. Since Remark42 uses a boltdb database, persistent storage is needed.
    • source: Data volume name, here I used remark42_data_01.
    • destination: Mount directory, here I mounted it to /srv/var, which is the default data storage directory for Remark42.
  • [http_service]: This section mainly contains service-related configurations.
    • internal_port: Internal port for the service, using 8080.
    • force_https: Force HTTPS.
    • auto_stop_machines: Set to false.
    • auto_start_machines: Set to true, meaning it will start automatically.
    • min_machines_running: Minimum number of running machines, set to 1.
    • processes: Service process, set to app.
  • [env]: Configure environment variables.
    • REMARK_URL: URL of the Remark42 service, here I used https://yu-remark42-01.fly.dev/, which is automatically generated by fly.io. If you later have a custom domain, this will need to be changed.
    • SITE: Site name, here I used remark42-demo.
    • SECRET: Custom JWT Token, here I used remark42-secret.
    • ADMIN_SHARED_ID: Administrator ID, here I used an empty string, meaning no administrator, which can be supplemented later.
  • [[vm]]: This section mainly contains machine-related configurations.
    • cpu_kind: CPU type, set to shared.
    • cpus: Number of CPUs, set to 1.
    • memory_mb: Memory, set to 256MB.

Create Service#

After completing and checking the configuration, run the following command to create the service:

flyctl launch

fly_launch_remark42

Environment Variable Configuration#

Currently, only the service has been deployed, and environment variables have not been set, so the service startup will have issues. Next, we will set the environment variables in the prod.env file:

AUTH_GITHUB_CID=<your_github_cid>
AUTH_GITHUB_CSEC=<your_github_csec>
AUTH_TWITTER_CID=<your_twitter_cid>
AUTH_TWITTER_CSEC=<your_twitter_csec>
AUTH_ANON=true
AUTH_TELEGRAM=true
TELEGRAM_TOKEN=<your_telegram_token>
NOTIFY_ADMINS=telegram
NOTIFY_TELEGRAM_CHAN=<your_telegram_group>
NOTIFY_USERS=email
AUTH_EMAIL_ENABLE=true
SMTP_HOST=smtp.gmail.com
SMTP_PORT=465
SMTP_TLS=true
[email protected]
SMTP_PASSWORD=<your_password>
[email protected]
[email protected]

The environment variable section is relatively complex; refer to the documentation for specific parameters.

Login/Authorization Configuration#

I configured anonymous comments, GitHub, Twitter, and Telegram login methods. You can configure other login methods based on your situation.

  • Anonymous login
    • AUTH_ANON: Whether to allow anonymous comments. I chose to allow it, meaning users can comment without logging in.
  • GitHub login
    • AUTH_GITHUB_CID and AUTH_GITHUB_CSEC: Client ID and Client Secret of the GitHub OAuth App.
  • Twitter login
    • AUTH_TWITTER_CID and AUTH_TWITTER_CSEC: Client ID and Client Secret of the Twitter OAuth App.
  • Telegram login
    • AUTH_TELEGRAM: Whether to allow Telegram login.
    • TELEGRAM_TOKEN: Telegram Bot Token created through botfather.
  • Email login
    • AUTH_EMAIL_ENABLE: Whether to allow email login.
    • AUTH_EMAIL_FROM: Sending email for email login.

Notification Configuration#

  • Telegram notifies administrators; refer to this part of the documentation for creating and configuring the Telegram Bot.
    • NOTIFY_ADMINS: Method of notifying administrators, choose telegram.
    • NOTIFY_TELEGRAM_CHAN: If enabling telegram notification for administrators, you need to configure the corresponding Channel id. Just fill in the id part after t.me/xxx, such as pseudoyuchat.
  • Email notifies users; refer to this part of the documentation for configuring SMTP, etc.
    • NOTIFY_USERS: Method of notifying users. I chose email, meaning email notifications, so the SMTP below needs to be configured.
    • NOTIFY_EMAIL_FROM: Sending address for email notifications.

Email SMTP Configuration#

The email login and email notification mentioned above require configuring the SMTP server. This part can also be configured according to your email service provider refer to the documentation.

  • SMTP_HOST: SMTP server address.
  • SMTP_PORT: SMTP server port.
  • SMTP_TLS: Whether to enable TLS.
  • SMTP_USERNAME: SMTP username.
  • SMTP_PASSWORD: SMTP password.

Import Environment Variables into the Service#

After completing the environment variable configuration according to the above instructions, run the following command in the directory where the configuration file and environment variable file are located to import the environment variables:

fly secrets import < prod.env

fly_secret_import

deploy_status_remark42

After execution, check the service status in the fly.io console. If it shows Deployed, it means the deployment was successful.

Configure Custom Domain (Optional)#

If you do not want to use the default domain provided by fly.io, you can configure a custom domain.

custom_domain_flyio

Enter the fly.io console, select the newly deployed yu-remark42-01 service, click on the Certificates option on the left, and then click Add a Certificate in the upper right corner to add a custom domain as prompted.

custom_domain_dns_in_fly

After clicking Create Certificate, a page will display the DNS records you need to add. Follow the prompts to add them.

cloudflare_dns_remark42

flyio_certificate_success

For example, my domain is hosted on Cloudflare. I added two DNS records as prompted. After returning to the page, click Check again or wait a while and refresh to see if they all show green, indicating successful configuration.

change_remark_url

At this point, we can modify REMARK_URL in fly.toml to the custom domain, then execute the following command to redeploy the service. After that, any changes to the configuration file can be updated using this command:

fly deploy

Blog Configuration for Remark42#

Having completed the deployment of the Remark42 service, we now need to add the Remark42 comment component to our blog posts. Taking my Hugo blog as an example.

Define the Comments Component in Hugo Theme#

I created a new file named comments.html in the layouts/partials directory of my Hugo blog to define the Remark42 comment component:

<div class="comments">
  <div class="title">
    <span>Comments</span>
    <span class="counter"><span class="remark42__counter" data-url="{{ .Permalink }}"></span></span>
  </div>
  <div id="remark42">
  </div>
</div>

<script>
  var remark_config = {
    host: 'https://comments.pseudoyu.com',
    site_id: 'pseudoyu.com',
    components: ['embed', 'counter'],
    max_shown_comments: 20,
    simple_view: true,
    theme: 'light',
  }
</script>

<script>
    (function () {
      // init or reset remark42
      const remark42 = window.REMARK42
      if (remark42) {
        remark42.destroy()
        remark42.createInstance(remark_config)
      } else {
        for (const component of remark_config.components) {
          var d = document, s = d.createElement('script');
          s.src = `${remark_config.host}/web/${component}.mjs`;
          s.type = 'module';
          s.defer = true;
          // prevent the <script> from loading multiple times by InstantClick
          s.setAttribute('data-no-instant', '')
          d.head.appendChild(s);
        }
      }
    })();
</script>

The host and site_id in remark_config need to be modified according to your actual configuration, while other parts can remain unchanged or be adjusted according to the documentation.

After configuring the comments component, include it at the bottom of the article in layouts/posts/single.html:

{{ partial "comments.html" . }}

add_comments_code_in_hugo

The general position is as shown in the image. If you are using other themes or blog systems, you need to find and modify the corresponding template file for your articles.

Local Preview/Deploy Website#

test_remark42_embedded

At this point, you can preview locally or deploy the website to check whether the comment system displays correctly. Thus, our service deployment is complete.

Obtain User ID and Configure Admin#

get_user_id_remark42

After completing the login authorization and testing comments, you can click on your avatar in Remark42 to open the management page. Double-clicking and pressing CMD/Ctrl+C will allow you to obtain the User ID starting with github_ or other platforms. You can configure this in ADMIN_SHARED_ID (modify the fly.toml configuration file and run fly deploy to redeploy, thus becoming an administrator, who has the authority to delete and manage other users' comments).

Others#

I exported the comment data from the previous Cusdis in JSON format according to certain conditions and used a Go program for format conversion and migration, thus retaining all previous comments.

Since Cusdis itself does not provide an export feature and the migration demand is too niche, I did not directly contribute code upstream or write a complete script. Friends with similar needs can refer to this PR for processing — "feat: add cusdis to remark42 migrator support by pseudoyu · Pull Request #1 · pseudoyu/remark42".

Conclusion#

This is the process of building my blog comment system. The construction and configuration of the comment system are relatively complex, and the configuration method in this article may become outdated over time. If you encounter problems, refer more to the official documentation.

This is one of my series of tutorials on blog building and deployment. If you are interested in building data statistics systems, internal blog search, etc., please stay tuned. I hope it can be helpful to everyone.

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.