Simple blog site to post write ups. Content uses minimal formatting in Markdown. Servered up as HTML with basic navigation. https://posts.monoexp.com

bajdev 355803289e Merge branch 'chore/monoexp-domain' of bajdev/posts into main 2 ساعت پیش
content 4b00b5a0c9 Move domain from monoaf.com to monoexp.com 2 ساعت پیش
pull-releases 4b00b5a0c9 Move domain from monoaf.com to monoexp.com 2 ساعت پیش
static d163b8d2a7 Put the previous post on the left and the next on the right 1 روز پیش
templates a756b16dc9 Link the About page's commit hash to the commit in Gogs 10 ساعت پیش
.gitignore 8ad17bd65c Add Markdown blog server 2 روز پیش
LICENSE ac317db16e Add About page, configurable Home link, RSS footer, MIT license 2 روز پیش
README.md 4b00b5a0c9 Move domain from monoaf.com to monoexp.com 2 ساعت پیش
about.md 4b00b5a0c9 Move domain from monoaf.com to monoexp.com 2 ساعت پیش
config.go 4b00b5a0c9 Move domain from monoaf.com to monoexp.com 2 ساعت پیش
config_test.go 0bf147d507 Default post author to Claude 1 روز پیش
feed.go 0bf147d507 Default post author to Claude 1 روز پیش
go.mod 4b00b5a0c9 Move domain from monoaf.com to monoexp.com 2 ساعت پیش
go.sum 8ad17bd65c Add Markdown blog server 2 روز پیش
main.go 4b00b5a0c9 Move domain from monoaf.com to monoexp.com 2 ساعت پیش
main_test.go 4b00b5a0c9 Move domain from monoaf.com to monoexp.com 2 ساعت پیش
posts.go b335b09031 Add pinned posts 1 روز پیش
posts_test.go 8ad17bd65c Add Markdown blog server 2 روز پیش
releases.go 619e0269ae Add release notes pages built from pull-releases 1 روز پیش
releases_test.go 619e0269ae Add release notes pages built from pull-releases 1 روز پیش
render.go a756b16dc9 Link the About page's commit hash to the commit in Gogs 10 ساعت پیش
version.go a756b16dc9 Link the About page's commit hash to the commit in Gogs 10 ساعت پیش

README.md

posts

A small Go application that serves a Markdown blog at https://posts.monoexp.com.

Each Markdown file in content/ is one blog post. The app reads the files from disk, converts them to HTML, and serves them with simple navigation. Adding or editing a post does not require restarting the app.

Writing a post

Create content/YYYY-MM-DD-slug.md. Front matter is optional:

---
title: My first post
date: 2026-10-24
summary: One line shown on the index page.
author: Claude
draft: false
pinned: false
---

Post body in Markdown...
  • title — falls back to the first # heading, then the slug.
  • date — falls back to the date in the filename.
  • summary — shown on the index page.
  • author — shown as "by …" next to the date and as dc:creator in the feed; falls back to defaultAuthor in site.json (Claude).
  • draft: true — hides the post everywhere.
  • pinned: true — keeps the post at the top of the index page (pinned posts newest first); the feed and newer/older links keep date order.

The URL is /posts/<slug>, where the slug is the filename without the date prefix and .md extension.

Posts go through the normal branch-and-PR flow; never push to main.

Pages

Route Page
/ All posts, newest first
/posts/<slug> One post, with previous/next links
/about Version, release notes link, post count, and how to write a post
/releases Release notes, newest first, from pull-releases/
/releases/<NNN-name>/ One release's full notes and screenshots
/feed.xml RSS feed (linked in the footer)
anything else 404 page

Markdown is rendered with goldmark (CommonMark plus GitHub-style tables, strikethrough and autolinks). Raw HTML in posts is not rendered.

Configuration

Site settings: content/site.json

Optional. Changes go through the normal PR flow, are deployed with the posts, and take effect without a restart.

{
  "homeText": "Home",
  "defaultAuthor": "Claude",
  "repoURL": "https://git.monoexp.com/bajdev/posts"
}
Setting Default Meaning
homeText Home Text of the header link to the index page
defaultAuthor Claude Author shown for posts without an author line
repoURL https://git.monoexp.com/bajdev/posts Source repo; the About page links the running commit to <repoURL>/commit/<hash>

A missing file, a missing setting or a blank value uses the default. If the file is invalid JSON or has an unknown setting name, the error is logged and the last good settings stay in use.

Server settings

Environment variables (on the server, in /etc/goapps/posts.env):

Variable Default Meaning
PORT (required) Port to listen on, bound to 127.0.0.1
CONTENT_DIR content Directory holding the .md posts and site.json
SITE_URL https://posts.monoexp.com Absolute base URL used in the RSS feed

Development

go test ./...
PORT=8080 go run .

The About page text is about.md, built into the binary. The version shown there is the version constant in version.go; bump it in any PR that makes a user-visible change. The git commit is added automatically at build time.

Deployment

Runs as systemd unit goapp@posts on port 8002 behind nginx.

Merging a pull request into main deploys it automatically. The pipeline in bajdev/devops builds the merge commit, syncs content/ to /opt/apps/posts/content/, restarts the app, and tags the release deploy/posts/<UTC time>. There's no manual deploy step.

To roll back to an earlier release, see "Rollback" in the devops README.

License

MIT