From 0fd5eb5821210020d0a59bb945f84bfb4fa78ecc Mon Sep 17 00:00:00 2001
From: Guanzhou Song
Date: Mon, 24 Aug 2026 16:16:57 -0400
Subject: [PATCH 1/3] Show the v0.116-0 package layout across the site
The package repository now serves the multi-package layout, but the site still
described the world before it. /packages hardcoded 0.114-0 (and 0.113-0 for the
repository examples), generated an extension-only install command for every
target, and stated that "the published package repository does not currently
include a gateway package, setup helper, or systemd service" -- which stopped
being true for Ubuntu 24.04 and RHEL 9. The Linux Packages Quick Start presented
building the gateway from Rust source as the only route to an endpoint.
Read the version from the release feed instead of repeating it. The deployment
already publishes packages/release-info.json describing the release it mirrors,
and nothing consumed it; that is why the page went stale in the first place. The
new module derives the DEB, RPM and meta-package versions from real asset
filenames, so the page cannot advertise a shape the release does not contain,
and falls back to a compiled-in release when the feed is unreachable so the
install commands are never blank.
Generate the install command per target. Tier-1 targets resolve the per-major
stand-alone, which pulls the extension, gateway, tools and documentdb-common;
everywhere else keeps the extension command, because offering `documentdb-N`
there would be an install command that cannot resolve. PostgreSQL 16 stays on
the extension command even on Tier-1, since v0.116-0 narrowed the stack to
PostgreSQL 17 and 18 and 16 resolves the older build.
Default the selector to Ubuntu 24.04 + PostgreSQL 18. It is the target the
release is built and end-to-end tested against; defaulting to Ubuntu 22.04 and
PostgreSQL 16 showed first-time visitors the extension-only experience.
Document what the packages actually do: the five package roles, the
documentdb-setup wizard (including that it prompts for a password, so servers
need --admin-password-stdin --yes), connecting with mongosh, verification, the
per-major systemd unit names, logs and ports, upgrading, and removal. Also warn
that the gateway binds all interfaces by default while the connect example says
127.0.0.1, and how to restrict it.
Add a drift check so this cannot silently rot again: when a deployment mirrors a
release, the fallback compiled into the bundle must name the same one.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 8df9084a-ccaf-432c-b015-2ccd8893a9d8
---
.github/scripts/check_release_drift.js | 109 ++++++++++++++
.github/workflows/continuous-deployment.yml | 3 +
app/lib/packageInstall.ts | 52 ++++++-
app/lib/releaseInfo.ts | 142 ++++++++++++++++++
app/packages/page.tsx | 152 ++++++++++++++++----
app/services/articleService.ts | 151 +++++++++++++++----
tests/packageInstall.test.ts | 37 ++++-
7 files changed, 581 insertions(+), 65 deletions(-)
create mode 100644 .github/scripts/check_release_drift.js
create mode 100644 app/lib/releaseInfo.ts
diff --git a/.github/scripts/check_release_drift.js b/.github/scripts/check_release_drift.js
new file mode 100644
index 0000000..fb4e29e
--- /dev/null
+++ b/.github/scripts/check_release_drift.js
@@ -0,0 +1,109 @@
+#!/usr/bin/env node
+/**
+ * Fails the build when the site's fallback release drifts from the release the
+ * package repository actually mirrors.
+ *
+ * The /packages page used to hardcode its versions, and they went stale: the
+ * page still advertised 0.114-0 (and 0.113-0 for the repository examples) after
+ * v0.116-0 had been published and mirrored. The page now reads
+ * out/packages/release-info.json at runtime, but it still needs a compiled-in
+ * fallback for the first paint and for the case where that fetch fails - so the
+ * fallback can drift in exactly the same way, just less visibly.
+ *
+ * This check closes that loop: whenever the deployment mirrors a release, the
+ * fallback baked into the bundle must name the same one.
+ *
+ * Skipped when release-info.json is absent, which is the normal case for a
+ * site-only build (BUILD_PACKAGES=false, or any fork without the packaging
+ * secrets). There is nothing to compare against then.
+ */
+
+const fs = require("node:fs");
+const path = require("node:path");
+
+const releaseInfoPath = path.join(process.cwd(), "out", "packages", "release-info.json");
+const fallbackSourcePath = path.join(process.cwd(), "app", "lib", "releaseInfo.ts");
+
+if (!fs.existsSync(releaseInfoPath)) {
+ console.log(`No ${path.relative(process.cwd(), releaseInfoPath)}; skipping release drift check.`);
+ process.exit(0);
+}
+
+const source = fs.readFileSync(fallbackSourcePath, "utf8");
+
+/** Reads a string field out of the FALLBACK_RELEASE object literal. */
+function fallbackField(field) {
+ const match = new RegExp(`${field}:\\s*"([^"]+)"`).exec(source);
+ return match ? match[1] : null;
+}
+
+const mirrored = JSON.parse(fs.readFileSync(releaseInfoPath, "utf8"));
+const mirroredTag = mirrored.tag_name;
+if (typeof mirroredTag !== "string" || mirroredTag.length === 0) {
+ console.error("release-info.json has no tag_name; cannot verify the site's fallback release.");
+ process.exit(1);
+}
+
+const fallbackTag = fallbackField("tagName");
+if (fallbackTag !== mirroredTag) {
+ console.error(
+ [
+ "Release drift: the site's fallback release does not match the mirrored release.",
+ "",
+ ` mirrored (out/packages/release-info.json): ${mirroredTag}`,
+ ` fallback (app/lib/releaseInfo.ts): ${fallbackTag ?? ""}`,
+ "",
+ "Update FALLBACK_RELEASE in app/lib/releaseInfo.ts to the mirrored release.",
+ "It is what visitors see before the release feed loads, and permanently if",
+ "that fetch fails.",
+ ].join("\n"),
+ );
+ process.exit(1);
+}
+
+// The version strings are derived from real asset filenames, so a mismatch here
+// means the fallback would render install commands for packages the release
+// does not contain.
+const assetNames = Array.isArray(mirrored.assets)
+ ? mirrored.assets.map((asset) => asset && asset.name).filter((name) => typeof name === "string")
+ : [];
+
+const derived = [
+ {
+ field: "aptVersion",
+ pattern: /^ubuntu[\d.]+-postgresql-\d+-documentdb_([^_]+)_/,
+ },
+ {
+ field: "rpmVersion",
+ pattern: /^rhel\d+-postgresql\d+-documentdb-(.+)\.(?:x86_64|aarch64)\.rpm$/,
+ },
+ {
+ field: "metaVersion",
+ pattern: /^ubuntu[\d.]+-documentdb_([^_]+)_all\.deb$/,
+ },
+];
+
+let failed = false;
+for (const { field, pattern } of derived) {
+ const actual = assetNames.map((name) => pattern.exec(name)).find((m) => m && m[1]);
+ if (!actual) {
+ // The release simply does not ship that package shape; the fallback keeps
+ // whatever it had, which is not drift.
+ continue;
+ }
+ const expected = actual[1];
+ const declared = fallbackField(field);
+ if (declared !== expected) {
+ console.error(
+ `Release drift: FALLBACK_RELEASE.${field} is "${declared}" but ${mirroredTag} ships "${expected}".`,
+ );
+ failed = true;
+ }
+}
+
+if (failed) {
+ console.error("\nUpdate FALLBACK_RELEASE in app/lib/releaseInfo.ts.");
+ process.exit(1);
+}
+
+console.log(`Release fallback matches the mirrored release (${mirroredTag}).`);
diff --git a/.github/workflows/continuous-deployment.yml b/.github/workflows/continuous-deployment.yml
index 27431c1..4032dd1 100644
--- a/.github/workflows/continuous-deployment.yml
+++ b/.github/workflows/continuous-deployment.yml
@@ -266,6 +266,9 @@ jobs:
# downloading ~500 MB of PostgreSQL and PostGIS, which keeps the check to
# a few seconds while still catching the entire "package missing from the
# pool / unsatisfiable dependency" class.
+ - name: Verify the site's fallback release matches the mirrored release
+ if: steps.features.outputs.packages == 'true'
+ run: node .github/scripts/check_release_drift.js
- name: Smoke test the generated repository (dependency resolution)
if: steps.features.outputs.packages == 'true'
run: |
diff --git a/app/lib/packageInstall.ts b/app/lib/packageInstall.ts
index 9ed15e5..c294973 100644
--- a/app/lib/packageInstall.ts
+++ b/app/lib/packageInstall.ts
@@ -39,12 +39,50 @@ const rpmMajorVersions: Record = {
rhel9: "9",
};
+// Distributions where the repository serves the full v0.116-0 package set
+// (`documentdb` meta, `documentdb-N`, `documentdb-common`, `documentdb-gateway`,
+// `documentdb-postgresql-tools`) rather than the extension package alone.
+// v0.116-0 ships Tier-1 only, so everywhere else still resolves the older
+// extension-only release and must keep the `postgresql-N-documentdb` command.
+export const aptFullStackDistros: readonly AptDistro[] = ["ubuntu24"];
+export const rpmFullStackDistros: readonly RpmDistro[] = ["rhel9"];
+
+// The stand-alone packages exist only for the majors the full stack was built
+// for. PostgreSQL 16 resolves the older extension-only build even on a
+// full-stack distribution, so it must not be offered the stand-alone command.
+const fullStackPgVersions = ["17", "18"];
+
+export function aptServesFullStack(
+ aptTarget: AptDistro,
+ aptPgVersion: AptPgVersion,
+): boolean {
+ return (
+ aptFullStackDistros.includes(aptTarget) &&
+ fullStackPgVersions.includes(aptPgVersion)
+ );
+}
+
+export function rpmServesFullStack(
+ rpmTarget: RpmDistro,
+ rpmPgVersion: RpmPgVersion,
+): boolean {
+ return (
+ rpmFullStackDistros.includes(rpmTarget) &&
+ fullStackPgVersions.includes(rpmPgVersion)
+ );
+}
+
export function buildAptInstallCommand(
aptTarget: AptDistro,
aptArch: AptArch,
aptPgVersion: AptPgVersion,
): string {
const pgdgSuite = aptPgdgSuites[aptTarget];
+ // `documentdb-N` pulls the whole stack (extension + gateway + tools +
+ // documentdb-common) and owns the systemd lifecycle for that major.
+ const installTarget = aptServesFullStack(aptTarget, aptPgVersion)
+ ? `documentdb-${aptPgVersion}`
+ : `postgresql-${aptPgVersion}-documentdb`;
return `sudo apt update && \\
sudo apt install -y curl ca-certificates gnupg && \\
@@ -53,7 +91,7 @@ echo "deb [signed-by=/usr/share/keyrings/postgresql.gpg] https://apt.postgresql.
curl -fsSL https://documentdb.io/documentdb-archive-keyring.gpg | sudo gpg --dearmor --yes -o /usr/share/keyrings/documentdb-archive-keyring.gpg && \\
echo "deb [arch=${aptArch} signed-by=/usr/share/keyrings/documentdb-archive-keyring.gpg] https://documentdb.io/deb stable ${aptTarget}" | sudo tee /etc/apt/sources.list.d/documentdb.list >/dev/null && \\
sudo apt update && \\
-sudo apt install -y postgresql-${aptPgVersion}-documentdb`;
+sudo apt install -y ${installTarget}`;
}
export function buildRpmInstallCommand(
@@ -62,6 +100,9 @@ export function buildRpmInstallCommand(
rpmPgVersion: RpmPgVersion,
): string {
const rhelMajorVersion = rpmMajorVersions[rpmTarget];
+ const installTarget = rpmServesFullStack(rpmTarget, rpmPgVersion)
+ ? `documentdb-${rpmPgVersion}`
+ : `postgresql${rpmPgVersion}-documentdb`;
return `sudo dnf install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-${rhelMajorVersion}.noarch.rpm && \\
sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-${rhelMajorVersion}-${rpmArch}/pgdg-redhat-repo-latest.noarch.rpm && \\
@@ -78,5 +119,12 @@ printf '%s\\n' \\
'enabled=1' \\
'gpgcheck=1' \\
'gpgkey=https://documentdb.io/documentdb-archive-keyring.gpg' | sudo tee /etc/yum.repos.d/documentdb.repo >/dev/null && \\
-sudo dnf install -y postgresql${rpmPgVersion}-documentdb`;
+sudo dnf install -y ${installTarget}`;
+}
+
+// Shown after a full-stack install: the packages ship a wizard that creates the
+// PostgreSQL instance, installs the extensions and starts the gateway, so the
+// install command alone does not leave a reachable endpoint.
+export function buildSetupCommand(): string {
+ return `sudo documentdb-setup --admin-user admin`;
}
diff --git a/app/lib/releaseInfo.ts b/app/lib/releaseInfo.ts
new file mode 100644
index 0000000..0171b0b
--- /dev/null
+++ b/app/lib/releaseInfo.ts
@@ -0,0 +1,142 @@
+"use client";
+
+import { useEffect, useState } from "react";
+
+// The site publishes out/packages/release-info.json on every deployment, built
+// from the GitHub release the package repository actually mirrors. It is the
+// only authoritative statement of "what version is on documentdb.io", so the
+// UI derives its version strings from it rather than repeating them.
+//
+// Before this module the versions were hardcoded in the page, and they drifted:
+// the page still advertised 0.114-0 (and 0.113-0 for the repository examples)
+// after v0.116-0 had been published and mirrored.
+
+export type ReleaseInfo = {
+ /** Git tag of the mirrored release, e.g. "v0.116-0". */
+ tagName: string;
+ /** Extension package version on DEB, e.g. "0.116-0". */
+ aptVersion: string;
+ /** Extension package version on RPM, e.g. "0.116.0-1.el9". */
+ rpmVersion: string;
+ /** Version of every non-extension package, e.g. "0.116.0". */
+ metaVersion: string;
+ releaseUrl: string;
+ assetNames: readonly string[];
+};
+
+// Used until the fetch resolves, and permanently if it fails. A stale-but-valid
+// page is much better than a blank one, so this is a real release rather than a
+// placeholder. Keep it in step with the newest release; the drift check in CI
+// fails the build when it falls behind release-info.json.
+export const FALLBACK_RELEASE: ReleaseInfo = {
+ tagName: "v0.116-0",
+ aptVersion: "0.116-0",
+ rpmVersion: "0.116.0-1.el9",
+ metaVersion: "0.116.0",
+ releaseUrl: "https://github.com/documentdb/documentdb/releases/tag/v0.116-0",
+ assetNames: [],
+};
+
+type RawReleaseInfo = {
+ tag_name?: unknown;
+ html_url?: unknown;
+ assets?: unknown;
+};
+
+function assetNamesOf(raw: RawReleaseInfo): string[] {
+ if (!Array.isArray(raw.assets)) {
+ return [];
+ }
+ return raw.assets
+ .map((asset) =>
+ asset && typeof asset === "object" && typeof (asset as { name?: unknown }).name === "string"
+ ? (asset as { name: string }).name
+ : null,
+ )
+ .filter((name): name is string => name !== null);
+}
+
+function firstMatch(names: readonly string[], pattern: RegExp): string | null {
+ for (const name of names) {
+ const match = pattern.exec(name);
+ if (match?.[1]) {
+ return match[1];
+ }
+ }
+ return null;
+}
+
+/**
+ * Derives the display versions from a release-info.json payload.
+ *
+ * Each field falls back independently: a release that stops shipping one
+ * package shape must not blank out the versions that are still present.
+ */
+export function parseReleaseInfo(payload: unknown): ReleaseInfo {
+ if (!payload || typeof payload !== "object") {
+ return FALLBACK_RELEASE;
+ }
+ const raw = payload as RawReleaseInfo;
+ const names = assetNamesOf(raw);
+
+ const tagName = typeof raw.tag_name === "string" ? raw.tag_name : FALLBACK_RELEASE.tagName;
+ const releaseUrl =
+ typeof raw.html_url === "string"
+ ? raw.html_url
+ : `https://github.com/documentdb/documentdb/releases/tag/${tagName}`;
+
+ // The extension keeps the control-file form (0.116-0) on DEB, while RPM
+ // splits it into Version/Release and renders 0.116.0-1.el9. Everything else
+ // uses the flat dotted form. Read all three off real filenames so the page
+ // cannot claim a shape the release does not contain.
+ const aptVersion =
+ firstMatch(names, /^ubuntu[\d.]+-postgresql-\d+-documentdb_([^_]+)_/) ??
+ firstMatch(names, /^deb\d+-postgresql-\d+-documentdb_([^_]+)_/) ??
+ FALLBACK_RELEASE.aptVersion;
+
+ const rpmVersion =
+ firstMatch(names, /^rhel\d+-postgresql\d+-documentdb-(.+)\.(?:x86_64|aarch64)\.rpm$/) ??
+ FALLBACK_RELEASE.rpmVersion;
+
+ const metaVersion =
+ firstMatch(names, /^ubuntu[\d.]+-documentdb_([^_]+)_all\.deb$/) ??
+ firstMatch(names, /^documentdb-(\d+\.\d+\.\d+)-\d+\.noarch\.rpm$/) ??
+ FALLBACK_RELEASE.metaVersion;
+
+ return { tagName, aptVersion, rpmVersion, metaVersion, releaseUrl, assetNames: names };
+}
+
+/**
+ * Reads the mirrored release description published alongside the packages.
+ *
+ * Returns the fallback synchronously so the first paint is always correct-ish,
+ * then swaps in the live values. The site is a static export, so this has to
+ * happen in the browser; NEXT_PUBLIC_BASE_PATH is the one base-path value Next
+ * keeps in the client bundle.
+ */
+export function useReleaseInfo(): ReleaseInfo {
+ const [release, setRelease] = useState(FALLBACK_RELEASE);
+
+ useEffect(() => {
+ let cancelled = false;
+ const basePath = process.env.NEXT_PUBLIC_BASE_PATH ?? "";
+
+ fetch(`${basePath}/packages/release-info.json`)
+ .then((response) => (response.ok ? response.json() : Promise.reject(response.status)))
+ .then((payload) => {
+ if (!cancelled) {
+ setRelease(parseReleaseInfo(payload));
+ }
+ })
+ .catch(() => {
+ // Keep the fallback: an unreachable or malformed feed must not empty
+ // the install commands the page exists to show.
+ });
+
+ return () => {
+ cancelled = true;
+ };
+ }, []);
+
+ return release;
+}
diff --git a/app/packages/page.tsx b/app/packages/page.tsx
index cdfb0c7..d8ab11b 100644
--- a/app/packages/page.tsx
+++ b/app/packages/page.tsx
@@ -6,8 +6,11 @@ import CommandSnippet from "../components/CommandSnippet";
import {
aptTargetPgVersions,
aptTargetLabels,
+ aptServesFullStack,
buildAptInstallCommand,
buildRpmInstallCommand,
+ buildSetupCommand,
+ rpmServesFullStack,
type AptArch,
type AptDistro,
type AptPgVersion,
@@ -16,6 +19,7 @@ import {
type RpmPgVersion,
rpmTargetLabels,
} from "../lib/packageInstall";
+import { useReleaseInfo } from "../lib/releaseInfo";
type InstallMethod = "docker" | "packages";
type PackageFamily = "apt" | "rpm";
@@ -50,28 +54,48 @@ const nextGuides = [
] as const;
const allReleasesUrl = "https://github.com/documentdb/documentdb/releases";
-// Latest GitHub release, used for the direct .deb/.rpm download examples.
-const latestReleaseAptVersion = "0.114-0";
-const latestReleaseRpmVersion = "0.114.0-1.el9";
-// Version currently served by the APT/RPM package repositories, which can lag
-// GitHub Releases. Used for the version-pinning examples.
-const repoAptVersionExample = "0.113-0";
-const repoRpmVersionExample = "0.113.0-1.el9";
-const currentReleaseExamples = [
- `ubuntu22.04-postgresql-18-documentdb_${latestReleaseAptVersion}_amd64.deb`,
- `deb13-postgresql-18-documentdb_${latestReleaseAptVersion}_amd64.deb`,
- `rhel9-postgresql18-documentdb-${latestReleaseRpmVersion}.x86_64.rpm`,
+
+// The v0.116-0 packaging redesign replaced the single extension package with
+// this set. Listed here so the page explains what an install actually brings
+// in, instead of naming one package and silently pulling four more.
+const packageRoles = [
+ {
+ name: "documentdb / documentdb-N",
+ role: "Meta and per-major stand-alone package. Pins PostgreSQL and owns the systemd lifecycle.",
+ },
+ {
+ name: "postgresql-N-documentdb",
+ role: "The PostgreSQL extension itself (files only).",
+ },
+ {
+ name: "documentdb-gateway",
+ role: "Wire-protocol runtime that serves the MongoDB-compatible endpoint.",
+ },
+ {
+ name: "documentdb-postgresql-tools",
+ role: "Administrator helpers: documentdb-tune, documentdb-createcluster, documentdb-register-gateway, documentdb-gateway-admin.",
+ },
+ {
+ name: "documentdb-common",
+ role: "Shared payload: documentdb-setup, the systemd units, helper scripts and sample data.",
+ },
] as const;
export default function PackagesPage() {
+ const release = useReleaseInfo();
const [method, setMethod] = useState("docker");
const [packageFamily, setPackageFamily] = useState("apt");
- const [aptTarget, setAptTarget] = useState("ubuntu22");
+ // Default to the paved road (Ubuntu 24.04 + PostgreSQL 18). It is the target
+ // the release is built and end-to-end tested against, and the only one whose
+ // repository component serves the full package set - defaulting to an
+ // extension-only target showed first-time visitors the older, smaller
+ // experience.
+ const [aptTarget, setAptTarget] = useState("ubuntu24");
const [rpmTarget, setRpmTarget] = useState("rhel9");
const [aptArch, setAptArch] = useState("amd64");
const [rpmArch, setRpmArch] = useState("x86_64");
- const [aptPgVersion, setAptPgVersion] = useState("16");
- const [rpmPgVersion, setRpmPgVersion] = useState("16");
+ const [aptPgVersion, setAptPgVersion] = useState("18");
+ const [rpmPgVersion, setRpmPgVersion] = useState("18");
const availableAptPgVersions = aptTargetPgVersions[aptTarget];
useEffect(() => {
@@ -80,10 +104,29 @@ export default function PackagesPage() {
}
}, [aptPgVersion, availableAptPgVersions]);
+ const latestReleaseAptVersion = release.aptVersion;
+ const latestReleaseRpmVersion = release.rpmVersion;
+ // The repository serves the mirrored release, so the pinning examples use the
+ // same versions rather than a separately maintained pair that fell behind.
+ const repoAptVersionExample = release.aptVersion;
+ const repoRpmVersionExample = release.rpmVersion;
+ const currentReleaseExamples = [
+ `ubuntu24.04-documentdb_${release.metaVersion}_all.deb`,
+ `ubuntu24.04-postgresql-18-documentdb_${latestReleaseAptVersion}_amd64.deb`,
+ `rhel9-postgresql18-documentdb-${latestReleaseRpmVersion}.x86_64.rpm`,
+ ] as const;
+
const aptCommand = buildAptInstallCommand(aptTarget, aptArch, aptPgVersion);
const rpmCommand = buildRpmInstallCommand(rpmTarget, rpmArch, rpmPgVersion);
- const selectedPackageNames =
+ // Tier-1 targets resolve the full v0.116-0 stack, so the selected package is
+ // the per-major stand-alone rather than the bare extension.
+ const isFullStack =
packageFamily === "apt"
+ ? aptServesFullStack(aptTarget, aptPgVersion)
+ : rpmServesFullStack(rpmTarget, rpmPgVersion);
+ const selectedPackageNames = isFullStack
+ ? `documentdb-${packageFamily === "apt" ? aptPgVersion : rpmPgVersion}`
+ : packageFamily === "apt"
? `postgresql-${aptPgVersion}-documentdb`
: `postgresql${rpmPgVersion}-documentdb`;
const selectedTargetText =
@@ -289,9 +332,36 @@ export default function PackagesPage() {
rum for PostgreSQL 16/17.
- It installs the PostgreSQL extension package. The published package repository
- does not currently include a gateway package, setup helper, or systemd service.
+ {isFullStack
+ ? "It installs the full DocumentDB stack for this target: the extension, the gateway runtime, the administrator tools and the systemd units."
+ : "It installs the PostgreSQL extension package. This target is not yet covered by the v0.116-0 package layout, so the repository serves the extension alone — no gateway package, setup helper, or systemd service."}
+ {isFullStack ? (
+ <>
+
+ Then run the setup wizard. It creates the PostgreSQL instance, installs the
+ extensions, bootstraps the admin user and starts the gateway — the install
+ above on its own does not leave a reachable endpoint. It prompts for the
+ admin password; pass{" "}
+ --admin-password-stdin --yes for an
+ unattended install.
+
+
+
+ The gateway then listens on port{" "}
+ 10260. It binds all interfaces by
+ default, so firewall the port and supply a real certificate before exposing
+ it to a network. See the{" "}
+
+ package installation guide
+ {" "}
+ for verification, day-2 and upgrade steps.
+
+ >
+ ) : null}
{packageFamily === "apt" ? (
Running in a clean Debian/Ubuntu container as root?
@@ -303,14 +373,36 @@ export default function PackagesPage() {
) : null}
- Need the MongoDB-compatible gateway?
-
-
- Use the Docker image for the fastest gateway-backed local setup. If you want a
- package-backed host install that still works with mongosh,
- the Linux package guide includes the exact non-root gateway follow-up commands
- and host build prerequisites.
+ {isFullStack
+ ? "What gets installed"
+ : "Need the MongoDB-compatible gateway?"}
+ {isFullStack ? (
+ <>
+
+ DocumentDB ships as five packages. Installing{" "}
+ {selectedPackageNames} pulls in
+ everything below.
+
+
+ {packageRoles.map((entry) => (
+
+
-
+ {entry.name}
+
+ - {entry.role}
+
+ ))}
+
+ >
+ ) : (
+
+ Use the Docker image for the fastest gateway-backed local setup. If you want a
+ package-backed host install that still works with mongosh,
+ the Linux package guide includes the exact non-root gateway follow-up commands
+ and host build prerequisites.
+
+ )}
{packageFamily === "apt" ? (
@@ -398,12 +490,12 @@ export default function PackagesPage() {
APT — list then pin
- apt-cache madison postgresql-16-documentdb
+ apt-cache madison postgresql-18-documentdb
- sudo apt install postgresql-16-documentdb=<VERSION>
+ sudo apt install postgresql-18-documentdb=<VERSION>
@@ -411,12 +503,12 @@ export default function PackagesPage() {
RPM — list then pin
- dnf --showduplicates list postgresql16-documentdb
+ dnf --showduplicates list postgresql18-documentdb
- sudo dnf install postgresql16-documentdb-<VERSION>
+ sudo dnf install postgresql18-documentdb-<VERSION>
@@ -473,13 +565,13 @@ export default function PackagesPage() {
sudo apt update && apt search documentdb && apt-cache policy
- postgresql-16-documentdb
+ postgresql-18-documentdb
sudo dnf clean all && dnf search documentdb && rpm -qi
- postgresql16-documentdb
+ postgresql18-documentdb
diff --git a/app/services/articleService.ts b/app/services/articleService.ts
index 29f6257..d95da27 100644
--- a/app/services/articleService.ts
+++ b/app/services/articleService.ts
@@ -108,65 +108,157 @@ If something does not work as expected:
const linuxPackagesGuideContent = `# Linux Packages Quick Start
-Install the DocumentDB PostgreSQL extension package on Debian, Ubuntu, or RHEL-compatible hosts.
+Install DocumentDB on Debian, Ubuntu, or RHEL-compatible hosts from the published package repository.
+
+## What you get
+
+Since v0.116-0 DocumentDB ships as a set of packages rather than a lone extension:
+
+| Package | Role |
+| --- | --- |
+| \`documentdb\` (meta) + \`documentdb-N\` | Full stand-alone install. Pins PostgreSQL major N and owns the systemd lifecycle. |
+| \`postgresql-N-documentdb\` | The PostgreSQL extension itself (files only). |
+| \`documentdb-gateway\` | Wire-protocol runtime serving the MongoDB-compatible endpoint. |
+| \`documentdb-postgresql-tools\` | Admin helpers: \`documentdb-tune\`, \`documentdb-createcluster\`, \`documentdb-register-gateway\`, \`documentdb-gateway-admin\`. |
+| \`documentdb-common\` | Shared payload: \`documentdb-setup\`, the systemd units, helper scripts, sample data. |
+
+The full set is published for **Ubuntu 24.04** and **RHEL-compatible 9** on PostgreSQL 17 and 18. Ubuntu 22.04, Debian 11/12/13 and RHEL-compatible 8 still resolve the **extension package only** — for those, see [Extension-only hosts](#extension-only-hosts) below.
## Choose the right package command
Use the [Package Finder](/packages) to generate the exact install command for your distro, architecture, and PostgreSQL version.
-> The generated command installs the PostgreSQL extension package and its PostgreSQL-side dependencies. The published package repository and GitHub Releases do not currently include a gateway package, setup helper, or systemd service.
+> The package commands assume a regular Linux host where you use \`sudo\`. In a clean container running as \`root\`, omit \`sudo\`.
>
-> The repository-backed install commands currently cover Ubuntu 22.04/24.04, Debian 11/12/13, and RHEL-compatible 8/9 systems. Debian 11 currently resolves PostgreSQL 16 and 17 in the repository-backed flow.
->
-> The package commands assume a regular Linux host where you use \`sudo\`. If you are testing in a clean container that already runs as \`root\`, omit \`sudo\` from the package-install commands.
->
-> On Debian and Ubuntu in a clean container, also run \`export DEBIAN_FRONTEND=noninteractive\` in the shell before the APT commands. Without it, \`tzdata\` (and a few other packages) prompt for input during \`apt install\` and the install hangs with no visible error.
+> On Debian and Ubuntu in a clean container, also run \`export DEBIAN_FRONTEND=noninteractive\` first. Without it, \`tzdata\` prompts for input during \`apt install\` and the install hangs with no visible error.
## Install the packages
-### APT example
+### APT example (Ubuntu 24.04, PostgreSQL 18)
\`\`\`bash
-${buildAptInstallCommand('ubuntu24', 'amd64', '16')}
+${buildAptInstallCommand('ubuntu24', 'amd64', '18')}
\`\`\`
-### RPM example
+### RPM example (RHEL-compatible 9, PostgreSQL 18)
\`\`\`bash
-${buildRpmInstallCommand('rhel9', 'x86_64', '16')}
+${buildRpmInstallCommand('rhel9', 'x86_64', '18')}
\`\`\`
-## What the package installs
+## Set up and connect
+
+Installing the packages puts files on disk; it does not create a database or start the endpoint. The setup wizard does that:
-The packages install the DocumentDB PostgreSQL extension files for the selected PostgreSQL major version. They do not by themselves start a MongoDB-compatible gateway endpoint on port \`10260\`.
+\`\`\`bash
+sudo documentdb-setup --admin-user admin
+\`\`\`
-Use the Docker quick start when you need the fastest local gateway-backed DocumentDB endpoint:
+It creates the PostgreSQL instance, installs the extensions, bootstraps the admin user, starts the gateway, and enables \`documentdb-local@.target\` so the stack survives reboot. It **prompts for the admin password**; for servers and CI pass \`--admin-password-file \` or \`--admin-password-stdin\` together with \`--yes\`.
+
+\`mongosh\` is not shipped by these packages — install it from the [official instructions](https://www.mongodb.com/docs/mongodb-shell/install/), then:
\`\`\`bash
-docker run -dt --name documentdb \\
- -p 10260:10260 \\
- ghcr.io/documentdb/documentdb/documentdb-local:latest \\
- --username \\
- --password
+mongosh 'mongodb://admin:@127.0.0.1:10260/mydb?tls=true&tlsAllowInvalidCertificates=true' \\
+ --eval 'db.runCommand({ping: 1})'
+\`\`\`
+
+A database and collection are created on first write:
+
+\`\`\`javascript
+db.orders.insertOne({ item: "widget", qty: 5 })
+db.orders.find()
+\`\`\`
+
+## Before exposing it to a network
+
+The gateway binds **all interfaces** (\`0.0.0.0:10260\` and \`[::]:10260\`) by default, even though the connect string above says \`127.0.0.1\`. The PostgreSQL instance behind it stays on loopback.
+
+Before using this anywhere but a private machine:
+
+- Restrict the listener with \`DOCUMENTDB_LISTEN_ADDR=127.0.0.1:10260\` in \`/etc/documentdb/local//gateway.env\` and restart the service, or firewall port \`10260\`. Note that re-running \`documentdb-setup\` rewrites that file, so a firewall rule is the more durable control.
+- Replace the auto-generated self-signed certificate. \`tlsAllowInvalidCertificates=true\` disables certificate validation — point \`DOCUMENTDB_TLS_CERT_FILE\` / \`DOCUMENTDB_TLS_KEY_FILE\` at a real certificate and drop that option.
+- Use a strong admin password and create per-application users rather than sharing \`admin\`.
+
+## Verify and operate
+
+\`\`\`bash
+sudo documentdb-setup --status # gateway listener, service states, resolved paths
+documentdb-gateway --version # DocumentDB version
+dpkg -l | grep documentdb # or: rpm -qa | grep documentdb
\`\`\`
-If you are operating a host PostgreSQL installation, configure PostgreSQL and run the gateway using the source repository's build/run scripts.
+> Do not use \`db.version()\` or \`buildInfo\` in \`mongosh\` to check the DocumentDB version — those report the emulated MongoDB wire version, not DocumentDB's.
-## Verify the package install
+| Thing | Where |
+| --- | --- |
+| Gateway port | \`10260\` |
+| PostgreSQL port | \`9700 + \` (9718 for PG 18), loopback only |
+| Gateway log | \`/var/lib/documentdb-gateway/gateway.log\` |
+| PostgreSQL log | \`/var/lib/documentdb-local//data/pglog.log\` |
+| Setup state / gateway env | \`/etc/documentdb/local//setup.conf\`, \`.../gateway.env\` |
-Use package-manager metadata to confirm the extension package is installed:
+Day 2 (units are templated per PostgreSQL major):
+
+\`\`\`bash
+sudo systemctl status documentdb-local@18.target
+sudo systemctl restart documentdb-local@18.target
+sudo systemctl stop documentdb-local@18.target
+\`\`\`
+
+On hosts without systemd the wizard starts the gateway directly; re-run \`documentdb-setup\` to restart it.
+
+Remove or reset:
+
+\`\`\`bash
+sudo documentdb-setup --restore # detach the managed integration
+sudo documentdb-local-reset --pg-version 18 --confirm-destroy # DESTROYS the data directory
+sudo apt remove documentdb # or: sudo dnf remove documentdb
+\`\`\`
+
+## Upgrading
+
+A package upgrade only replaces files. Afterwards, update the extensions in every database that has DocumentDB installed:
+
+\`\`\`sql
+ALTER EXTENSION documentdb_core UPDATE;
+ALTER EXTENSION documentdb UPDATE;
+ALTER EXTENSION documentdb_extended_rum UPDATE; -- only if installed
+\`\`\`
+
+PostgreSQL applies intermediate upgrade scripts automatically. In-place upgrades are not yet a fully tested path, so take a backup first.
+
+## Extension-only hosts
+
+Ubuntu 22.04, Debian 11/12/13 and RHEL-compatible 8 currently serve the extension package alone — no gateway, setup helper, or systemd units. On those hosts the install command ends in \`postgresql--documentdb\` (APT) or \`postgresql-documentdb\` (RPM), and there is no \`documentdb-setup\`.
+
+Confirm the extension landed with package metadata:
\`\`\`bash
# APT
-apt-cache policy postgresql-16-documentdb
-dpkg -L postgresql-16-documentdb | grep -E 'documentdb.*\\.(control|sql|so)$' | head
+apt-cache policy postgresql-18-documentdb
+dpkg -L postgresql-18-documentdb | grep -E 'documentdb.*\\.(control|sql|so)$' | head
# RPM
-dnf info postgresql16-documentdb
-rpm -ql postgresql16-documentdb | grep -E 'documentdb.*\\.(control|sql|so)$' | head
+dnf info postgresql18-documentdb
+rpm -ql postgresql18-documentdb | grep -E 'documentdb.*\\.(control|sql|so)$' | head
\`\`\`
-## Turn a package install into a local \`mongosh\` endpoint
+For the fastest gateway-backed endpoint on those hosts, use the Docker quick start:
+
+\`\`\`bash
+docker run -dt --name documentdb \\
+ -p 10260:10260 \\
+ ghcr.io/documentdb/documentdb/documentdb-local:latest \\
+ --username \\
+ --password
+\`\`\`
+
+Otherwise, run the gateway from the source repository against your host PostgreSQL, as described below.
+
+## Turn an extension-only install into a local \`mongosh\` endpoint
+
+On Ubuntu 24.04 and RHEL 9 use \`documentdb-setup\` above instead — this section is only for distributions where the gateway is not packaged yet.
If you want to keep PostgreSQL on the host and still connect with \`mongosh\`, install the extension package first and then run the gateway from the source repository against that PostgreSQL instance.
@@ -258,7 +350,8 @@ Use this flow when you want a package-backed host install plus a local MongoDB-c
If something does not work on the first try:
-- Confirm the extension package is installed: \`postgresql--documentdb\` on APT or \`postgresql-documentdb\` on RPM
+- Confirm the packages are installed: \`documentdb-\` on a full-stack target, or \`postgresql--documentdb\` (APT) / \`postgresql-documentdb\` (RPM) on an extension-only target
+- On a full-stack target, run \`sudo documentdb-setup --status\` first: it reports the gateway listener, the service states and the resolved paths
- Re-run the Package Finder command for the exact distro, architecture, and PostgreSQL version you selected
- Confirm the PostgreSQL upstream repository was added before the DocumentDB package install
- If you are running in a clean container as \`root\`, omit \`sudo\` from the package-install commands and switch to an unprivileged user before the gateway steps
@@ -269,7 +362,7 @@ If something does not work on the first try:
- If the gateway build fails while reading \`Cargo.lock\`, switch to a current Rust toolchain from \`rustup\` instead of the distro-packaged \`cargo\`
- If \`mongosh\` cannot connect, confirm the gateway script is still running and listening on port \`10260\`
- For Debian 11, use PostgreSQL 16 or 17; PostgreSQL 18 is blocked by the upstream Bullseye PostGIS dependency
-- If you need a gateway endpoint, use DocumentDB Local with Docker or build and run the gateway from source
+- If you need a gateway endpoint on an extension-only distribution, use DocumentDB Local with Docker or build and run the gateway from source
## Next steps
diff --git a/tests/packageInstall.test.ts b/tests/packageInstall.test.ts
index d4b5996..c1c0ba8 100644
--- a/tests/packageInstall.test.ts
+++ b/tests/packageInstall.test.ts
@@ -1,9 +1,11 @@
import { describe, expect, it } from 'vitest';
import {
+ aptServesFullStack,
aptTargetLabels,
aptTargetPgVersions,
buildAptInstallCommand,
buildRpmInstallCommand,
+ rpmServesFullStack,
rpmTargetLabels,
} from '../app/lib/packageInstall';
import type {
@@ -89,9 +91,16 @@ describe('buildAptInstallCommand', () => {
expect(command).toContain(`documentdb.io/deb stable ${distro}`);
});
- it.each(aptMatrix)('installs postgresql-$pg-documentdb for $distro/$arch', ({ distro, arch, pg }) => {
+ it.each(aptMatrix)('installs the right package for $distro/$arch/pg$pg', ({ distro, arch, pg }) => {
const command = buildAptInstallCommand(distro, arch, pg);
- expect(command).toContain(`sudo apt install -y postgresql-${pg}-documentdb`);
+ // v0.116-0 ships the full package set for Tier-1 targets only. There the
+ // per-major stand-alone pulls the whole stack; everywhere else the
+ // repository still serves the extension alone, and offering `documentdb-N`
+ // would be an install command that cannot resolve.
+ const expected = aptServesFullStack(distro, pg)
+ ? `documentdb-${pg}`
+ : `postgresql-${pg}-documentdb`;
+ expect(command).toContain(`sudo apt install -y ${expected}`);
});
it('does not offer PostgreSQL 18 on Debian 11', () => {
@@ -126,9 +135,29 @@ describe('buildRpmInstallCommand', () => {
expect(command).toContain(`baseurl=https://documentdb.io/rpm/${distro}`);
});
- it.each(rpmMatrix)('installs postgresql$pg-documentdb for $distro/$arch', ({ distro, arch, pg }) => {
+ it.each(rpmMatrix)('installs the right package for $distro/$arch/pg$pg', ({ distro, arch, pg }) => {
const command = buildRpmInstallCommand(distro, arch, pg);
- expect(command).toContain(`sudo dnf install -y postgresql${pg}-documentdb`);
+ const expected = rpmServesFullStack(distro, pg)
+ ? `documentdb-${pg}`
+ : `postgresql${pg}-documentdb`;
+ expect(command).toContain(`sudo dnf install -y ${expected}`);
+ });
+
+ it('serves the full stack only where v0.116-0 published it', () => {
+ // PostgreSQL 16 resolves the older extension-only build even on a Tier-1
+ // target, so it must keep the extension command.
+ expect(rpmServesFullStack('rhel9', '18')).toBe(true);
+ expect(rpmServesFullStack('rhel9', '16')).toBe(false);
+ expect(rpmServesFullStack('rhel8', '18')).toBe(false);
+ expect(aptServesFullStack('ubuntu24', '18')).toBe(true);
+ expect(aptServesFullStack('ubuntu24', '16')).toBe(false);
+ expect(aptServesFullStack('ubuntu22', '18')).toBe(false);
+ expect(buildAptInstallCommand('ubuntu22', 'amd64', '18')).toContain(
+ 'sudo apt install -y postgresql-18-documentdb',
+ );
+ expect(buildAptInstallCommand('ubuntu24', 'amd64', '18')).toContain(
+ 'sudo apt install -y documentdb-18',
+ );
});
it('enables gpgcheck against the DocumentDB signing key', () => {
From 199afa784b890b2c8278956962fe4f632603249e Mon Sep 17 00:00:00 2001
From: Guanzhou Song
Date: Mon, 24 Aug 2026 17:07:07 -0400
Subject: [PATCH 2/3] Correct the removal command and the page's extension-only
framing
A cold read-the-site-and-install run surfaced two things the earlier pass
missed.
`apt remove documentdb` does not remove DocumentDB. The meta package only
owns the dependency on the per-major package, so removing it leaves
documentdb-18, documentdb-common, documentdb-gateway and
documentdb-postgresql-tools installed -- verified: 5 packages before, 4 after.
Remove the per-major package too and let autoremove reap the shared payload.
The /packages hero and package catalog still taught the old model. The hero
offered ""Linux packages for PostgreSQL extension installs"" and said the
generated command installs ""the DocumentDB extension package"", and the catalog
listed only the `postgresql--documentdb` naming against a flat
distribution list. A visitor who read only the static part of that page would
conclude the extension package is all there is, which is exactly the
misunderstanding the release needs to clear up. Both now distinguish the
full-stack targets from the extension-only ones.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 8df9084a-ccaf-432c-b015-2ccd8893a9d8
---
PACKAGE-INSTALL.md | 7 ++++++-
app/packages/page.tsx | 30 +++++++++++++++++++++++++-----
app/services/articleService.ts | 7 ++++++-
3 files changed, 37 insertions(+), 7 deletions(-)
diff --git a/PACKAGE-INSTALL.md b/PACKAGE-INSTALL.md
index 7d0b248..ef20068 100644
--- a/PACKAGE-INSTALL.md
+++ b/PACKAGE-INSTALL.md
@@ -165,7 +165,12 @@ instead; re-run `documentdb-setup` to restart it.
```bash
sudo documentdb-setup --restore # detach the managed integration
sudo documentdb-local-reset --pg-version 18 --confirm-destroy # DESTROYS the data directory
-sudo apt remove documentdb # or: sudo dnf remove documentdb
+
+# Removing the meta package alone leaves the stack installed — it only owns the
+# dependency on the per-major package. Remove that too, and let autoremove reap
+# documentdb-common, documentdb-gateway and documentdb-postgresql-tools.
+sudo apt remove --autoremove documentdb documentdb-18
+sudo dnf remove documentdb documentdb-18 && sudo dnf autoremove
```
### What the packages are
diff --git a/app/packages/page.tsx b/app/packages/page.tsx
index d8ab11b..5e22d86 100644
--- a/app/packages/page.tsx
+++ b/app/packages/page.tsx
@@ -141,9 +141,11 @@ export default function PackagesPage() {
Download DocumentDB
- Choose Docker for the fastest local setup, or Linux packages for PostgreSQL
- extension installs. The generated package commands configure the PostgreSQL
- dependency repositories and install the DocumentDB extension package.
+ Choose Docker for the fastest local setup, or Linux packages for a persistent
+ install. On Ubuntu 24.04 and RHEL-compatible 9 the packages install the full
+ DocumentDB stack — the PostgreSQL extension, the wire-protocol gateway, the
+ administrator tools and systemd units. Other distributions currently receive the
+ extension package alone.
@@ -441,17 +443,35 @@ export default function PackagesPage() {
| APT |
- Ubuntu 22.04/24.04, Debian 11/12/13 |
+ Ubuntu 24.04 (full stack) |
+ amd64, arm64 |
+ 17, 18 |
+
+ documentdb-<pg>
+ |
+
+
+ | APT |
+ Ubuntu 22.04, Debian 11/12/13 (extension only) |
amd64, arm64 |
16, 17, 18 (Debian 11: 16, 17) |
postgresql-<pg>-documentdb
|
+
+ | RPM |
+ RHEL-compatible 9 (full stack) |
+ x86_64, aarch64 |
+ 17, 18 |
+
+ documentdb-<pg>
+ |
+
| RPM |
- RHEL-compatible 8/9 (tested on Rocky Linux)
+ RHEL-compatible 8 (extension only, tested on Rocky Linux)
|
x86_64, aarch64 |
16, 17, 18 |
diff --git a/app/services/articleService.ts b/app/services/articleService.ts
index d95da27..4bf91bc 100644
--- a/app/services/articleService.ts
+++ b/app/services/articleService.ts
@@ -213,7 +213,12 @@ Remove or reset:
\`\`\`bash
sudo documentdb-setup --restore # detach the managed integration
sudo documentdb-local-reset --pg-version 18 --confirm-destroy # DESTROYS the data directory
-sudo apt remove documentdb # or: sudo dnf remove documentdb
+
+# Removing the meta package alone leaves the stack installed - it only owns the
+# dependency on the per-major package. Remove that too and let autoremove reap
+# the shared payload.
+sudo apt remove --autoremove documentdb documentdb-18
+sudo dnf remove documentdb documentdb-18 && sudo dnf autoremove
\`\`\`
## Upgrading
From 463e6072dd54f10ba05d5166ef81fdbc647ff461 Mon Sep 17 00:00:00 2001
From: Guanzhou Song
Date: Mon, 24 Aug 2026 17:29:04 -0400
Subject: [PATCH 3/3] Fix the uninstall path, and stop the landing page sending
users to a source build
A second cold read-the-site-and-install run found three things.
The documented uninstall left a running, network-exposed database behind.
Verified on a clean container: after `apt remove --autoremove documentdb
documentdb-18`, apt reports `Package 'documentdb' is not installed` (the meta
is never pulled by installing `documentdb-18`), `postgresql-18-documentdb`
is still `ii` installed with its .so and .control files on disk, the other
four packages are left in `rc` state with their config, and -- because
package removal does not stop a service -- the gateway is still listening on
0.0.0.0:10260 and still answering queries. `apt purge --autoremove
documentdb-18 postgresql-18-documentdb` leaves nothing behind, so document
that, and tell people to stop the stack first.
The landing page told full-stack users to build the gateway from source: ""Linux
packages install the PostgreSQL extension; the Linux package guide adds the
extra source-gateway steps needed when you want a host install that still
exposes a MongoDB-compatible endpoint."" On Ubuntu 24.04 and RHEL 9 the gateway
is packaged and `documentdb-setup` starts it, so that sends people off to
build a Rust project they do not need.
The connection URI had no note about percent-encoding, so a password containing
`@` silently misparses. Add the note and the flag-based form that avoids the
problem entirely.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 8df9084a-ccaf-432c-b015-2ccd8893a9d8
---
PACKAGE-INSTALL.md | 24 +++++++++++++++++++-----
app/packages/page.tsx | 15 ++++++++++-----
app/services/articleService.ts | 23 ++++++++++++++++++-----
3 files changed, 47 insertions(+), 15 deletions(-)
diff --git a/PACKAGE-INSTALL.md b/PACKAGE-INSTALL.md
index ef20068..d30d279 100644
--- a/PACKAGE-INSTALL.md
+++ b/PACKAGE-INSTALL.md
@@ -102,6 +102,14 @@ mongosh 'mongodb://admin:@127.0.0.1:10260/mydb?tls=true&tlsAllowInvali
--eval 'db.runCommand({ping: 1})'
```
+If the password contains `@`, `:`, `/` or other reserved characters it must be percent-encoded
+in the URI (`@` becomes `%40`). To avoid encoding entirely, pass the credentials as flags:
+
+```bash
+mongosh localhost:10260 -u admin -p --authenticationMechanism SCRAM-SHA-256 \
+ --tls --tlsAllowInvalidCertificates --eval 'db.runCommand({ping: 1})'
+```
+
A first database and collection are created on first write:
```javascript
@@ -163,16 +171,22 @@ instead; re-run `documentdb-setup` to restart it.
**Remove or reset:**
```bash
+# Stop the stack first — package removal deletes files but does not stop a
+# running gateway. On systemd hosts:
+sudo systemctl stop documentdb-local@18.target
+# Without systemd the wizard started the gateway directly; kill that process.
+
sudo documentdb-setup --restore # detach the managed integration
sudo documentdb-local-reset --pg-version 18 --confirm-destroy # DESTROYS the data directory
-# Removing the meta package alone leaves the stack installed — it only owns the
-# dependency on the per-major package. Remove that too, and let autoremove reap
-# documentdb-common, documentdb-gateway and documentdb-postgresql-tools.
-sudo apt remove --autoremove documentdb documentdb-18
-sudo dnf remove documentdb documentdb-18 && sudo dnf autoremove
+# Name the package you installed AND the extension: autoremove does not reap
+# postgresql-18-documentdb, and `remove` would leave its config behind.
+sudo apt purge --autoremove documentdb-18 postgresql-18-documentdb
+sudo dnf remove documentdb-18 postgresql18-documentdb && sudo dnf autoremove
```
+If you installed the `documentdb` meta package rather than `documentdb-18`, name that instead.
+
### What the packages are
| Package | Role |
diff --git a/app/packages/page.tsx b/app/packages/page.tsx
index 5e22d86..ee63af6 100644
--- a/app/packages/page.tsx
+++ b/app/packages/page.tsx
@@ -498,7 +498,10 @@ export default function PackagesPage() {
- Use the commands below to discover available versions before pinning. Replace{" "}
+ Use the commands below to discover available versions before pinning. The
+ examples name the extension package; substitute{" "}
+ {selectedPackageNames} to pin the package
+ your selected target actually installs. Replace{" "}
<VERSION> with the version string
shown by the list command (e.g.{" "}
{repoAptVersionExample} for APT,{" "}
@@ -604,10 +607,12 @@ export default function PackagesPage() {
3. Connect and try it
- Docker starts a gateway-backed local endpoint on port 10260. Linux packages install
- the PostgreSQL extension; the Linux package guide adds the extra source-gateway
- steps needed when you want a host install that still exposes a MongoDB-compatible
- endpoint.
+ Docker starts a gateway-backed local endpoint on port 10260. On Ubuntu 24.04 and
+ RHEL-compatible 9 the packages give you the same thing: install, then run{" "}
+ sudo documentdb-setup --admin-user admin,
+ which creates the database and starts the gateway. On the extension-only
+ distributions the Linux package guide covers the additional source-gateway steps
+ needed to expose a MongoDB-compatible endpoint.
diff --git a/app/services/articleService.ts b/app/services/articleService.ts
index 4bf91bc..9d7db2a 100644
--- a/app/services/articleService.ts
+++ b/app/services/articleService.ts
@@ -163,6 +163,13 @@ mongosh 'mongodb://admin:@127.0.0.1:10260/mydb?tls=true&tlsAllowInvali
--eval 'db.runCommand({ping: 1})'
\`\`\`
+If the password contains \`@\`, \`:\`, \`/\` or other reserved characters it must be percent-encoded in the URI (\`@\` becomes \`%40\`), otherwise the URI misparses. To avoid encoding entirely, pass the credentials as flags instead:
+
+\`\`\`bash
+mongosh localhost:10260 -u admin -p --authenticationMechanism SCRAM-SHA-256 \\
+ --tls --tlsAllowInvalidCertificates --eval 'db.runCommand({ping: 1})'
+\`\`\`
+
A database and collection are created on first write:
\`\`\`javascript
@@ -211,16 +218,22 @@ On hosts without systemd the wizard starts the gateway directly; re-run \`docume
Remove or reset:
\`\`\`bash
+# Stop the stack first — package removal deletes files but does not stop a
+# running gateway. On systemd hosts:
+sudo systemctl stop documentdb-local@18.target
+# Without systemd the wizard started the gateway directly; kill that process.
+
sudo documentdb-setup --restore # detach the managed integration
sudo documentdb-local-reset --pg-version 18 --confirm-destroy # DESTROYS the data directory
-# Removing the meta package alone leaves the stack installed - it only owns the
-# dependency on the per-major package. Remove that too and let autoremove reap
-# the shared payload.
-sudo apt remove --autoremove documentdb documentdb-18
-sudo dnf remove documentdb documentdb-18 && sudo dnf autoremove
+# Name the package you installed AND the extension: autoremove does not reap
+# postgresql-18-documentdb, and \`remove\` would leave config behind.
+sudo apt purge --autoremove documentdb-18 postgresql-18-documentdb
+sudo dnf remove documentdb-18 postgresql18-documentdb && sudo dnf autoremove
\`\`\`
+(If you installed the \`documentdb\` meta package rather than \`documentdb-18\`, name that instead.)
+
## Upgrading
A package upgrade only replaces files. Afterwards, update the extensions in every database that has DocumentDB installed: