# Server Architecture ## Infrastructure - **FreeBSD jails** — Indiekit runs in an isolated jail - **nginx** — reverse proxy; must forward `Host: blog.giersig.eu` and `X-Forwarded-Proto: https` for Fedify to construct correct canonical URLs (see `patch-ap-federation-bridge-base-url`) - **MongoDB** — `10.100.0.20:27017`, database `indiekit`, auth source `admin` - **Redis** — optional; URL via `REDIS_URL` env var; used for AP activity queue ## Publication URLs - `publicationBaseUrl` = `https://blog.giersig.eu` (from `PUBLICATION_URL` env or hardcoded default) - `applicationBaseUrl` = same (from `INDIEKIT_URL` env) - GitHub repo: `svemagie/blog`, branch `main` ## Internal Fetch Several patches rewrite outbound HTTP fetches to use internal jail addresses instead of going through the public internet / nginx: - `patch-micropub-fetch-internal-url` — Micropub post creation fetches - `patch-bluesky-syndicator-internal-url` — Bluesky syndicator - `_toInternalUrl()` helper in microsub/activitypub controllers ## Hairpin NAT — git.wildwuchs.work from inside jails **Problem:** pf's `rdr` rules only fire on `$ext_if` (vtnet0). Traffic originating from a jail (node-Jail `10.100.0.20`, gitea-Jail `10.100.0.90`) to the public IP never hits the RDR rule, so `https://git.wildwuchs.work` is unreachable from inside any jail. This breaks: - `actions/checkout@v4` in the act_runner (gitea-Jail) — can't clone the repo - `npm ci` fetching `git+https://git.wildwuchs.work/...` package dependencies (node-Jail) - `git fetch origin` in deploy scripts that use the public URL **Solution — git URL rewrite in each affected jail:** Each jail that runs git operations has a `.gitconfig` that rewrites the public URL to the internal Gitea address: ```ini [url "http://10.100.0.90:3000/"] insteadOf = https://git.wildwuchs.work/ ``` | Jail | User | `.gitconfig` path | |------|------|-------------------| | gitea-Jail (act_runner) | `git` (home: `/usr/local/git`) | `/usr/local/bastille/jails/gitea/root/usr/local/git/.gitconfig` | | node-Jail (indiekit) | `indiekit` (home: `/usr/local/indiekit`) | `/usr/local/bastille/jails/node/root/usr/local/indiekit/.gitconfig` | `/etc/hosts` in the gitea-Jail also has `10.100.0.90 git.wildwuchs.work` for DNS resolution. **If a new jail needs git access to git.wildwuchs.work:** add the same `[url]` block to the relevant user's `.gitconfig` on the host at `/usr/local/bastille/jails//root//.gitconfig`. ## Collections (MongoDB) | Collection | Contents | |------------|----------| | `posts` | Micropub post data (path + properties) | | `ap_timeline` | Incoming + outgoing AP posts; key: `uid` | | `ap_notifications` | Mentions, replies, likes, boosts received | | `ap_followers` | Follower actor URLs | | `ap_following` | Following actor URLs | | `ap_activities` | Activity log (outbound + inbound) | | `ap_profile` | Own actor profile (name, icon, url) | | `ap_interactions` | Likes and boosts performed by own account | ## ActivityPub Actor - Handle: `activityPubHandle` from `AP_HANDLE` env → `GITHUB_USERNAME` (`svemagie`) → hostname prefix - Full handle: `@svemagie@blog.giersig.eu` - Actor URL: `https://blog.giersig.eu/activitypub/actor` - AP objects served at: `https://blog.giersig.eu/activitypub/objects/note/{+id}` - Own reply posts: `/activitypub/objects/note/replies/{slug}` ## Patch Infrastructure Patches live in `scripts/patch-*.mjs`. Each script: 1. Checks if already applied (MARKER string) 2. Looks for OLD_SNIPPET in node_modules target file 3. Replaces with NEW_SNIPPET if found 4. Reports result to stdout Both `postinstall` and `serve` scripts in `package.json` run all patches in order. Some patches (e.g. `patch-microsub-reader-ap-dispatch`) only appear in `serve`, not `postinstall`. New AP patches are appended at the end of the AP patch chain (after `patch-ap-federation-bridge-base-url`).