fix(startup): add strict mongo preflight in production
This commit is contained in:
@@ -25,6 +25,7 @@
|
||||
- Preferred: set a full `MONGO_URL` (example: `mongodb://user:pass@host:27017/indiekit?authSource=admin`).
|
||||
- If `MONGO_URL` is not set, set `MONGO_USERNAME` and `MONGO_PASSWORD` explicitly; config builds the URL from `MONGO_USERNAME`, `MONGO_PASSWORD`, `MONGO_HOST`, `MONGO_PORT`, `MONGO_DATABASE`, `MONGO_AUTH_SOURCE`.
|
||||
- Startup scripts now fail fast when `MONGO_URL` is absent and `MONGO_USERNAME` is missing, to avoid silent auth mismatches.
|
||||
- Startup now runs `scripts/preflight-mongo-connection.mjs` before boot. In `NODE_ENV=production` this is strict and aborts start on Mongo auth/connect failures.
|
||||
- For `MongoServerError: Authentication failed`, first verify `MONGO_PASSWORD`, then try `MONGO_AUTH_SOURCE=admin`.
|
||||
|
||||
## Content paths
|
||||
@@ -65,7 +66,7 @@
|
||||
- `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).
|
||||
- Startup scripts parse `.env` with the `dotenv` parser (not shell `source`), so values containing spaces are handled safely.
|
||||
- Startup scripts run patch helpers before boot (`scripts/patch-lightningcss.mjs`, `scripts/patch-endpoint-media-scope.mjs`, `scripts/patch-endpoint-files-upload-route.mjs`, `scripts/patch-frontend-serviceworker-file.mjs`, `scripts/patch-conversations-collection-guards.mjs`).
|
||||
- Startup scripts run preflight + patch helpers before boot (`scripts/preflight-mongo-connection.mjs`, `scripts/patch-lightningcss.mjs`, `scripts/patch-endpoint-media-scope.mjs`, `scripts/patch-endpoint-files-upload-route.mjs`, `scripts/patch-frontend-serviceworker-file.mjs`, `scripts/patch-conversations-collection-guards.mjs`).
|
||||
- The media scope patch fixes a known upstream issue where file uploads can fail if the token scope is `create update delete` without explicit `media`.
|
||||
- The files upload route patch fixes browser multi-upload by posting to `/files/upload` (session-authenticated) instead of direct `/media` calls without bearer token.
|
||||
- The frontend serviceworker patch ensures `@indiekit/frontend/lib/serviceworker.js` exists at runtime to avoid ENOENT in the offline/service worker route.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"postinstall": "node scripts/patch-lightningcss.mjs && node scripts/patch-endpoint-media-scope.mjs && node scripts/patch-endpoint-files-upload-route.mjs && node scripts/patch-frontend-serviceworker-file.mjs && node scripts/patch-conversations-collection-guards.mjs",
|
||||
"serve": "node scripts/patch-lightningcss.mjs && node scripts/patch-endpoint-media-scope.mjs && node scripts/patch-endpoint-files-upload-route.mjs && node scripts/patch-frontend-serviceworker-file.mjs && node scripts/patch-conversations-collection-guards.mjs && node node_modules/@indiekit/indiekit/bin/cli.js serve --config indiekit.config.mjs",
|
||||
"serve": "node scripts/preflight-mongo-connection.mjs && node scripts/patch-lightningcss.mjs && node scripts/patch-endpoint-media-scope.mjs && node scripts/patch-endpoint-files-upload-route.mjs && node scripts/patch-frontend-serviceworker-file.mjs && node scripts/patch-conversations-collection-guards.mjs && node node_modules/@indiekit/indiekit/bin/cli.js serve --config indiekit.config.mjs",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
|
||||
61
scripts/preflight-mongo-connection.mjs
Normal file
61
scripts/preflight-mongo-connection.mjs
Normal file
@@ -0,0 +1,61 @@
|
||||
import { MongoClient } from "mongodb";
|
||||
|
||||
import config from "../indiekit.config.mjs";
|
||||
|
||||
const strictMode =
|
||||
process.env.REQUIRE_MONGO === "1" ||
|
||||
(process.env.REQUIRE_MONGO !== "0" && process.env.NODE_ENV === "production");
|
||||
|
||||
const hasMongoUrl = Boolean(process.env.MONGO_URL);
|
||||
const mongoUser = process.env.MONGO_USERNAME || process.env.MONGO_USER || "";
|
||||
const hasMongoPassword = Boolean(process.env.MONGO_PASSWORD);
|
||||
|
||||
if (!hasMongoUrl && (!mongoUser || !hasMongoPassword)) {
|
||||
const message =
|
||||
"[preflight] Missing Mongo credentials: set MONGO_URL or MONGO_USERNAME + MONGO_PASSWORD.";
|
||||
|
||||
if (strictMode) {
|
||||
console.error(message);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.warn(`${message} Continuing because strict mode is disabled.`);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const mongodbUrl = config.application?.mongodbUrl;
|
||||
|
||||
if (!mongodbUrl) {
|
||||
const message = "[preflight] MongoDB URL could not be resolved from configuration.";
|
||||
|
||||
if (strictMode) {
|
||||
console.error(message);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.warn(`${message} Continuing because strict mode is disabled.`);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const client = new MongoClient(mongodbUrl, { connectTimeoutMS: 5000 });
|
||||
|
||||
try {
|
||||
await client.connect();
|
||||
await client.db().command({ ping: 1 });
|
||||
console.log("[preflight] MongoDB connection OK");
|
||||
} catch (error) {
|
||||
const message = `[preflight] MongoDB connection failed: ${error.message}`;
|
||||
|
||||
if (strictMode) {
|
||||
console.error(message);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.warn(`${message} Continuing because strict mode is disabled.`);
|
||||
} finally {
|
||||
try {
|
||||
await client.close();
|
||||
} catch {
|
||||
// no-op
|
||||
}
|
||||
}
|
||||
@@ -34,6 +34,9 @@ fi
|
||||
|
||||
export NODE_ENV="${NODE_ENV:-production}"
|
||||
|
||||
# Verify MongoDB credentials/connectivity before launching server.
|
||||
/usr/local/bin/node scripts/preflight-mongo-connection.mjs
|
||||
|
||||
# Ensure runtime dependency patches are applied even if node_modules already exists.
|
||||
/usr/local/bin/node scripts/patch-lightningcss.mjs
|
||||
/usr/local/bin/node scripts/patch-endpoint-media-scope.mjs
|
||||
|
||||
Reference in New Issue
Block a user