No description
  • Go 91.6%
  • HTML 4.1%
  • Shell 3%
  • CSS 1.2%
Find a file
Jimmy Berglund a8e069107e
All checks were successful
CI / build (push) Successful in 11m39s
GoThread 1.0.2
Bump the NodeInfo software version to 1.0.2 and summarize the changes
since 1.0.1 in the changelog: the public /api/v1/communities endpoint,
the public /instances page with per-rule visibility toggles, the sortable
communities directory, lower delivery retry budget, pending remote joins,
and the custom 404 page.
2026-09-14 20:02:04 +02:00
.forgejo/workflows GoThread 1.0.0 2026-08-23 21:39:37 +02:00
cmd/server Show pending remote joins and bound their retry re-deliveries 2026-09-14 01:22:28 +02:00
internal GoThread 1.0.2 2026-09-14 20:02:04 +02:00
scripts GoThread 1.0.0 2026-08-23 21:39:37 +02:00
.dockerignore GoThread 1.0.0 2026-08-23 21:39:37 +02:00
.gitignore GoThread 1.0.0 2026-08-23 21:39:37 +02:00
CHANGELOG.md GoThread 1.0.2 2026-09-14 20:02:04 +02:00
config.example.conf GoThread 1.0.0 2026-08-23 21:39:37 +02:00
docker-compose.yml GoThread 1.0.0 2026-08-23 21:39:37 +02:00
Dockerfile GoThread 1.0.0 2026-08-23 21:39:37 +02:00
go.mod GoThread 1.0.0 2026-08-23 21:39:37 +02:00
go.sum GoThread 1.0.0 2026-08-23 21:39:37 +02:00
LICENSE GoThread 1.0.0 2026-08-23 21:39:37 +02:00
Makefile GoThread 1.0.0 2026-08-23 21:39:37 +02:00
README.md GoThread 1.0.0 2026-08-23 21:39:37 +02:00

GoThread

A lightweight, spec-compliant threadiverse (Reddit-like) server that federates over ActivityPub. One static Go binary, one SQLite file, a built-in server- rendered UI — self-host in minutes.

GoThread speaks standard ActivityStreams 2.0 types and interops with the threadiverse: it is smoke-tested round-trip against Lemmy (follow, post, comment, vote, and moderation both directions).

Features

  • Full local forum — communities, posts, comments with threaded sorting (active/hot/new/top/controversial + time windows), votes, markdown-lite, search, RSS, pagination, profiles, notifications (mentions/replies/participation), private multireddit lists, NSFW communities.
  • Media hosting — images and video uploads stored in the same SQLite file, served with Range support.
  • Hand-rolled ActivityPub — AS2 vocab with tolerant decode, HTTP signatures (sign RSA, verify RSA + Ed25519), WebFinger, NodeInfo, inbox/outbox, fetch-by-ID, and a delivery queue with retries, backoff and idempotent dedup.
  • Moderation — removes/restores, deletes, pins, locks, reports and a mod log, personal blocks, community bans and instance allow/blocklists. Cross- instance moderation works: bans propagate to remote instances and remote Lemmy ModBanFromCommunity events are enforced locally.
  • Admin — rename the instance, toggle registration open/closed with invite links, a federation-health dashboard (queue depth, failures, replay), and single-file backups.
  • Email (optional) — SMTP-verified accounts and password resets. With a mail server configured, new accounts must confirm their email before signing in, email changes are staged until verified, unconfirmed registrations are purged after 7 days, and forgotten passwords get a one-time reset link.

Requirements

Go 1.26+ to build. Runtime is a single static binary (no cgo, no external services); modernc.org/sqlite is the only dependency.

Quick start

go build -o gothread ./cmd/server
./gothread

The defaults are https on 127.0.0.1:8040 with a forum_like.db next to the binary. For local development over plain HTTP:

./gothread -scheme http -domain 127.0.0.1:8040

For a real instance, copy the example config and edit it:

cp config.example.conf my.conf
# edit my.conf (set DOMAIN, INSTANCE_NAME, SMTP_*, etc.)
./gothread -config my.conf

The config file is KEY = value lines with comments; see config.example.conf for every key and its default.

  • The first registered account becomes the instance admin.
  • Register a community, then post — no further setup required.
  • Check ./gothread --help for every flag, or hit /healthz for a health check.

Docker

docker build -t gothread .
docker run -p 8040:8040 -e FORUM_LIKE_DOMAIN=forum.example -v gothread-data:/app/data gothread

Configuration

Precedence: defaults < config file < environment < flags. Env vars are FORUM_LIKE_*; the config file is KEY = value lines (see --help for keys).

Notable settings:

Flag / env Default Purpose
-scheme / SCHEME https Public URL scheme (http for dev)
-domain / DOMAIN host:port Public domain, used for federation IDs
-instance-name / INSTANCE_NAME GoThread Display name shown in the navbar and titles (seed; change later in /admin)
-registration-mode / REGISTRATION_MODE open open or closed (invite links) — a one-time seed; later toggled in /admin/registration
-federation-mode / FEDERATION_MODE blocklist blocklist admits all non-blocked hosts; allowlist admits only allowed hosts
-allow-private-federation off Allow federation to/from private, loopback and link-local addresses (dev/LAN)
-require-email / REQUIRE_EMAIL true Make an email mandatory at registration. Without an SMTP server configured, registration is blocked until one is set
-smtp-host / SMTP_HOST SMTP server for email verification and password resets (empty disables all outbound mail)
-smtp-port / SMTP_PORT 587 SMTP port
-smtp-username / SMTP_USERNAME SMTP username (PLAIN auth, only over TLS or localhost)
-smtp-password / SMTP_PASSWORD SMTP password
-smtp-from / SMTP_FROM noreply@<domain> Sender address on outbound mail
-smtp-security / SMTP_SECURITY starttls starttls (587), ssl (implicit TLS, 465), or none (plaintext, local dev only)
-smtp-insecure / SMTP_INSECURE off Skip TLS certificate verification (test servers)
-rate-limit-enabled / RATE_LIMIT_ENABLED off Per-client-IP rate limiting (set -trusted-proxies behind a proxy)
-backup-dir / BACKUP_DIR backups Where /admin/backup writes snapshots
-backup One-shot: write a snapshot and exit (cron-friendly)

Federation notes

  • SSRF guard: outbound federation to private/loopback/link-local targets is refused by default. Two instances on localhost must both pass -allow-private-federation.
  • Delivery is asynchronous with retries and backoff. Watch failures and replay dropped deliveries from the admin federation dashboard (/admin/federation).

Email

Email is opt-in via -smtp-host; without it, addresses are collected but never verified. Admins can still mint one-time password reset links by hand (see below). With a mail server configured:

  • Registration — a supplied address must be confirmed from a link before the account can sign in. The username stays reserved until the link is used (or the account is purged after 7 days). If the confirmation email cannot be sent, the registration is rolled back and the username is freed.
  • Login — unverified accounts get a resend page instead of a session.
  • Password reset/forgot mails a one-time, 1-hour link; responses are deliberately identical whether or not the address exists. Resetting revokes every live session.
  • Admin reset links — with or without SMTP, /admin/reset lets an admin mint a one-time, 1-hour reset link for any local account (by username or email). Issuing one supersedes any earlier reset link for that account.
  • Email changes — the current address stays active until the new one is confirmed; a staged change sits as pending_email in settings.
  • A janitor runs hourly: unverified registrations older than 7 days, spent or expired tokens, and expired sessions are removed.

Backup & restore

Everything — posts, media, keys — lives in the one SQLite file.

  • Backup: /admin/backup (admin), or ./gothread -backup /path/snapshot.db.
  • Restore: stop the server, replace the DB file with the snapshot, start again.

Development

go build ./...    # build
go vet ./...      # vet
go test ./...     # full test suite (457+ tests, no external services)
gofmt -l .        # format check, must print nothing

Smoke suites

Real servers on fixed ports (scripts/), run with go and curl:

  • federation_smoke.sh — two-instance federation and delivery replay
  • moderation_smoke.sh — blocks, thread mods, reports, audit log, announced bans
  • media_smoke.sh — multipart uploads, media serve/Range/rejections
  • registration_smoke.sh — open/closed toggle, invites, optional email
  • interop_smoke.sh — Lemmy round-trip (requires podman + podman-compose)

internal/httpsig/testdata/*.http and internal/ap/testdata/*.json are frozen requests captured from the interop harness; they pin the signer/verifier to on-wire shapes.

Layout

  • cmd/server/ — entrypoint, wiring, graceful shutdown
  • internal/config/ — flags/env/file config
  • internal/mail/ — SMTP sending (net/smtp only, no new dependencies)
  • internal/storage/ — SQLite via database/sql, embedded migrations
  • internal/ap/ — AS2/AP vocab with tolerant decode
  • internal/httpsig/ — HTTP signatures
  • internal/federation/ — delivery queue, dedup, fetch-by-ID, SSRF guard
  • internal/web/ — routes, sessions, server-rendered templates, admin UI

License

AGPL-3.0. If you modify GoThread and serve it over a network, you must offer users the modified source (section 13).