Build from source
Use this guide when you need to build Quipthread from source. For most self-hosted installations, run the published Docker image instead. It includes the migration CLI and does not require Go or Bun on the host.
Prerequisites
Section titled “Prerequisites”- A Linux server or VPS
- A domain or subdomain pointing to it
- Go 1.26.4 or newer and Bun installed (for building from source)
- Linux AMD64 or ARM64 for the pinned Atlas migration CLI
curl,sha256sum, and permission to install Atlas at/usr/local/bin/atlas
1. Clone and build
Section titled “1. Clone and build”git clone https://github.com/quipthread/quipthreadcd quipthread
# Build the dashboard and embed widget, then copy assets into backend/static/bun install --frozen-lockfilebun run build:assets:selfhosted
# Build the Go binary with embedded assetscd backendCGO_ENABLED=0 go build -tags=selfhosted,production -o quipthread .The resulting quipthread binary includes the dashboard and embed widget — no separate static file server needed.
Install the migration CLI
Section titled “Install the migration CLI”The backend requires Atlas v1.3.0 at /usr/local/bin/atlas, even when serving a database that is already migrated.
Download the pinned binary for your server: Linux AMD64 or Linux ARM64. See the Atlas installation documentation for background. Quipthread verifies this exact version and checksum, so use the pinned download rather than the latest release.
The commands below download the correct binary, verify it against the repository checksum, and install it. Run them from the backend directory on your Linux server:
( set -eu case "$(uname -m)" in x86_64) arch=amd64 ;; aarch64|arm64) arch=arm64 ;; *) echo "Atlas requires Linux AMD64 or ARM64" >&2; exit 1 ;; esac artifact="atlas-linux-${arch}-v1.3.0" checksum="$(awk -v key="linux/${arch}/${artifact}" '$2 == key { print $1 }' migration/atlas_cli.sha256)" test -n "$checksum" download_dir="$(mktemp -d)" trap 'rm -rf "$download_dir"' EXIT curl --fail --silent --show-error --location \ "https://release.ariga.io/atlas/${artifact}" --output "$download_dir/atlas" printf '%s %s\n' "$checksum" "$download_dir/atlas" | sha256sum --check --status sudo install -m 0555 "$download_dir/atlas" /usr/local/bin/atlas /usr/local/bin/atlas version)Keep the Atlas version and checksum aligned with the checkout you build. The Docker image performs this installation for you.
2. Configure environment
Section titled “2. Configure environment”Create a .env file in the backend directory and run the binary from that directory. Avoid a conflicting .env in the parent directory, which the loader reads first. At minimum:
# RequiredJWT_SECRET=<output of: openssl rand -hex 32>BASE_URL=https://comments.example.comALLOWED_ORIGINS=https://publisher.example.comDATABASE_URL=./data/comments.dbTRUST_PROXY=true
# At least one auth providerGITHUB_CLIENT_ID=...GITHUB_CLIENT_SECRET=...See Environment Variables for the full list. For OAuth app setup, see OAuth Setup.
3. Run the backend
Section titled “3. Run the backend”./quipthread# Listening on :8080Keep this process running with a service manager such as systemd. Its working directory must contain .env, and its service account needs write access to the database directory. Startup runs migrations automatically and stops if migration fails.
Proxy it behind Caddy or nginx to serve HTTPS. With TRUST_PROXY=true, restrict direct access to port 8080 so only your trusted proxy can reach it. Use TRUST_PROXY=false when accessing the app directly.
Caddy example:
comments.example.com { reverse_proxy localhost:8080}4. Sign in and create your first site
Section titled “4. Sign in and create your first site”Navigate to https://comments.example.com/login and sign in with GitHub, Google, or email (if enabled). The first user to sign in is automatically promoted to admin.
Once signed in you will be redirected to the dashboard at /dashboard/. Create a site record — you will receive a Site ID.
5. Embed the widget
Section titled “5. Embed the widget”Add the snippet to any page where you want comments. Place the <div> where the widget should appear:
<div id="comments" data-site-id="YOUR_SITE_ID" data-page-id="YOUR_PAGE_ID"></div><script src="https://comments.example.com/embed.js" async></script>Replace YOUR_SITE_ID with the ID from the dashboard, and set data-page-id to a unique string per page (e.g. the post slug).
6. Verify
Section titled “6. Verify”Open a page with the embed and you should see the comment widget. Post a test comment and check it under Moderation in the dashboard. A new commenter’s first comment waits for moderator approval.
You can also visit https://comments.example.com/dev to test the widget in isolation against the built-in dev test page.
Build a Docker image from source
Section titled “Build a Docker image from source”From the repository root, build the image:
docker build -t quipthread:local .Use quipthread:local in place of the published image in the Docker Compose or docker run example. The Docker build installs its own build tools.
Protect your data
Section titled “Protect your data”Use the backup and restore guide for the Docker image. A directly installed Go binary does not start Litestream for you; configure your own SQLite backup process before using it in production.