diff --git a/README.md b/README.md index 4567c8a0..cd1593c9 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,16 @@ - Post management UI should use `/posts` (`@indiekit/endpoint-posts.mountPath`). - Do not set post-management `mountPath` to frontend routes like `/blog`, otherwise backend publishing can be shadowed by the public site. +## Backend endpoints + +- Configured endpoint mount paths: +- Posts management: `/posts` +- Files: `/files` +- Webmentions moderation + API: `/webmentions` +- Conversations + API: `/conversations` +- GitHub activity + API: `/github` +- If IndieKit is reverse-proxied behind `/admin`, these become `/admin/posts`, `/admin/files`, etc. + ## MongoDB - Preferred: set a full `MONGO_URL` (example: `mongodb://user:pass@host:27017/indiekit?authSource=admin`). @@ -46,4 +56,9 @@ - `GH_CONTENT_TOKEN`: token for content repo (`blog`), used by `@indiekit/store-github`. - `GH_ACTIVITY_TOKEN`: token for GitHub dashboard/activity endpoint, used by `@rmdes/indiekit-endpoint-github`. - `GITHUB_USERNAME`: GitHub user/owner name. -- Backward compatibility: if `GH_CONTENT_TOKEN` or `GH_ACTIVITY_TOKEN` are not set, config falls back to `GITHUB_TOKEN`. \ No newline at end of file +- Backward compatibility: if `GH_CONTENT_TOKEN` or `GH_ACTIVITY_TOKEN` are not set, config falls back to `GITHUB_TOKEN`. + +## Startup script + +- `start.sh` is intentionally ignored by Git (`.gitignore`) so server secrets are not committed. +- Use `start.example.sh` as the tracked template and keep real credentials in environment variables (or `.env` on the server). \ No newline at end of file diff --git a/custom-server.js b/custom-server.js index b8f4fc2f..d9a64270 100644 --- a/custom-server.js +++ b/custom-server.js @@ -1,2 +1,15 @@ -require('dotenv').config(); -require('indiekit').serve(); +require("dotenv/config"); +const { spawn } = require("child_process"); + +const args = [ + require.resolve("@indiekit/indiekit/bin/cli.js"), + "serve", + "--config", + "indiekit.config.mjs", +]; + +const child = spawn(process.execPath, args, { stdio: "inherit" }); + +child.on("exit", (code) => { + process.exit(code ?? 1); +}); diff --git a/indiekit.config.mjs b/indiekit.config.mjs index 532f6848..09ac281e 100644 --- a/indiekit.config.mjs +++ b/indiekit.config.mjs @@ -27,6 +27,18 @@ const githubContentToken = process.env.GH_CONTENT_TOKEN || process.env.GITHUB_TOKEN; const githubActivityToken = process.env.GH_ACTIVITY_TOKEN || process.env.GITHUB_TOKEN; +const publicationBaseUrl = ( + process.env.PUBLICATION_URL || "https://blog.giersig.eu" +).replace(/\/+$/, ""); + +let webmentionDomain = process.env.WEBMENTION_IO_DOMAIN; +if (!webmentionDomain) { + try { + webmentionDomain = new URL(publicationBaseUrl).hostname; + } catch { + webmentionDomain = "blog.giersig.eu"; + } +} export default { debug: "indiekit:*", @@ -35,55 +47,55 @@ export default { mongodbUrl: mongoUrl, }, publication: { - me: "https://blog.giersig.eu", + me: publicationBaseUrl, postTypes: { article: { name: "Artikel", post: { path: "content/articles/{slug}.md", - url: "https://blog.giersig.eu/articles/{slug}/", + url: `${publicationBaseUrl}/articles/{slug}/`, }, }, note: { name: "Notiz", post: { path: "content/notes/{slug}.md", - url: "https://blog.giersig.eu/notes/{slug}/", + url: `${publicationBaseUrl}/notes/{slug}/`, }, }, bookmark: { name: "Lesezeichen", post: { path: "content/bookmarks/{slug}.md", - url: "https://blog.giersig.eu/bookmarks/{slug}/", + url: `${publicationBaseUrl}/bookmarks/{slug}/`, }, }, like: { name: "Like", post: { path: "content/likes/{slug}.md", - url: "https://blog.giersig.eu/likes/{slug}/", + url: `${publicationBaseUrl}/likes/{slug}/`, }, }, photo: { name: "Foto", post: { path: "content/photos/{slug}.md", - url: "https://blog.giersig.eu/photos/{slug}/", + url: `${publicationBaseUrl}/photos/{slug}/`, }, }, reply: { name: "Antwort", post: { path: "content/replies/{slug}.md", - url: "https://blog.giersig.eu/replies/{slug}/", + url: `${publicationBaseUrl}/replies/{slug}/`, }, }, page: { name: "Seite", post: { path: "content/pages/{slug}.md", - url: "https://blog.giersig.eu/{slug}/", + url: `${publicationBaseUrl}/{slug}/`, }, }, }, @@ -113,6 +125,7 @@ export default { }, "@rmdes/indiekit-endpoint-webmention-io": { token: process.env.WEBMENTION_IO_TOKEN, + domain: webmentionDomain, }, "@rmdes/indiekit-endpoint-conversations": { mountPath: "/conversations", diff --git a/start.example.sh b/start.example.sh new file mode 100644 index 00000000..b097585c --- /dev/null +++ b/start.example.sh @@ -0,0 +1,30 @@ +#!/bin/sh +set -eu + +cd /usr/local/indiekit + +# Optional: load environment from local .env file. +if [ -f .env ]; then + set -a + . ./.env + set +a +fi + +: "${SECRET:?SECRET is required}" +: "${PASSWORD_SECRET:?PASSWORD_SECRET is required}" + +# Allow either full Mongo URL or decomposed credentials. +if [ -z "${MONGO_URL:-}" ]; then + : "${MONGO_PASSWORD:?MONGO_PASSWORD is required when MONGO_URL is not set}" + export MONGO_USERNAME="${MONGO_USERNAME:-indiekit}" + export MONGO_AUTH_SOURCE="${MONGO_AUTH_SOURCE:-admin}" +fi + +if [ -z "${GH_CONTENT_TOKEN:-}" ] && [ -z "${GITHUB_TOKEN:-}" ]; then + echo "GH_CONTENT_TOKEN or GITHUB_TOKEN is required" >&2 + exit 1 +fi + +export NODE_ENV="${NODE_ENV:-production}" + +exec /usr/local/bin/node node_modules/@indiekit/indiekit/bin/cli.js serve --config indiekit.config.mjs