Skip to content
fomoxx.

Why I Self-Host Waline on a VPS with SQLite

中文版

Why I Self-Host Waline on a VPS with SQLite

I recently wanted to add a comment system to my blog.

Looking at the usual options, I realized how quickly comments can turn into a small infrastructure project: GitHub Issues, Discussions, Vercel, serverless functions, cloud databases, object storage, CAPTCHAs, email notifications, and anti-spam services.

None of those pieces is especially difficult on its own. Put enough of them together, though, and a comment box starts to look like another system to operate.

My requirements were much simpler:

  1. I did not want comments hosted in GitHub.
  2. I did not want to add a stack of cloud services just for comments.
  3. I wanted the data under my control, with straightforward backup and migration.
  4. The blog was still small enough that I did not need a complex architecture from day one.

So I chose Waline and decided to run it directly on my VPS with SQLite holding the comment data.

It is not the most “cloud-native” design. It is simple, controllable, and easy to reason about.

Why I did not use GitHub-hosted comments

GitHub-backed comment systems have one big advantage: they are lightweight.

Tools such as utterances and giscus map a post to a GitHub issue or discussion, load a frontend component, and give you a working comment section with very little infrastructure.

If the blog is exclusively for developers and almost every reader already has a GitHub account, that can be an excellent fit.

I did not want that trade-off.

First, the comment data does not really live with the site. It can be exported, but its normal operating model still depends on GitHub. If I later migrate, I would need to think again about article mapping, user identity, and reply relationships.

Second, requiring GitHub creates friction. A reader who only wants to leave one sentence may not want to sign into a developer platform first.

Third, I did not want the interaction layer of a general personal blog to assume that every reader should have a developer identity. The site can cover AI, tools, trading, content operations, and more ordinary subjects.

My preference is therefore simple: keep the comment system lightweight, but keep the data as close to my own infrastructure as possible.

Why I chose Waline

Waline sits in a useful middle ground for me.

It is more than a frontend widget but much smaller than a forum. It has a server, an admin interface, a database layer, and mature integrations for static blogs.

At the time I made this choice, the Hugo theme I was using already supported Waline, so the integration cost was low. The site no longer depends on that theme; Waline is now integrated through the site’s own Hugo partial.

The features I cared about were:

  • Anonymous comments without forcing readers to authenticate through GitHub.
  • Admin management for comments, moderation, and users.
  • Comment moderation, which is useful when opening a new public comment endpoint.
  • Multiple database backends, so SQLite can be the starting point and a larger database remains an option later.
  • Lightweight frontend integration, which only needs a small Hugo configuration or partial.

Waline is not a full community platform and I do not want it to be one. For a personal blog comment section, that is exactly the point.

Why I did not use Vercel plus a cloud database

Waline supports deployments such as Vercel, and for a small blog the free tiers can be enough.

I still did not see a reason to use them for this site.

Vercel itself is not difficult. A hosted database is not difficult either. But once they are combined, I now have to remember:

  • where the Vercel project lives;
  • where the database lives;
  • where the environment variables live;
  • whether the free tier is still sufficient;
  • how the domain is connected;
  • how the comment data will move if I migrate later.

All of those questions have answers. They are just not the problems I actually want to spend time on.

A comment system is not the core product of this site. It is a small table next to the blog. I want it to sit there quietly, work, remain backup-able, and not require a chain of service dependencies.

I already had a VPS, so running Waline there was the simpler option.

Why VPS + SQLite works for me

The architecture is straightforward:

fomoxx.com article page
        |
        | loads the Waline frontend component
        v
comments.fomoxx.com
        |
        | Nginx / Caddy reverse proxy
        v
Waline Docker container
        |
        v
SQLite file

The benefits are equally straightforward.

First, there are few dependencies. One Docker container, one data directory, and one reverse-proxy configuration are enough.

Second, the data model is easy to understand. The comments live in the SQLite file. Backing up the comment system means backing up one data directory. Compared with several cloud dashboards, that simplicity is reassuring.

Third, cost is predictable. The VPS is already running and paid for. Waline adds a small amount of CPU, memory, and disk usage without giving me another serverless or database quota to monitor.

Fourth, migration remains manageable. If the comment volume eventually justifies PostgreSQL or MySQL, I can move then instead of building for hypothetical scale on day one.

A simplified deployment

I run Waline through Docker Compose, expose it only on a local port, and put Nginx or Caddy in front of it for HTTPS.

A simplified configuration looks like this:

services:
  waline:
    image: lizheming/waline:latest
    container_name: waline
    restart: unless-stopped
    ports:
      - "127.0.0.1:8360:8360"
    volumes:
      - ./data:/app/data
    environment:
      TZ: Asia/Shanghai
      SQLITE_PATH: /app/data
      SQLITE_DB: waline.sqlite
      JWT_TOKEN: "replace this with a sufficiently long random string"
      SITE_NAME: fomoxx
      SITE_URL: https://fomoxx.com
      SECURE_DOMAINS: fomoxx.com,comments.fomoxx.com
      COMMENT_AUDIT: "true"
      IPQPS: "60"

A few settings matter more to me than the rest.

COMMENT_AUDIT=true means comments require approval before they are displayed. When opening a comment section on a new public site, I would rather approve messages manually than let spam appear directly under posts.

SECURE_DOMAINS restricts which site domains are allowed to call the comment service so the endpoint is not treated as a public API by unrelated websites.

IPQPS=60 adds a frequency limit. It will not stop every attack, but it raises the cost of basic automated abuse.

I also keep the comment service on the separate comments.fomoxx.com hostname rather than mounting it under the main site path. That keeps later migration, replacement, rate limiting, and protection easier to reason about.

The most important part is backup

SQLite’s biggest strength is its simplicity.

Its biggest operational risk is the same thing: the important data is concentrated in a file.

So this setup only makes sense if the data is backed up.

My minimum requirement is one backup of the Waline data directory per day and at least seven days of retention.

If the VPS also has snapshots, that is useful, but I would not use snapshots as the only backup.

A backup can be as simple as:

tar -czf waline-$(date +%F).tar.gz /opt/waline/data

Then copy the archive to another machine, object storage, or a local NAS.

A personal blog will not generate comment traffic like a transaction system, but once readers have written comments, those comments become part of the site’s content.

They may not be financially valuable, but they are worth preserving.

My final setup

The decision ended up being simple:

  • Comment system: Waline
  • Deployment: my own VPS
  • Database: SQLite
  • Hostname: comments.fomoxx.com
  • Publishing policy: moderation enabled before comments become visible
  • Operational priority: back up the data directory instead of designing a complex architecture

What I like about this setup is that it does not pretend to be more sophisticated than it needs to be.

It puts the comment system back in its proper place: a small, independent, backup-able service beside the blog.

FAQ

Is Waline a good fit for a personal blog?

For my use case, yes. Waline provides a frontend comment component, a server, an admin interface, moderation, notifications, and multiple database options. SQLite is enough for an early-stage personal blog.

Why not use GitHub Issues or Discussions for comments?

GitHub-backed comment systems are lightweight, but they tie the comment experience and data model to GitHub. I wanted readers to be able to comment without treating a developer platform as the default identity layer.

Is SQLite enough for a comment system?

For a small personal blog, SQLite is usually sufficient. The more important operational requirement is regular backup. If the comment volume ever grows enough to justify it, the database can be migrated later.

Are comments published immediately?

Waline can display comments directly, but I prefer enabling comment moderation on a new personal site so spam and low-cost API abuse do not appear publicly before review.

Continue reading

Comments