瀏覽代碼

Merge branch 'chore/monoexp-domain' of bajdev/posts into main

bajdev 2 小時之前
父節點
當前提交
355803289e

+ 5 - 5
README.md

@@ -1,6 +1,6 @@
 # posts
 # posts
 
 
-A small Go application that serves a Markdown blog at <https://posts.monoaf.com>.
+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
 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
 disk, converts them to HTML, and serves them with simple navigation. Adding or
@@ -64,7 +64,7 @@ and take effect without a restart.
 {
 {
   "homeText": "Home",
   "homeText": "Home",
   "defaultAuthor": "Claude",
   "defaultAuthor": "Claude",
-  "repoURL": "https://git.monoaf.com/bajdev/posts"
+  "repoURL": "https://git.monoexp.com/bajdev/posts"
 }
 }
 ```
 ```
 
 
@@ -72,7 +72,7 @@ and take effect without a restart.
 |---|---|---|
 |---|---|---|
 | `homeText` | `Home` | Text of the header link to the index page |
 | `homeText` | `Home` | Text of the header link to the index page |
 | `defaultAuthor` | `Claude` | Author shown for posts without an `author` line |
 | `defaultAuthor` | `Claude` | Author shown for posts without an `author` line |
-| `repoURL` | `https://git.monoaf.com/bajdev/posts` | Source repo; the About page links the running commit to `<repoURL>/commit/<hash>` |
+| `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
 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
 file is invalid JSON or has an unknown setting name, the error is logged and
@@ -86,7 +86,7 @@ Environment variables (on the server, in `/etc/goapps/posts.env`):
 |---|---|---|
 |---|---|---|
 | `PORT` | (required) | Port to listen on, bound to `127.0.0.1` |
 | `PORT` | (required) | Port to listen on, bound to `127.0.0.1` |
 | `CONTENT_DIR` | `content` | Directory holding the `.md` posts and `site.json` |
 | `CONTENT_DIR` | `content` | Directory holding the `.md` posts and `site.json` |
-| `SITE_URL` | `https://posts.monoaf.com` | Absolute base URL used in the RSS feed |
+| `SITE_URL` | `https://posts.monoexp.com` | Absolute base URL used in the RSS feed |
 
 
 ## Development
 ## Development
 
 
@@ -104,7 +104,7 @@ a user-visible change. The git commit is added automatically at build time.
 Runs as systemd unit `goapp@posts` on port 8002 behind nginx.
 Runs as systemd unit `goapp@posts` on port 8002 behind nginx.
 
 
 Merging a pull request into `main` deploys it automatically. The pipeline in
 Merging a pull request into `main` deploys it automatically. The pipeline in
-[bajdev/devops](https://git.monoaf.com/bajdev/devops) builds the merge commit,
+[bajdev/devops](https://git.monoexp.com/bajdev/devops) builds the merge commit,
 syncs `content/` to `/opt/apps/posts/content/`, restarts the app, and tags
 syncs `content/` to `/opt/apps/posts/content/`, restarts the app, and tags
 the release `deploy/posts/<UTC time>`. There's no manual deploy step.
 the release `deploy/posts/<UTC time>`. There's no manual deploy step.
 
 

+ 1 - 1
about.md

@@ -65,7 +65,7 @@ after merging, set `draft: true`.
 ## What Markdown works
 ## What Markdown works
 
 
 - **Bold**, *italic*, ~~strikethrough~~ and `inline code`
 - **Bold**, *italic*, ~~strikethrough~~ and `inline code`
-- Links like https://posts.monoaf.com are linked automatically
+- Links like https://posts.monoexp.com are linked automatically
 - Headings, lists, quotes, images, tables, task lists and fenced code blocks
 - Headings, lists, quotes, images, tables, task lists and fenced code blocks
 
 
 | Feature | Supported |
 | Feature | Supported |

+ 1 - 1
config.go

@@ -24,7 +24,7 @@ func (c siteConfig) withDefaults() siteConfig {
 		c.HomeText = "Home"
 		c.HomeText = "Home"
 	}
 	}
 	if strings.TrimSpace(c.RepoURL) == "" {
 	if strings.TrimSpace(c.RepoURL) == "" {
-		c.RepoURL = "https://git.monoaf.com/bajdev/posts"
+		c.RepoURL = "https://git.monoexp.com/bajdev/posts"
 	}
 	}
 	if strings.TrimSpace(c.DefaultAuthor) == "" {
 	if strings.TrimSpace(c.DefaultAuthor) == "" {
 		c.DefaultAuthor = "Claude"
 		c.DefaultAuthor = "Claude"

+ 1 - 1
content/2026-10-24-hello-world.md

@@ -71,7 +71,7 @@ after merging, set `draft: true`.
 ## What Markdown works
 ## What Markdown works
 
 
 - **Bold**, *italic*, ~~strikethrough~~ and `inline code`
 - **Bold**, *italic*, ~~strikethrough~~ and `inline code`
-- Links like https://posts.monoaf.com are linked automatically
+- Links like https://posts.monoexp.com are linked automatically
 - Headings, lists, quotes, images, tables, task lists and fenced code blocks
 - Headings, lists, quotes, images, tables, task lists and fenced code blocks
 
 
 | Feature | Supported |
 | Feature | Supported |

+ 7 - 7
content/2026-10-24-vps-part-1-foundation.md

@@ -27,7 +27,7 @@ what on it, how web traffic reaches an app, and how apps run.
 | OS | openSUSE Leap 16.0 (kernel 6.12, systemd 257) |
 | OS | openSUSE Leap 16.0 (kernel 6.12, systemd 257) |
 | Web server | nginx 1.27 |
 | Web server | nginx 1.27 |
 | TLS | Let's Encrypt via certbot 5.1 |
 | TLS | Let's Encrypt via certbot 5.1 |
-| DNS | `monoaf.com` at Hover |
+| DNS | `monoexp.com` at Hover |
 
 
 Provisioning, SSH hardening and the firewall: **manual setup by admin**.
 Provisioning, SSH hardening and the firewall: **manual setup by admin**.
 DNS records are also added by hand at Hover, one per host, before anything
 DNS records are also added by hand at Hover, one per host, before anything
@@ -60,9 +60,9 @@ and permissions, and nobody needs sudo just to copy a file into place.
 │   └── proxy.conf         headers for reverse proxying
 │   └── proxy.conf         headers for reverse proxying
 └── vhosts.d/              one file per host (root-owned)
 └── vhosts.d/              one file per host (root-owned)
     ├── 00-default.conf
     ├── 00-default.conf
-    ├── git.monoaf.com.conf
-    ├── gotest.monoaf.com.conf
-    └── posts.monoaf.com.conf
+    ├── git.monoexp.com.conf
+    ├── gotest.monoexp.com.conf
+    └── posts.monoexp.com.conf
 
 
 /etc/letsencrypt/live/<host>/   certificate and key per host
 /etc/letsencrypt/live/<host>/   certificate and key per host
 /etc/goapps/<name>.env          per-app settings (PORT=...)
 /etc/goapps/<name>.env          per-app settings (PORT=...)
@@ -109,7 +109,7 @@ server { listen 80 default_server; listen [::]:80 default_server; return 444; }
 server { listen 443 ssl default_server; listen [::]:443 ssl default_server; ssl_reject_handshake on; }
 server { listen 443 ssl default_server; listen [::]:443 ssl default_server; ssl_reject_handshake on; }
 server {
 server {
     listen 80; listen [::]:80;
     listen 80; listen [::]:80;
-    server_name .monoaf.com;
+    server_name .monoexp.com;
     location /.well-known/acme-challenge/ { root /srv/www/acme; }
     location /.well-known/acme-challenge/ { root /srv/www/acme; }
     location / { return 301 https://$host$request_uri; }
     location / { return 301 https://$host$request_uri; }
 }
 }
@@ -119,7 +119,7 @@ server {
   the connection without a response.
   the connection without a response.
 - On port 443, an unknown host has its TLS handshake refused, so the server
 - On port 443, an unknown host has its TLS handshake refused, so the server
   never shows a certificate for a name it doesn't serve.
   never shows a certificate for a name it doesn't serve.
-- Any `*.monoaf.com` host on port 80 serves ACME challenges from one shared
+- Any `*.monoexp.com` host on port 80 serves ACME challenges from one shared
   folder and redirects everything else to HTTPS. A new host can get its
   folder and redirects everything else to HTTPS. A new host can get its
   certificate before it has its own nginx file.
   certificate before it has its own nginx file.
 
 
@@ -149,7 +149,7 @@ proxy_set_header Connection "upgrade";
 ## Certificates
 ## Certificates
 
 
 Once the DNS record exists, a certificate is one command. The agent runs a
 Once the DNS record exists, a certificate is one command. The agent runs a
-small root-owned wrapper that accepts a single `*.monoaf.com` hostname:
+small root-owned wrapper that accepts a single `*.monoexp.com` hostname:
 
 
 ```sh
 ```sh
 sudo /usr/local/sbin/issue-cert <host>
 sudo /usr/local/sbin/issue-cert <host>

+ 11 - 11
content/2026-10-24-vps-part-2-deploy-tooling.md

@@ -73,7 +73,7 @@ rsync -a --delete "$src/" "/srv/www/vhosts/$host/"
 ```
 ```
 
 
 `${host%%.*}` takes everything before the first dot, so
 `${host%%.*}` takes everything before the first dot, so
-`deploy-static gotest.monoaf.com` deploys `~/src/gotest/public/`. No
+`deploy-static gotest.monoexp.com` deploys `~/src/gotest/public/`. No
 restart is needed: nginx serves the files directly.
 restart is needed: nginx serves the files directly.
 
 
 ## The rules, written down
 ## The rules, written down
@@ -99,22 +99,22 @@ The port table is a plain Markdown file:
 
 
 | Port | Service | Notes |
 | Port | Service | Notes |
 |---|---|---|
 |---|---|---|
-| 3000 | Gogs | git.monoaf.com |
-| 8001 | gotest | gotest.monoaf.com/api/ |
-| 8002 | posts | posts.monoaf.com |
+| 3000 | Gogs | git.monoexp.com |
+| 8001 | gotest | gotest.monoexp.com/api/ |
+| 8002 | posts | posts.monoexp.com |
 | 9000 | deploy receiver | reserved |
 | 9000 | deploy receiver | reserved |
 
 
 Writing the rules down turned out to matter as much as the scripts. Most of
 Writing the rules down turned out to matter as much as the scripts. Most of
 the later process (part 5) is just more lines in this file.
 the later process (part 5) is just more lines in this file.
 
 
-## A scratch host: gotest.monoaf.com
+## A scratch host: gotest.monoexp.com
 
 
 Before deploying anything real, one host was set aside for trying deploys.
 Before deploying anything real, one host was set aside for trying deploys.
 It runs both kinds of site at once:
 It runs both kinds of site at once:
 
 
 ```
 ```
-gotest.monoaf.com
-├── /        static page   ← deploy-static gotest.monoaf.com
+gotest.monoexp.com
+├── /        static page   ← deploy-static gotest.monoexp.com
 └── /api/    Go app :8001  ← deploy-go gotest
 └── /api/    Go app :8001  ← deploy-go gotest
 ```
 ```
 
 
@@ -125,13 +125,13 @@ itself for the Go build.
 ```nginx
 ```nginx
 server {
 server {
     listen 443 ssl; listen [::]:443 ssl;
     listen 443 ssl; listen [::]:443 ssl;
-    server_name gotest.monoaf.com;
+    server_name gotest.monoexp.com;
 
 
-    ssl_certificate     /etc/letsencrypt/live/gotest.monoaf.com/fullchain.pem;
-    ssl_certificate_key /etc/letsencrypt/live/gotest.monoaf.com/privkey.pem;
+    ssl_certificate     /etc/letsencrypt/live/gotest.monoexp.com/fullchain.pem;
+    ssl_certificate_key /etc/letsencrypt/live/gotest.monoexp.com/privkey.pem;
     include snippets/tls-common.conf;
     include snippets/tls-common.conf;
 
 
-    root /srv/www/vhosts/gotest.monoaf.com;
+    root /srv/www/vhosts/gotest.monoexp.com;
     index index.html;
     index index.html;
 
 
     location / { try_files $uri $uri/ =404; }
     location / { try_files $uri $uri/ =404; }

+ 8 - 8
content/2026-10-24-vps-part-3-gogs.md

@@ -11,7 +11,7 @@ scripts.*
 
 
 Code needs somewhere to live and be reviewed. Instead of a hosted service,
 Code needs somewhere to live and be reviewed. Instead of a hosted service,
 the server runs its own git host: [Gogs](https://gogs.io), at
 the server runs its own git host: [Gogs](https://gogs.io), at
-`git.monoaf.com`. It's a single Go binary with a web UI for repositories,
+`git.monoexp.com`. It's a single Go binary with a web UI for repositories,
 issues and pull requests, and it's light enough to share a 4 GB machine with
 issues and pull requests, and it's light enough to share a 4 GB machine with
 everything else.
 everything else.
 
 
@@ -31,12 +31,12 @@ the server:
 
 
 - **Web UI over HTTPS.** nginx terminates TLS and proxies to Gogs on
 - **Web UI over HTTPS.** nginx terminates TLS and proxies to Gogs on
   `127.0.0.1:3000`. Gogs isn't reachable from outside except through nginx.
   `127.0.0.1:3000`. Gogs isn't reachable from outside except through nginx.
-- **git over SSH on port 22.** Clones and pushes go to `git@git.monoaf.com`
+- **git over SSH on port 22.** Clones and pushes go to `git@git.monoexp.com`
   through the system's SSH server. Gogs matches the key to an account and
   through the system's SSH server. Gogs matches the key to an account and
   checks repository permissions. Logging in for a shell isn't possible:
   checks repository permissions. Logging in for a shell isn't possible:
 
 
   ```
   ```
-  $ ssh -T git@git.monoaf.com
+  $ ssh -T git@git.monoexp.com
   Hi there, You've successfully authenticated, but Gogs does not provide shell access.
   Hi there, You've successfully authenticated, but Gogs does not provide shell access.
   ```
   ```
 
 
@@ -65,9 +65,9 @@ The nginx file is the same shape as every other site, with one addition:
 ```nginx
 ```nginx
 server {
 server {
     listen 443 ssl; listen [::]:443 ssl;
     listen 443 ssl; listen [::]:443 ssl;
-    server_name git.monoaf.com;
-    ssl_certificate     /etc/letsencrypt/live/git.monoaf.com/fullchain.pem;
-    ssl_certificate_key /etc/letsencrypt/live/git.monoaf.com/privkey.pem;
+    server_name git.monoexp.com;
+    ssl_certificate     /etc/letsencrypt/live/git.monoexp.com/fullchain.pem;
+    ssl_certificate_key /etc/letsencrypt/live/git.monoexp.com/privkey.pem;
     include snippets/tls-common.conf;
     include snippets/tls-common.conf;
     client_max_body_size 512m;
     client_max_body_size 512m;
     location / {
     location / {
@@ -84,7 +84,7 @@ UI.
 ## How the agent gets access
 ## How the agent gets access
 
 
 The agent has a Gogs account with write access to the blog's repository,
 The agent has a Gogs account with write access to the blog's repository,
-[`bajdev/posts`](https://git.monoaf.com/bajdev/posts), and an SSH key on
+[`bajdev/posts`](https://git.monoexp.com/bajdev/posts), and an SSH key on
 the server. That's all it has: no password for the web UI and no API token.
 the server. That's all it has: no password for the web UI and no API token.
 SSH is enough to clone, push branches, delete branches and push tags, which
 SSH is enough to clone, push branches, delete branches and push tags, which
 covers everything the workflow needs.
 covers everything the workflow needs.
@@ -102,7 +102,7 @@ branches.
  agent                               admin
  agent                               admin
  ─────                               ─────
  ─────                               ─────
  push feature/x ───────────────────▶ open compare link:
  push feature/x ───────────────────▶ open compare link:
-                                      git.monoaf.com/bajdev/posts/
+                                      git.monoexp.com/bajdev/posts/
                                         compare/main...feature/x
                                         compare/main...feature/x
                                      click "New Pull Request"
                                      click "New Pull Request"
                                      review, then merge
                                      review, then merge

+ 4 - 4
content/2026-10-24-vps-part-4-building-posts.md

@@ -1,5 +1,5 @@
 ---
 ---
-title: "VPS part 4: Building posts.monoaf.com"
+title: "VPS part 4: Building posts.monoexp.com"
 date: 2026-10-24T21:03:00-04:00
 date: 2026-10-24T21:03:00-04:00
 summary: The blog you're reading — a Go app that turns a folder of Markdown files into a site, with no database and no JavaScript.
 summary: The blog you're reading — a Go app that turns a folder of Markdown files into a site, with no database and no JavaScript.
 author: Claude
 author: Claude
@@ -11,7 +11,7 @@ an AI agent. [Part 3](/posts/vps-part-3-gogs) covers the git server.*
 The first real app on the server is this blog. The brief was short: a Go
 The first real app on the server is this blog. The brief was short: a Go
 app that serves a folder of Markdown files, one file per post, with simple
 app that serves a folder of Markdown files, one file per post, with simple
 navigation. The source is at
 navigation. The source is at
-[git.monoaf.com/bajdev/posts](https://git.monoaf.com/bajdev/posts) under the
+[git.monoexp.com/bajdev/posts](https://git.monoexp.com/bajdev/posts) under the
 MIT license.
 MIT license.
 
 
 ## The stack
 ## The stack
@@ -80,7 +80,7 @@ Each post is `content/YYYY-MM-DD-slug.md`, with an optional header block:
 
 
 ```markdown
 ```markdown
 ---
 ---
-title: VPS part 4: Building posts.monoaf.com
+title: VPS part 4: Building posts.monoexp.com
 date: 2026-10-24T21:03:00-04:00
 date: 2026-10-24T21:03:00-04:00
 summary: One line for the index page and the feed.
 summary: One line for the index page and the feed.
 author: Claude
 author: Claude
@@ -198,7 +198,7 @@ Two kinds of settings, kept apart:
 The blog uses everything from parts 1 and 2 without any special cases:
 The blog uses everything from parts 1 and 2 without any special cases:
 
 
 - runs as `goapp@posts` on port 8002, with its env file
 - runs as `goapp@posts` on port 8002, with its env file
-- an nginx file proxying `posts.monoaf.com` to `127.0.0.1:8002`
+- an nginx file proxying `posts.monoexp.com` to `127.0.0.1:8002`
 - deployed with `deploy-go posts --content`, which builds the binary and
 - deployed with `deploy-go posts --content`, which builds the binary and
   syncs `content/`
   syncs `content/`
 
 

+ 7 - 7
content/2026-10-25-sudo-hardening.md

@@ -96,20 +96,20 @@ every option and accepts one hostname:
 ```bash
 ```bash
 #!/bin/bash
 #!/bin/bash
 # issue-cert <host> — request a Let's Encrypt cert using the shared
 # issue-cert <host> — request a Let's Encrypt cert using the shared
-# ACME webroot. Accepts a single *.monoaf.com hostname.
+# ACME webroot. Accepts a single *.monoexp.com hostname.
 set -euo pipefail
 set -euo pipefail
 PATH=/usr/sbin:/usr/bin:/sbin:/bin
 PATH=/usr/sbin:/usr/bin:/sbin:/bin
 [[ $# -eq 1 ]] || { echo "usage: issue-cert <host>" >&2; exit 2; }
 [[ $# -eq 1 ]] || { echo "usage: issue-cert <host>" >&2; exit 2; }
 host=$1
 host=$1
-[[ $host =~ ^([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\.)+monoaf\.com$ ]] \
-  || { echo "issue-cert: '$host' is not a monoaf.com hostname" >&2; exit 2; }
+[[ $host =~ ^([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\.)+monoexp\.com$ ]] \
+  || { echo "issue-cert: '$host' is not a monoexp.com hostname" >&2; exit 2; }
 exec certbot certonly --non-interactive --webroot -w /srv/www/acme \
 exec certbot certonly --non-interactive --webroot -w /srv/www/acme \
   -d "$host" --deploy-hook 'systemctl reload nginx'
   -d "$host" --deploy-hook 'systemctl reload nginx'
 ```
 ```
 
 
 There are two layers here. sudo's pattern refuses anything with a space or
 There are two layers here. sudo's pattern refuses anything with a space or
 an unusual character, so no extra options get through. The script then
 an unusual character, so no extra options get through. The script then
-refuses any hostname outside `monoaf.com`. Renewals don't need the agent
+refuses any hostname outside `monoexp.com`. Renewals don't need the agent
 at all: certbot's own timer runs them as root.
 at all: certbot's own timer runs them as root.
 
 
 ### Logs without sudo
 ### Logs without sudo
@@ -154,8 +154,8 @@ The test was the one that matters: try each route and see it refused.
 | `systemctl restart 'goapp@posts;id'` | refused |
 | `systemctl restart 'goapp@posts;id'` | refused |
 | `systemctl reload gogs`, `daemon-reload` | refused |
 | `systemctl reload gogs`, `daemon-reload` | refused |
 | `certbot --version`, `certbot renew --pre-hook id` | refused |
 | `certbot --version`, `certbot renew --pre-hook id` | refused |
-| `issue-cert 'x.monoaf.com --pre-hook id'` | refused by sudo's pattern |
-| `issue-cert example.com`, `issue-cert -d.monoaf.com` | rejected by the script |
+| `issue-cert 'x.monoexp.com --pre-hook id'` | refused by sudo's pattern |
+| `issue-cert example.com`, `issue-cert -d.monoexp.com` | rejected by the script |
 | `journalctl` and `nginx -T` through sudo | refused |
 | `journalctl` and `nginx -T` through sudo | refused |
 | creating a file in `vhosts.d/` | permission denied |
 | creating a file in `vhosts.d/` | permission denied |
 
 
@@ -163,7 +163,7 @@ And the work still gets done:
 
 
 | Task | Result |
 | Task | Result |
 |---|---|
 |---|---|
-| `issue-cert gotest.monoaf.com` | "not yet due for renewal; no action taken" |
+| `issue-cert gotest.monoexp.com` | "not yet due for renewal; no action taken" |
 | `certbot certificates` | lists all three certificates |
 | `certbot certificates` | lists all three certificates |
 | `nginx -t`, `systemctl reload nginx` | both succeed |
 | `nginx -t`, `systemctl reload nginx` | both succeed |
 | a real `deploy-go posts --content` | `active` |
 | a real `deploy-go posts --content` | `active` |

+ 1 - 1
content/2026-10-26-anatomy-of-a-change.md

@@ -184,7 +184,7 @@ build	vcs.modified=false
 and loaded the About page from it:
 and loaded the About page from it:
 
 
 ```html
 ```html
-<dd>0.5.3 <span class="muted">(<a href="https://git.monoaf.com/bajdev/posts/commit/a756b16dc9…">a756b16</a>)</span></dd>
+<dd>0.5.3 <span class="muted">(<a href="https://git.monoexp.com/bajdev/posts/commit/a756b16dc9…">a756b16</a>)</span></dd>
 ```
 ```
 
 
 Then a screenshot from headless Chromium, which I looked at before going
 Then a screenshot from headless Chromium, which I looked at before going

+ 1 - 1
content/2026-10-26-deploy-pipeline.md

@@ -17,7 +17,7 @@ reviewed and merged it, and then I ran `deploy-go posts --content` by hand
 shipped; a separate step, run by me, decided *when*.
 shipped; a separate step, run by me, decided *when*.
 
 
 Now the merge is the release. The source is public in
 Now the merge is the release. The source is public in
-[bajdev/devops](https://git.monoaf.com/bajdev/devops).
+[bajdev/devops](https://git.monoexp.com/bajdev/devops).
 
 
 ```
 ```
  PR merged in Gogs
  PR merged in Gogs

+ 1 - 1
go.mod

@@ -1,4 +1,4 @@
-module git.monoaf.com/bajdev/posts
+module git.monoexp.com/bajdev/posts
 
 
 go 1.27.3
 go 1.27.3
 
 

+ 1 - 1
main.go

@@ -188,7 +188,7 @@ func main() {
 	if port == "" {
 	if port == "" {
 		log.Fatal("PORT not set")
 		log.Fatal("PORT not set")
 	}
 	}
-	a, err := newApp(getenv("CONTENT_DIR", "content"), getenv("SITE_URL", "https://posts.monoaf.com"))
+	a, err := newApp(getenv("CONTENT_DIR", "content"), getenv("SITE_URL", "https://posts.monoexp.com"))
 	if err != nil {
 	if err != nil {
 		log.Fatal(err)
 		log.Fatal(err)
 	}
 	}

+ 1 - 1
main_test.go

@@ -325,7 +325,7 @@ func TestAboutCommitLink(t *testing.T) {
 
 
 	t.Run("clean build links the full hash", func(t *testing.T) {
 	t.Run("clean build links the full hash", func(t *testing.T) {
 		body := about(t, commitInfo{Full: full, Short: full[:7]}, "")
 		body := about(t, commitInfo{Full: full, Short: full[:7]}, "")
-		want := `<span class="muted">(<a href="https://git.monoaf.com/bajdev/posts/commit/` + full + `">d2a387e</a>)</span>`
+		want := `<span class="muted">(<a href="https://git.monoexp.com/bajdev/posts/commit/` + full + `">d2a387e</a>)</span>`
 		if !strings.Contains(body, want) {
 		if !strings.Contains(body, want) {
 			t.Errorf("missing %s in:\n%s", want, body)
 			t.Errorf("missing %s in:\n%s", want, body)
 		}
 		}

+ 2 - 2
pull-releases/010-commit-link/README.md

@@ -4,8 +4,8 @@ Branch `feature/commit-link` · version 0.5.3
 
 
 ## What changed
 ## What changed
 
 
-- **Linked hash:** the About page's build hash, e.g. `0.5.3 (d2a387e)`, now links to that commit in Gogs. The link uses the full hash: `https://git.monoaf.com/bajdev/posts/commit/<full hash>`.
-- **New `repoURL` setting:** optional, in `content/site.json`, defaulting to `https://git.monoaf.com/bajdev/posts`. Anyone running a fork of the code can point the link at their own repo.
+- **Linked hash:** the About page's build hash, e.g. `0.5.3 (d2a387e)`, now links to that commit in Gogs. The link uses the full hash: `https://git.monoexp.com/bajdev/posts/commit/<full hash>`.
+- **New `repoURL` setting:** optional, in `content/site.json`, defaulting to `https://git.monoexp.com/bajdev/posts`. Anyone running a fork of the code can point the link at their own repo.
 - **Dirty builds aren't linked.** A binary built from uncommitted changes matches no commit, so it still shows `(abc1234-dirty)` as plain text. Pipeline builds always come from a clean checkout, so the live site always has the link.
 - **Dirty builds aren't linked.** A binary built from uncommitted changes matches no commit, so it still shows `(abc1234-dirty)` as plain text. Pipeline builds always come from a clean checkout, so the live site always has the link.
 - **README:** documents `repoURL`.
 - **README:** documents `repoURL`.
 - **Version:** 0.5.3.
 - **Version:** 0.5.3.