fix: update Gitea org giersig.eu → svemagie.net, blog.giersig.eu → svemagie.net in docs + CLAUDE.md
Deploy Indiekit Server / deploy (push) Failing after 5s

This commit is contained in:
Sven
2026-05-14 19:56:33 +02:00
parent e0a48dc787
commit 30737fbb39
3 changed files with 34 additions and 34 deletions
+1 -1
View File
@@ -24,7 +24,7 @@ jobs:
restart_log=/tmp/indiekit-restart.log restart_log=/tmp/indiekit-restart.log
# Update code as indiekit user; point remote at internal Gitea (no auth needed — public read). # Update code as indiekit user; point remote at internal Gitea (no auth needed — public read).
doas bastille cmd node sh -lc 'su -l indiekit -c "cd /usr/local/indiekit && git remote set-url origin https://git.wildwuchs.work/giersig.eu/indiekit-server.git && git fetch origin && git reset --hard origin/main"' doas bastille cmd node sh -lc 'su -l indiekit -c "cd /usr/local/indiekit && git remote set-url origin https://git.wildwuchs.work/svemagie.net/indiekit-server.git && git fetch origin && git reset --hard origin/main"'
# Install dependencies (postinstall runs all patches automatically). # Install dependencies (postinstall runs all patches automatically).
doas bastille cmd node sh -lc 'su -l indiekit -c "cd /usr/local/indiekit && npm ci --legacy-peer-deps"' doas bastille cmd node sh -lc 'su -l indiekit -c "cd /usr/local/indiekit && npm ci --legacy-peer-deps"'
+7 -7
View File
@@ -1,6 +1,6 @@
# CLAUDE.md — indiekit-blog # CLAUDE.md — indiekit-blog
Personal [Indiekit](https://getindiekit.com/) deployment for [blog.giersig.eu](https://blog.giersig.eu). Personal [Indiekit](https://getindiekit.com/) deployment for [svemagie.net](https://svemagie.net).
## Always read memory files first ## Always read memory files first
@@ -63,7 +63,7 @@ The node jail **cannot reach its own public HTTPS URL**. Internal self-fetches m
### nginx / Fedify ### nginx / Fedify
nginx must forward `Host: blog.giersig.eu` and `X-Forwarded-Proto: https` or AP lookups 302-redirect to the login page. See `patch-ap-federation-bridge-base-url`. nginx must forward `Host: svemagie.net` and `X-Forwarded-Proto: https` or AP lookups 302-redirect to the login page. See `patch-ap-federation-bridge-base-url`.
`createFederation()` requires `allowPrivateAddress: true` (blog resolves to a LAN IP) and `signatureTimeWindow: { hours: 12 }` (Mastodon retries with old signatures). `createFederation()` requires `allowPrivateAddress: true` (blog resolves to a LAN IP) and `signatureTimeWindow: { hours: 12 }` (Mastodon retries with old signatures).
@@ -182,7 +182,7 @@ npm install git+https://git.wildwuchs.work/svemagie/indiekit-endpoint-activitypu
| Favourited/reblogged state wrong on account statuses timeline | `accounts.js` added `ix.objectUrl` to the Sets instead of `item.uid` — fixed by `patch-ap-interactions-accounts-uid` | | Favourited/reblogged state wrong on account statuses timeline | `accounts.js` added `ix.objectUrl` to the Sets instead of `item.uid` — fixed by `patch-ap-interactions-accounts-uid` |
| Liked posts show as not-liked in thread context (ancestors/descendants) | Context endpoint used empty interaction Sets — fixed by `patch-ap-interactions-context-state` | | Liked posts show as not-liked in thread context (ancestors/descendants) | Context endpoint used empty interaction Sets — fixed by `patch-ap-interactions-context-state` |
| "Empty reply from server" on webmention poller | Poller routing through nginx (returns 444 for wrong Host) — must use `INDIEKIT_DIRECT_URL` | | "Empty reply from server" on webmention poller | Poller routing through nginx (returns 444 for wrong Host) — must use `INDIEKIT_DIRECT_URL` |
| HTTP Signature 401 errors on all inbound activities | nginx forwarding wrong `Host` header — fixed by `patch-ap-signature-host-header` (overrides to `blog.giersig.eu`) | | HTTP Signature 401 errors on all inbound activities | nginx forwarding wrong `Host` header — fixed by `patch-ap-signature-host-header` (overrides to `svemagie.net`) |
| HTTP Signature verify errors flooding logs for deleted/migrated actors | Expected noise — `patch-ap-inbox-delivery-debug` (in `patch-ap-federation-infra.mjs`) suppresses both `["fedify","federation","inbox"]` and `["fedify","runtime","docloader"]` to `lowestLevel: "fatal"`. Current marker: `ap-inbox-delivery-debug-A-fatal` | | HTTP Signature verify errors flooding logs for deleted/migrated actors | Expected noise — `patch-ap-inbox-delivery-debug` (in `patch-ap-federation-infra.mjs`) suppresses both `["fedify","federation","inbox"]` and `["fedify","runtime","docloader"]` to `lowestLevel: "fatal"`. Current marker: `ap-inbox-delivery-debug-A-fatal` |
| Mastodon client (Phanpy, etc.) gets 401 on all authenticated endpoints ~10 min after login | OAuth access token inherited the auth code's 10-min `expiresAt` — fixed by `patch-ap-oauth-token-expiry-fix` (`$unset: { expiresAt }` during code exchange) | | Mastodon client (Phanpy, etc.) gets 401 on all authenticated endpoints ~10 min after login | OAuth access token inherited the auth code's 10-min `expiresAt` — fixed by `patch-ap-oauth-token-expiry-fix` (`$unset: { expiresAt }` during code exchange) |
| Mastodon client gets 401 on all requests immediately (not just after 10 min) | "Autorisiertes Abrufen erfordern" (authorized fetch / secure mode) is enabled — unsigned GET requests to actor/collections are rejected. Error message "access token is invalid" is misleading; it comes from the authorized-fetch layer, not OAuth. Fix: disable authorized fetch in AP admin settings. Trade-off: blocked servers can still fetch public posts, but this is acceptable for a public blog. | | Mastodon client gets 401 on all requests immediately (not just after 10 min) | "Autorisiertes Abrufen erfordern" (authorized fetch / secure mode) is enabled — unsigned GET requests to actor/collections are rejected. Error message "access token is invalid" is misleading; it comes from the authorized-fetch layer, not OAuth. Fix: disable authorized fetch in AP admin settings. Trade-off: blocked servers can still fetch public posts, but this is acceptable for a public blog. |
@@ -229,16 +229,16 @@ npm install git+https://git.wildwuchs.work/svemagie/indiekit-endpoint-activitypu
**`GITEA_BASE_URL`** must end with a trailing slash: `http://10.100.0.90:3000/api/v1/` **`GITEA_BASE_URL`** must end with a trailing slash: `http://10.100.0.90:3000/api/v1/`
Without it, `new URL(apiPath, baseUrl)` silently strips the `v1` segment → 404 on all writes. Without it, `new URL(apiPath, baseUrl)` silently strips the `v1` segment → 404 on all writes.
**`GH_CONTENT_TOKEN`** — the Gitea PAT for `svemagie`. `start.sh` rejects startup if neither `GH_CONTENT_TOKEN` nor `GITHUB_TOKEN` is present. The token must have repo read/write scope on `giersig.eu/indiekit-blog`. **`GH_CONTENT_TOKEN`** — the Gitea PAT for `svemagie`. `start.sh` rejects startup if neither `GH_CONTENT_TOKEN` nor `GITHUB_TOKEN` is present. The token must have repo read/write scope on `svemagie.net/indiekit-blog`.
**`GITEA_CONTENT_USER`** = `giersig.eu` (the org, not the personal username) **`GITEA_CONTENT_USER` = `svemagie.net` (the org, not the personal username)
**`GITEA_CONTENT_REPO`** = `indiekit-blog` **`GITEA_CONTENT_REPO`** = `indiekit-blog`
--- ---
## Micropub → Gitea build dispatch ## Micropub → Gitea build dispatch
Gitea Contents API commits (what `store-github` does) do **not** trigger `on: push` CI workflows. `patch-micropub-gitea-dispatch-conditional.mjs` patches the Micropub endpoint to fire a `workflow_dispatch` event to `giersig.eu/indiekit-blog` after each create/update, so the blog rebuilds immediately after a post is published. Gitea Contents API commits (what `store-github` does) do **not** trigger `on: push` CI workflows. `patch-micropub-gitea-dispatch-conditional.mjs` patches the Micropub endpoint to fire a `workflow_dispatch` event to `svemagie.net/indiekit-blog` after each create/update, so the blog rebuilds immediately after a post is published.
--- ---
@@ -251,7 +251,7 @@ python3 << 'PYEOF'
import urllib.request, json, base64 import urllib.request, json, base64
TOKEN = "your-gitea-pat" TOKEN = "your-gitea-pat"
REPO = "giersig.eu/indiekit-blog" REPO = "svemagie.net/indiekit-blog"
PATH = ".github/workflows/deploy.yml" PATH = ".github/workflows/deploy.yml"
BASE = "http://10.100.0.90:3000/api/v1" BASE = "http://10.100.0.90:3000/api/v1"
+26 -26
View File
@@ -25,16 +25,16 @@ In `package.json` these use the `git+https://git.wildwuchs.work/svemagie/repo` s
## ActivityPub federation ## ActivityPub federation
The blog is a native ActivityPub actor (`@svemagie@blog.giersig.eu`) powered by [Fedify](https://fedify.dev/) v2.1.0 via the `@rmdes/indiekit-endpoint-activitypub` package. All federation routes are mounted at `/activitypub`. The blog is a native ActivityPub actor (`@svemagie@svemagie.net`) powered by [Fedify](https://fedify.dev/) v2.1.0 via the `@rmdes/indiekit-endpoint-activitypub` package. All federation routes are mounted at `/activitypub`.
### Actor identity ### Actor identity
| Field | Value | | Field | Value |
|---|---| |---|---|
| Handle | `svemagie` (`AP_HANDLE` env var) | | Handle | `svemagie` (`AP_HANDLE` env var) |
| Actor URL | `https://blog.giersig.eu/activitypub/users/svemagie` | | Actor URL | `https://svemagie.net/activitypub/users/svemagie` |
| Actor type | `Person` | | Actor type | `Person` |
| WebFinger | `acct:svemagie@blog.giersig.eu` | | WebFinger | `acct:svemagie@svemagie.net` |
| Migration alias | `https://troet.cafe/users/svemagie` (`AP_ALSO_KNOWN_AS`) | | Migration alias | `https://troet.cafe/users/svemagie` (`AP_ALSO_KNOWN_AS`) |
### Key management ### Key management
@@ -89,7 +89,7 @@ createFederation({
``` ```
- **`signatureTimeWindow: { hours: 12 }`** — Mastodon retries failed deliveries with the original signature, which can be hours old. Without this, retries are rejected. - **`signatureTimeWindow: { hours: 12 }`** — Mastodon retries failed deliveries with the original signature, which can be hours old. Without this, retries are rejected.
- **`allowPrivateAddress: true`** — blog.giersig.eu resolves to a private IP (10.100.0.10) on the home LAN. Without this, Fedify's SSRF guard blocks WebFinger and `lookupObject()` for own-site URLs, breaking federation. - **`allowPrivateAddress: true`** — svemagie.net resolves to a private IP (10.100.0.10) on the home LAN. Without this, Fedify's SSRF guard blocks WebFinger and `lookupObject()` for own-site URLs, breaking federation.
### Inbox handling ### Inbox handling
@@ -189,7 +189,7 @@ The patch replaces the broken date-from-URL regex with a simple last-path-segmen
### Troubleshooting ### Troubleshooting
**All inbound AP activities return 401 / remote servers stop delivering** **All inbound AP activities return 401 / remote servers stop delivering**
The root cause is usually the `host` header being forwarded as the nginx upstream IP instead of the canonical `blog.giersig.eu`. Fedify includes `host` in the signed-string for Cavage HTTP Signatures; if it doesn't match what the remote server signed, every inbox POST fails verification. Fixed by `patch-ap-signature-host-header`: overrides `"host"` with `new URL(publicationUrl).host` in `fromExpressRequest()` after copying headers from the Express request. The root cause is usually the `host` header being forwarded as the nginx upstream IP instead of the canonical `svemagie.net`. Fedify includes `host` in the signed-string for Cavage HTTP Signatures; if it doesn't match what the remote server signed, every inbox POST fails verification. Fixed by `patch-ap-signature-host-header`: overrides `"host"` with `new URL(publicationUrl).host` in `fromExpressRequest()` after copying headers from the Express request.
**`ERR fedify·federation·inbox Failed to verify the request's HTTP Signatures`** **`ERR fedify·federation·inbox Failed to verify the request's HTTP Signatures`**
At low volume this is expected (deleted actors, migrated servers with stale keys). `patch-ap-inbox-delivery-debug` changes the log level for `["fedify","federation","inbox"]` from `"fatal"` to `"error"` so real delivery failures are visible. If you see it flooding, the most common cause is the `host` header mismatch above — check that `patch-ap-signature-host-header` is applied. The body buffering patch must also preserve raw bytes in `req._rawBody` — if `JSON.stringify(req.body)` is used instead, the Digest header won't match. At low volume this is expected (deleted actors, migrated servers with stale keys). `patch-ap-inbox-delivery-debug` changes the log level for `["fedify","federation","inbox"]` from `"fatal"` to `"error"` so real delivery failures are visible. If you see it flooding, the most common cause is the `host` header mismatch above — check that `patch-ap-signature-host-header` is applied. The body buffering patch must also preserve raw bytes in `req._rawBody` — if `JSON.stringify(req.body)` is used instead, the Digest header won't match.
@@ -344,7 +344,7 @@ Like posts are created as **drafts** (`post-status: draft` → `draft: true` in
The YouTube Data API requires OAuth 2.0 (not just an API key) to access a user's liked videos. The YouTube Data API requires OAuth 2.0 (not just an API key) to access a user's liked videos.
1. Create an **OAuth 2.0 Client ID** (Web application) in [Google Cloud Console](https://console.cloud.google.com/apis/credentials) 1. Create an **OAuth 2.0 Client ID** (Web application) in [Google Cloud Console](https://console.cloud.google.com/apis/credentials)
2. Add authorized redirect URI: `https://blog.giersig.eu/youtube/likes/callback` 2. Add authorized redirect URI: `https://svemagie.net/youtube/likes/callback`
3. Ensure **YouTube Data API v3** is enabled for the project 3. Ensure **YouTube Data API v3** is enabled for the project
4. Set environment variables: 4. Set environment variables:
@@ -444,7 +444,7 @@ Two bugs in the Mastodon API delete route. Bug 1 (ReferenceError): the route use
The LogTape logger for `["fedify","federation","inbox"]` was hardcoded to `"fatal"` in `federation-setup.js`, suppressing all inbox errors including genuine delivery failures. Fix: changes the log level to `"error"` so real failures are visible. Expected noise from deleted/migrated actors (whose keys no longer resolve) still floods at `"error"` but can be filtered at the log aggregator level. The LogTape logger for `["fedify","federation","inbox"]` was hardcoded to `"fatal"` in `federation-setup.js`, suppressing all inbox errors including genuine delivery failures. Fix: changes the log level to `"error"` so real failures are visible. Expected noise from deleted/migrated actors (whose keys no longer resolve) still floods at `"error"` but can be filtered at the log aggregator level.
**`patch-ap-signature-host-header.mjs`** **`patch-ap-signature-host-header.mjs`**
`patch-ap-federation-bridge-base-url` fixed Fedify URL routing to use the canonical `publicationUrl`, but left the `host` header in the copied Headers object untouched. nginx forwards an internal host (e.g. `10.100.0.20`) which Fedify reads from `request.headers.get("host")` when reconstructing the signed-string for Cavage HTTP Signatures. Signed-string mismatch → every inbox POST returns 401 → remote servers exhaust retries and stop delivering. Fix: after the header-copy loop in `fromExpressRequest()`, overrides `"host"` with `new URL(publicationUrl).host` (`"blog.giersig.eu"`) when `publicationUrl` is provided. `patch-ap-federation-bridge-base-url` fixed Fedify URL routing to use the canonical `publicationUrl`, but left the `host` header in the copied Headers object untouched. nginx forwards an internal host (e.g. `10.100.0.20`) which Fedify reads from `request.headers.get("host")` when reconstructing the signed-string for Cavage HTTP Signatures. Signed-string mismatch → every inbox POST returns 401 → remote servers exhaust retries and stop delivering. Fix: after the header-copy loop in `fromExpressRequest()`, overrides `"host"` with `new URL(publicationUrl).host` (`"svemagie.net"`) when `publicationUrl` is provided.
### Conversations ### Conversations
@@ -510,7 +510,7 @@ Adds AI disclosure field UI (text level, code level, etc.) to the post creation/
Removes AI disclosure fields from the post form submission before saving, delegating persistence to the AI block sidecar system. Removes AI disclosure fields from the post form submission before saving, delegating persistence to the AI block sidecar system.
**`patch-endpoint-posts-fetch-diagnostic.mjs`** **`patch-endpoint-posts-fetch-diagnostic.mjs`**
In the two-jail setup the node jail cannot reach `https://blog.giersig.eu` directly; self-referential fetches in `@indiekit/endpoint-posts` fail with `ECONNREFUSED`. Fix: rewrites self-referential fetch URLs to `http://localhost:<PORT>` using `INTERNAL_FETCH_URL` (or an automatic fallback), and wraps the fetch in a try-catch that logs the URL and response status on failure to make networking problems easier to diagnose. In the two-jail setup the node jail cannot reach `https://svemagie.net` directly; self-referential fetches in `@indiekit/endpoint-posts` fail with `ECONNREFUSED`. Fix: rewrites self-referential fetch URLs to `http://localhost:<PORT>` using `INTERNAL_FETCH_URL` (or an automatic fallback), and wraps the fetch in a try-catch that logs the URL and response status on failure to make networking problems easier to diagnose.
**`patch-endpoint-posts-uid-lookup.mjs`** **`patch-endpoint-posts-uid-lookup.mjs`**
Fixes post editing 404s by adding `uid`-based lookup to the micropub source query. Without this, posts older than the first 40 results could not be opened for editing. Fixes post editing 404s by adding `uid`-based lookup to the micropub source query. Without this, posts older than the first 40 results could not be opened for editing.
@@ -645,7 +645,7 @@ The production setup uses two FreeBSD jails managed by [Bastille](https://bastil
### Internal fetch URL ### Internal fetch URL
The node jail cannot reach the public HTTPS URL (`https://blog.giersig.eu`) because TLS terminates on the web jail. Several features need to fetch their own pages or static assets: The node jail cannot reach the public HTTPS URL (`https://svemagie.net`) because TLS terminates on the web jail. Several features need to fetch their own pages or static assets:
- **Webmention sender** — fetches live page HTML for link extraction - **Webmention sender** — fetches live page HTML for link extraction
- **Bluesky syndicator** — fetches photos for upload, OG metadata/images for link cards - **Bluesky syndicator** — fetches photos for upload, OG metadata/images for link cards
@@ -657,9 +657,9 @@ All of these use a shared `_toInternalUrl()` helper (injected by patch scripts)
INTERNAL_FETCH_URL=http://10.100.0.20:3000 INTERNAL_FETCH_URL=http://10.100.0.20:3000
``` ```
**Why not nginx (`http://10.100.0.10`)?** nginx's HTTP/80 listener for `blog.giersig.eu` returns a `301` redirect to `https://`. Node's fetch follows the redirect to the public HTTPS URL, which the node jail cannot reach: pf's `rdr` rule only fires on the external interface (`vtnet0`), so there is no hairpin NAT for jail-originated traffic. The result is `UND_ERR_SOCKET: other side closed` on every internal POST (editing posts, syndication, token introspection). **Why not nginx (`http://10.100.0.10`)?** nginx's HTTP/80 listener for `svemagie.net` returns a `301` redirect to `https://`. Node's fetch follows the redirect to the public HTTPS URL, which the node jail cannot reach: pf's `rdr` rule only fires on the external interface (`vtnet0`), so there is no hairpin NAT for jail-originated traffic. The result is `UND_ERR_SOCKET: other side closed` on every internal POST (editing posts, syndication, token introspection).
### nginx configuration (`/usr/local/etc/nginx/sites/blog.giersig.eu.conf`) ### nginx configuration (`/usr/local/etc/nginx/sites/svemagie.net.conf`)
The full vhost config lives in the web jail. Key design points: The full vhost config lives in the web jail. Key design points:
@@ -681,11 +681,11 @@ map $http_accept $is_activitypub {
# Passes responses through unmodified — no error interception. # Passes responses through unmodified — no error interception.
server { server {
listen 10.100.0.10:80; listen 10.100.0.10:80;
server_name blog.giersig.eu; server_name svemagie.net;
# Hardcode Host so Indiekit sees the real domain, not the jail IP. # Hardcode Host so Indiekit sees the real domain, not the jail IP.
# X-Forwarded-Proto https prevents force-https from redirecting. # X-Forwarded-Proto https prevents force-https from redirecting.
proxy_set_header Host blog.giersig.eu; proxy_set_header Host svemagie.net;
proxy_set_header X-Forwarded-Proto https; proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
@@ -698,27 +698,27 @@ server {
} }
} }
# ── 2. HTTP: giersig.eu + www → blog.giersig.eu ───────────────────────────── # ── 2. HTTP: giersig.eu + www → svemagie.net ─────────────────────────────
server { server {
listen 80; listen 80;
server_name giersig.eu www.giersig.eu; server_name giersig.eu www.giersig.eu;
return 301 https://blog.giersig.eu$request_uri; return 301 https://svemagie.net$request_uri;
} }
# ── 3. HTTP: blog.giersig.eu (ACME challenge + HTTPS redirect) ────────────── # ── 3. HTTP: svemagie.net (ACME challenge + HTTPS redirect) ──────────────
server { server {
listen 80; listen 80;
server_name blog.giersig.eu; server_name svemagie.net;
location /.well-known/acme-challenge/ { location /.well-known/acme-challenge/ {
root /usr/local/www/letsencrypt; root /usr/local/www/letsencrypt;
} }
location / { location / {
return 301 https://blog.giersig.eu$request_uri; return 301 https://svemagie.net$request_uri;
} }
} }
# ── 4. HTTPS: giersig.eu + www → blog.giersig.eu ──────────────────────────── # ── 4. HTTPS: giersig.eu + www → svemagie.net ────────────────────────────
server { server {
listen 443 ssl; listen 443 ssl;
server_name giersig.eu www.giersig.eu; server_name giersig.eu www.giersig.eu;
@@ -726,16 +726,16 @@ server {
ssl_certificate_key /usr/local/etc/letsencrypt/live/giersig.eu/privkey.pem; ssl_certificate_key /usr/local/etc/letsencrypt/live/giersig.eu/privkey.pem;
include /usr/local/etc/letsencrypt/options-ssl-nginx.conf; include /usr/local/etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /usr/local/etc/letsencrypt/ssl-dhparams.pem; ssl_dhparam /usr/local/etc/letsencrypt/ssl-dhparams.pem;
return 301 https://blog.giersig.eu$request_uri; return 301 https://svemagie.net$request_uri;
} }
# ── 5. HTTPS: blog.giersig.eu (main) ──────────────────────────────────────── # ── 5. HTTPS: svemagie.net (main) ────────────────────────────────────────
server { server {
listen 443 ssl; listen 443 ssl;
http2 on; http2 on;
server_name blog.giersig.eu; server_name svemagie.net;
ssl_certificate /usr/local/etc/letsencrypt/live/blog.giersig.eu/fullchain.pem; ssl_certificate /usr/local/etc/letsencrypt/live/svemagie.net/fullchain.pem;
ssl_certificate_key /usr/local/etc/letsencrypt/live/blog.giersig.eu/privkey.pem; ssl_certificate_key /usr/local/etc/letsencrypt/live/svemagie.net/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3; ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off; ssl_prefer_server_ciphers off;
@@ -822,7 +822,7 @@ Environment variables are loaded from `.env` via `dotenv`. Copy `.env.example` t
| Variable | Default | Purpose | | Variable | Default | Purpose |
|---|---|---| |---|---|---|
| `PUBLICATION_URL` | `https://blog.giersig.eu` | Canonical blog URL | | `PUBLICATION_URL` | `https://svemagie.net` | Canonical blog URL |
| `INDIEKIT_URL` | same as `PUBLICATION_URL` | Application base URL | | `INDIEKIT_URL` | same as `PUBLICATION_URL` | Application base URL |
| `REDIS_URL` | — | Redis for AP message queue + KV store (production-required for persistence) | | `REDIS_URL` | — | Redis for AP message queue + KV store (production-required for persistence) |
| `INTERNAL_FETCH_URL` | `http://localhost:PORT` | Direct Indiekit URL for self-fetches, bypassing nginx | | `INTERNAL_FETCH_URL` | `http://localhost:PORT` | Direct Indiekit URL for self-fetches, bypassing nginx |
@@ -1074,7 +1074,7 @@ Also bumped `@rmdes/indiekit-endpoint-posts` beta.25→beta.44 and removed `came
**fix(webmention): livefetch evolution v3→v5** (`11d600058`, `7f9f02bc3`, `17b93b3a2`) **fix(webmention): livefetch evolution v3→v5** (`11d600058`, `7f9f02bc3`, `17b93b3a2`)
Three successive fixes to the webmention sender livefetch patch, driven by split-DNS and jail networking constraints: Three successive fixes to the webmention sender livefetch patch, driven by split-DNS and jail networking constraints:
- **v3** (`11d600058`): Send `Host: blog.giersig.eu` on internal fetches so nginx routes to the correct vhost; add `fetchUrl` diagnostics and response body preview on h-entry check failure - **v3** (`11d600058`): Send `Host: svemagie.net` on internal fetches so nginx routes to the correct vhost; add `fetchUrl` diagnostics and response body preview on h-entry check failure
- **v4** (`7f9f02bc3`): Remove `INTERNAL_FETCH_URL` rewrite for live page fetches — post URLs require authentication on the internal nginx vhost (returns login page). Fetch from `postUrl` (public URL) directly. Add `WEBMENTION_LIVEFETCH_URL` as an opt-in override - **v4** (`7f9f02bc3`): Remove `INTERNAL_FETCH_URL` rewrite for live page fetches — post URLs require authentication on the internal nginx vhost (returns login page). Fetch from `postUrl` (public URL) directly. Add `WEBMENTION_LIVEFETCH_URL` as an opt-in override
- **v5** (`17b93b3a2`): Replace live page fetch entirely with a synthetic h-entry HTML snippet built from `post.properties` stored in MongoDB (`in-reply-to`, `like-of`, `bookmark-of`, `repost-of`, `content.html`). No network fetch required — eliminates all split-DNS / auth reliability issues - **v5** (`17b93b3a2`): Replace live page fetch entirely with a synthetic h-entry HTML snippet built from `post.properties` stored in MongoDB (`in-reply-to`, `like-of`, `bookmark-of`, `repost-of`, `content.html`). No network fetch required — eliminates all split-DNS / auth reliability issues