diff --git a/app/docs/[section]/[[...slug]]/page.tsx b/app/docs/[section]/[[...slug]]/page.tsx
index 363c487..1e91f6d 100644
--- a/app/docs/[section]/[[...slug]]/page.tsx
+++ b/app/docs/[section]/[[...slug]]/page.tsx
@@ -133,12 +133,14 @@ export default async function ArticlePage({ params }: PageProps) {
const navigationLinks = navigation.map((item) => {
// Better matching logic for active state
// For index files, match both /section and /section/index
- // For other files, match the specific file name
+ // For other files, match the specific file name. Compare the final path
+ // segment exactly - a substring test marks every sibling whose slug
+ // starts with this one (packages also matching packages-operations).
const itemPath = item.link.replace('/docs/', '');
const currentPath = file === 'index' ? section : `${section}/${file}`;
const isActive = itemPath === currentPath ||
(file === 'index' && itemPath === `${section}/index`) ||
- (item.link.includes(file) && file !== 'index');
+ (file !== 'index' && item.link.split('/').pop() === file);
return (
/dev/null && \\
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 && \\
+echo "deb [arch=${arch} 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 ${installTarget}`;
}
@@ -100,17 +105,20 @@ export function buildRpmInstallCommand(
rpmPgVersion: RpmPgVersion,
): string {
const rhelMajorVersion = rpmMajorVersions[rpmTarget];
+ // See buildAptInstallCommand: "auto" resolves on the host so one published
+ // example works on x86_64 and aarch64 alike.
+ const arch = rpmArch === "auto" ? "$(uname -m)" : rpmArch;
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 && \\
+sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-${rhelMajorVersion}-${arch}/pgdg-redhat-repo-latest.noarch.rpm && \\
sudo dnf -qy module disable postgresql && \\
sudo dnf install -y dnf-plugins-core && \\
(sudo dnf config-manager --set-enabled crb || \\
sudo dnf config-manager --set-enabled powertools || \\
- sudo dnf config-manager --set-enabled codeready-builder-for-rhel-${rhelMajorVersion}-${rpmArch}-rpms) && \\
+ sudo dnf config-manager --set-enabled codeready-builder-for-rhel-${rhelMajorVersion}-${arch}-rpms) && \\
sudo rpm --import https://documentdb.io/documentdb-archive-keyring.gpg && \\
printf '%s\\n' \\
'[documentdb]' \\
diff --git a/app/services/articleService.ts b/app/services/articleService.ts
index 3f37b21..480ec8c 100644
--- a/app/services/articleService.ts
+++ b/app/services/articleService.ts
@@ -8,6 +8,20 @@ import { buildAptInstallCommand, buildRpmInstallCommand } from '../lib/packageIn
import { documentdbDiscordUrl } from './externalLinks';
const articlesDirectory = path.join(process.cwd(), 'articles');
+
+// Sections served entirely from this file rather than from the cloned
+// articles/ tree. Getting Started holds quick starts only; the longer-form
+// deployment guides live in their own section, alongside DocumentDB Local.
+const virtualSections: Record = {
+ 'linux-packages': {
+ landingTitle: 'Linux Packages',
+ pages: [
+ { slug: '', title: 'Operating a Package Install' },
+ { slug: 'offline', title: 'Offline / Air-gapped Install' },
+ ],
+ },
+};
+
const dockerGuideContent = `# Docker Quick Start
Run DocumentDB locally with Docker and verify the setup before moving to driver code.
@@ -145,100 +159,106 @@ If something does not work as expected:
const linuxPackagesGuideContent = `# Linux Packages Quick Start
-Install DocumentDB on Debian, Ubuntu, or RHEL-compatible hosts from the published package repository.
+Install DocumentDB from the published package repository and get a MongoDB-compatible endpoint on your own host.
-## Install
+**Ubuntu 24.04 and RHEL-compatible 9, on PostgreSQL 17 or 18**, get the full stack — extension, gateway, setup wizard and systemd units. Every other target gets the PostgreSQL extension without the endpoint: use the [Docker Quick Start](/docs/getting-started/docker) for an endpoint in one command, or the [Package Finder](/packages) for any other distribution, architecture or PostgreSQL major.
-**Ubuntu 24.04 and RHEL-compatible 9, on PostgreSQL 17 or 18**, get the full stack — extension, gateway, setup wizard and systemd units. Every other target is extension-only: see [Other targets](#other-targets).
+You do not need PostgreSQL already installed — the setup wizard creates and manages its own instance. The install does add the PGDG repository and pull PostgreSQL, PostGIS and around 160 packages (about 140 MB), so pick a host you are willing to have PGDG on.
+
+## Install
### Ubuntu 24.04, PostgreSQL 18 (APT)
\`\`\`bash
-${buildAptInstallCommand('ubuntu24', 'amd64', '18')}
+${buildAptInstallCommand('ubuntu24', 'auto', '18')}
\`\`\`
### RHEL-compatible 9, PostgreSQL 18 (RPM)
\`\`\`bash
-${buildRpmInstallCommand('rhel9', 'x86_64', '18')}
+${buildRpmInstallCommand('rhel9', 'auto', '18')}
\`\`\`
-For PostgreSQL 17, install \`documentdb-17\`; the \`documentdb\` meta package is equivalent to \`documentdb-18\`. For any other distribution, architecture or major, use the [Package Finder](/packages).
+For PostgreSQL 17, install \`documentdb-17\`; there is no \`documentdb-16\`. Keep the \`crb\` line on RHEL — without it \`dnf\` fails on \`libqhull_r.so.7\`.
-> [!NOTE]
-> In a container running as \`root\`, drop the leading \`sudo\` (it is often not installed). Leave \`sudo -u \` commands alone — those switch user rather than elevate; run them as \`su -c '...'\` instead. On Debian/Ubuntu also \`export DEBIAN_FRONTEND=noninteractive\` first, or \`tzdata\` prompts and the install hangs with no visible error.
+Then install \`mongosh\`, which you need to talk to the endpoint:
-> [!WARNING]
-> **On ARM, change three strings** — the commands above are written for x86_64.
->
-> | In | Replace | With |
-> | --- | --- | --- |
-> | APT \`documentdb.list\` line | \`arch=amd64\` | \`arch=$(dpkg --print-architecture)\` |
-> | RPM PGDG URL | \`EL-9-x86_64\` | \`EL-9-$(uname -m)\` (same for \`EL-8-x86_64\`) |
-> | RPM \`config-manager\` fallback | \`codeready-builder-for-rhel-9-x86_64-rpms\` | \`...-aarch64-rpms\` |
->
-> Neither failure names the architecture. APT reports \`documentdb-18 : Depends: postgresql-18-documentdb but it is not installable\` — only the extension package is arch-specific, so it is the one that goes missing. DNF reports \`Bad GPG signature\` on \`pgdg-common\`, because PGDG ships a separate reporpm per architecture under an identical file name.
+\`\`\`bash
+# Ubuntu 24.04
+curl -fsSL https://pgp.mongodb.com/server-8.0.asc | sudo gpg --dearmor -o /usr/share/keyrings/mongodb.gpg
+echo "deb [signed-by=/usr/share/keyrings/mongodb.gpg] https://repo.mongodb.org/apt/ubuntu noble/mongodb-org/8.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb.list
+sudo apt update && sudo apt install -y mongodb-mongosh
-> [!IMPORTANT]
-> **Do not drop the \`crb\` line.** PostGIS pulls in \`gdal*-libs\`, which needs \`libqhull_r.so.7\`, and that ships only in CRB (\`powertools\` on EL8). Without it \`dnf install\` fails with \`nothing provides libqhull_r.so.7()(64bit)\`, naming GDAL but never the missing repository.
+# RHEL-compatible 9
+printf '[mongodb-org-8.0]\\nname=MongoDB\\nbaseurl=https://repo.mongodb.org/yum/redhat/9/mongodb-org/8.0/$basearch/\\ngpgcheck=1\\nenabled=1\\ngpgkey=https://pgp.mongodb.com/server-8.0.asc\\n' | sudo tee /etc/yum.repos.d/mongodb.repo
+sudo dnf install -y mongodb-mongosh
+\`\`\`
## Set up and connect
+> [!IMPORTANT]
+> The wizard binds the gateway on **all interfaces** (\`0.0.0.0:10260\`) with a self-signed certificate. Firewall port \`10260\` before you run it on anything but a private machine, then read [Before exposing it to a network](/docs/linux-packages#before-exposing-it-to-a-network).
+
Installing the packages puts files on disk; it does not create a database or start the endpoint. The setup wizard does that:
\`\`\`bash
sudo documentdb-setup --admin-user admin
\`\`\`
-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\`.
+It creates the PostgreSQL instance, installs the extensions, starts the gateway, and enables it at boot. It **prompts for the admin password**.
-\`mongosh\` is not shipped by these packages. Install it from MongoDB's own repository — these are the two paved-road targets, and the [official instructions](https://www.mongodb.com/docs/mongodb-shell/install/) cover every other platform:
+Now open a shell against the endpoint:
\`\`\`bash
-# Ubuntu 24.04
-curl -fsSL https://www.mongodb.org/static/pgp/server-8.0.asc | sudo gpg --dearmor -o /usr/share/keyrings/mongodb-server-8.0.gpg
-echo "deb [signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg] https://repo.mongodb.org/apt/ubuntu noble/mongodb-org/8.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-8.0.list >/dev/null
-sudo apt update && sudo apt install -y mongodb-mongosh
-
-# RHEL-compatible 9
-printf '%s\\n' '[mongodb-org-8.0]' 'name=MongoDB Repository' \\
- "baseurl=https://repo.mongodb.org/yum/redhat/9/mongodb-org/8.0/$(uname -m)/" \\
- 'gpgcheck=1' 'enabled=1' 'gpgkey=https://pgp.mongodb.com/server-8.0.asc' | sudo tee /etc/yum.repos.d/mongodb-org-8.0.repo >/dev/null
-sudo dnf install -y mongodb-mongosh
+mongosh localhost:10260 -u admin -p '' --authenticationMechanism SCRAM-SHA-256 \\
+ --tls --tlsAllowInvalidCertificates
\`\`\`
-Then connect. A bare \`-p\` makes \`mongosh\` **prompt** for the password, so pass it inline in scripts and CI — otherwise a non-interactive shell sends an empty password and fails with the unhelpful \`MongoServerError: Invalid key\`:
+A database and collection are created on first write:
-\`\`\`bash
-mongosh localhost:10260 -u admin -p '' --authenticationMechanism SCRAM-SHA-256 \\
- --tls --tlsAllowInvalidCertificates --eval 'db.runCommand({ping: 1})'
+\`\`\`javascript
+> db.orders.insertOne({ item: "widget", qty: 5 })
+{ acknowledged: true, insertedId: ObjectId('...') }
+
+> db.orders.find()
+[ { _id: ObjectId('...'), item: 'widget', qty: 5 } ]
\`\`\`
-Or as a URI — percent-encode reserved characters in the password (\`@\` becomes \`%40\`), or it misparses:
+**That is a working DocumentDB.** Confirm the service state with \`sudo documentdb-setup --status\` and the version with \`documentdb-gateway --version\`.
-\`\`\`bash
-mongosh 'mongodb://admin:@127.0.0.1:10260/mydb?tls=true&tlsAllowInvalidCertificates=true' \\
- --eval 'db.runCommand({ping: 1})'
-\`\`\`
+## Where to go next
-A database and collection are created on first write:
+- Build an application: [Node.js Quick Start](/docs/getting-started/nodejs-setup) or [Python Quick Start](/docs/getting-started/python-setup)
+- Secure it, manage services, run SQL, upgrade, uninstall, and hosts without systemd: [Operating a package install](/docs/linux-packages)
+- Install without internet access: [Offline / air-gapped install](/docs/linux-packages/offline)
+- Another distribution, architecture or PostgreSQL major: [Package Finder](/packages)
-\`\`\`javascript
-db.orders.insertOne({ item: "widget", qty: 5 })
-db.orders.find()
-\`\`\`
+## Troubleshooting
+
+- \`Unable to locate package documentdb-18\` (apt) / \`No match for argument: documentdb-18\` (dnf) — the DocumentDB repository was not added, or that target is extension-only. Check the [Package Finder](/packages)
+- \`documentdb-18 : Depends: postgresql-18 but it is not installable\` — PGDG was not added first
+- \`nothing provides libqhull_r.so.7\` — the \`crb\` line did not run
+- \`MongoServerError: Invalid key\` — empty or wrong password; a bare \`-p\` prompts, so a non-interactive shell sends nothing
+- Anything else — \`sudo documentdb-setup --status\` reports the listener, service states and resolved paths
+
+More failure modes, including other distributions and hosts without systemd: [Operating a package install](/docs/linux-packages#troubleshooting).
+`;
+
+const linuxPackagesOperationsContent = `# Operating a package install
+
+Day-2 operations for a DocumentDB installed from Linux packages: securing the endpoint, managing services, running SQL, upgrading, and removal. Install first with the [Linux Packages Quick Start](/docs/getting-started/packages).
## 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.
+The gateway binds **all interfaces** (\`0.0.0.0:10260\` and \`[::]:10260\`) by default. 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.
+- 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\`. **Re-running \`documentdb-setup\` silently resets this to a wildcard bind**, so re-check with \`grep DOCUMENTDB_LISTEN_ADDR /etc/documentdb/local//gateway.env\` afterwards. 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
+## Services and paths
\`\`\`bash
sudo documentdb-setup --status # gateway listener, service states, resolved paths
@@ -246,17 +266,17 @@ documentdb-gateway --version # DocumentDB version
dpkg -l | grep documentdb # or: rpm -qa | grep documentdb
\`\`\`
-> Do not use \`db.version()\` or \`buildInfo\` in \`mongosh\` to check the DocumentDB version — those report the emulated MongoDB wire version, not DocumentDB's.
-
| 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\` |
+| Gateway log | systemd: \`journalctl -u documentdb-gateway-local@18.service\` · otherwise \`/var/lib/documentdb-gateway/gateway.log\` |
+| PostgreSQL log | systemd: \`journalctl -u documentdb-postgresql@18.service\` · otherwise \`/var/lib/documentdb-local//data/pglog.log\` |
| Setup state / gateway env | \`/etc/documentdb/local//setup.conf\`, \`.../gateway.env\` |
-Day 2 (units are templated per PostgreSQL major):
+On a systemd host both services log to the journal; the log **files** above exist only when \`documentdb-setup\` falls back to its non-systemd \`nohup\` mode. \`documentdb-setup --status\` prints whichever applies to your host.
+
+Units are templated per PostgreSQL major:
\`\`\`bash
sudo systemctl status documentdb-local@18.target
@@ -264,12 +284,7 @@ sudo systemctl restart documentdb-local@18.target
sudo systemctl stop documentdb-local@18.target
\`\`\`
-**Without systemd** (containers, some dev images) the wizard starts the gateway directly and says so. \`systemctl\` will fail with *"System has not been booted with systemd"* — use \`documentdb-setup --status\` to inspect, re-run \`documentdb-setup\` to restart, \`--restore\` to stop.
-
-> [!NOTE]
-> On a **minimal RHEL-compatible image, install \`procps-ng\` first**. \`documentdb-setup\` locates the directly-started gateway with \`pgrep\`; without it \`--restore\` reports success while the gateway keeps serving, and a later re-run then fails with \`Port 10260 is already in use\`. Debian and Ubuntu images already ship \`procps\`.
-
-### Running SQL against the managed instance
+## Running SQL against the managed instance
\`documentdb-setup\` runs a private instance as the \`documentdb-local\` user on a socket, so a bare \`psql\` will not find it:
@@ -277,20 +292,30 @@ sudo systemctl stop documentdb-local@18.target
sudo -u documentdb-local psql -h /run/documentdb-local/18/postgresql -p 9718 -d postgres
\`\`\`
-Use that connection for the \`ALTER EXTENSION\` statements under [Upgrading](#upgrading), and to read the installed versions:
-
\`\`\`sql
SELECT extname, extversion FROM pg_extension WHERE extname LIKE 'documentdb%';
\`\`\`
-### Remove or reset
+## 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.
+
+## Remove or reset
\`\`\`bash
-# Stop the stack first — package removal deletes files but does not stop a
-# running gateway. On systemd hosts:
+# Stop the stack first. On systemd hosts:
sudo systemctl stop documentdb-local@18.target
+# Without systemd, use an UNSCOPED restore (no --pg-version):
+sudo documentdb-setup --restore
-sudo documentdb-setup --restore # detach the managed integration
sudo documentdb-local-reset --pg-version 18 --confirm-destroy # DESTROYS the data directory
# Name the package you installed AND the extension: autoremove does not reap
@@ -299,54 +324,67 @@ sudo apt purge --autoremove documentdb-18 postgresql-18-documentdb
sudo dnf remove documentdb-18 postgresql18-documentdb && sudo dnf autoremove
\`\`\`
-## Upgrading
+Confirm the stack is down first with \`ss -lnt | grep 10260\`. A gateway still running when its packages go keeps serving from a deleted binary. On a multi-major host remove one major at a time and re-check the survivor: \`documentdb-common\` owns the shared tooling and only \`documentdb-N\` holds it.
-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
-\`\`\`
+## Known issues in 0.116
-PostgreSQL applies intermediate upgrade scripts automatically. In-place upgrades are not yet a fully tested path, so take a backup first.
+These are defects in this release, not expected behaviour. Most need a host without systemd to hit; the two marked **any host** do not.
-## Other targets
+| Area | Issue | Affects |
+| --- | --- | --- |
+| Status | \`documentdb-setup --status\` can report "active" for any process holding port 10260 | **any host** |
+| Upgrade | \`documentdb-setup\` does not run \`ALTER EXTENSION documentdb_core UPDATE\`; run it yourself | **any host** |
+| Restart | Re-running \`documentdb-setup\` to restart can hang; redirecting output to a file avoids it | no systemd |
+| Stop | \`documentdb-setup --restore --pg-version N\` reports success without stopping the gateway — use an unscoped \`--restore\`, which stops every major on the host | no systemd |
+| Minimal RHEL | Install \`procps-ng\` first, or \`--restore\` reports success while the gateway keeps serving and a later run fails with \`Port 10260 is already in use\` | no systemd |
+| Reset | \`documentdb-local-reset --confirm-destroy\` can report success while leaving a PostgreSQL process running | no systemd |
-The full stack is published only for **Ubuntu 24.04 and RHEL-compatible 9 on PostgreSQL 17 or 18**. Everywhere else — including **PostgreSQL 16 on every distribution** — you get the extension package alone: no gateway, no \`documentdb-setup\`, no systemd units. There is no \`documentdb-16\`; asking for it fails with *"has no installation candidate"* (APT) or *"No match for argument"* (DNF).
+**Prefer a systemd host for anything you care about**, where the service lifecycle is managed by systemd rather than by the setup script.
-| Distribution | PGDG suite | Repository component | Install |
-| --- | --- | --- | --- |
-| Ubuntu 24.04 | \`noble-pgdg\` | \`ubuntu24\` | \`documentdb-18\` / \`documentdb-17\` — full stack |
-| RHEL-compatible 9 | — | \`rpm/rhel9\` | \`documentdb-18\` / \`documentdb-17\` — full stack |
-| Ubuntu 22.04 | \`jammy-pgdg\` | \`ubuntu22\` | \`postgresql-18-documentdb\` |
-| Debian 11 | \`bullseye-pgdg\` | \`deb11\` | \`postgresql-17-documentdb\` — **PG 18 not installable** |
-| Debian 12 | \`bookworm-pgdg\` | \`deb12\` | \`postgresql-18-documentdb\` |
-| Debian 13 | \`trixie-pgdg\` | \`deb13\` | \`postgresql-18-documentdb\` |
-| RHEL-compatible 8 | — | \`rpm/rhel8\` | \`postgresql18-documentdb\` — \`EL-8\` URLs, \`powertools\` not \`crb\` |
+## Multiple PostgreSQL majors
-The APT repository is \`https://documentdb.io/deb stable \`; the RPM baseurl is \`https://documentdb.io/rpm/\`. It serves **0.116** on the full-stack targets and **0.114** everywhere else — \`apt-cache madison \` / \`dnf --showduplicates list \` show the truth.
+Install the matching \`documentdb-N\` for every major you configure. \`documentdb-setup\` refuses a major whose extension package is missing:
-**Debian 11 has no PostgreSQL 18** — the upstream Bullseye PostGIS build does not exist, so the install fails with \`Depends: postgresql-18-postgis-3 but it is not installable\`. Use 16 or 17.
-
-**Debian 13:** \`apt.postgresql.org\` also publishes this extension and its version sorts higher, so PGDG's build installs by default. Pin with \`apt install postgresql-18-documentdb=\` for this repository's copy.
+\`\`\`text
+ERROR: The DocumentDB extension package is not installed for PostgreSQL 17
+(/usr/share/postgresql/17/extension/documentdb.control is missing).
+\`\`\`
-Confirm the extension landed:
+Each major also needs its own gateway port — the second one fails on \`Gateway port 10260 is already in use\` unless you pass \`--gateway-port\`:
\`\`\`bash
-apt-cache policy postgresql-18-documentdb # or: dnf info postgresql18-documentdb
-dpkg -L postgresql-18-documentdb | grep -E 'documentdb.*\\.(control|sql|so)$' | head
+sudo documentdb-setup --pg-version 17 --gateway-port 10261 --admin-user admin
\`\`\`
-For a MongoDB-compatible endpoint on these hosts, use the [Docker Quick Start](/docs/getting-started/docker), or run the gateway from source against your host PostgreSQL with \`scripts/start_oss_server.sh\` and \`scripts/build_and_start_gateway.sh\` in the [DocumentDB repository](https://github.com/documentdb/documentdb). Run those as an unprivileged user, and \`export TERM=xterm\` first in non-interactive shells or the script aborts on \`tput\`.
+## Troubleshooting
+
+Failure modes beyond the four in the [quick start](/docs/getting-started/packages#troubleshooting):
+
+- \`Bad GPG signature\` on \`pgdg-common\` — wrong architecture in the PGDG repository URL
+- \`apt install\` hangs in a container — \`export DEBIAN_FRONTEND=noninteractive\` first, and drop the leading \`sudo\` when running as \`root\` (minimal images often have no \`sudo\`). Keep \`sudo -u \`, which switches user; \`su documentdb-local -c\` fails because that account has \`/usr/sbin/nologin\`, so use \`su -s /bin/bash documentdb-local -c '...'\`
+- Debian 11 has PostgreSQL 18 from PGDG but no \`postgresql-18-postgis-3\` for Bullseye, so the dependency set cannot be satisfied; use 16 or 17
+- \`ss: command not found\` on a minimal RHEL host — install \`iproute\`; the DocumentDB packages do not pull it in
+- Debian 13 also gets this extension from \`apt.postgresql.org\`, whose version sorts higher; pin with \`apt install postgresql-18-documentdb=\` for this repository's build
+- \`db.version()\` and \`buildInfo\` in \`mongosh\` report the emulated MongoDB wire version, not DocumentDB's — use \`documentdb-gateway --version\`
+
+## Multiple PostgreSQL majors
+
+Install the matching \`documentdb-N\` for every major you configure. \`documentdb-setup --pg-version N\` will happily configure a major whose package is absent, and nothing then owns the result — a later \`autoremove\` can reap \`documentdb-common\` out from under it.
-## Offline / air-gapped install
+## Unattended setup
+
+\`documentdb-setup\` prompts for the admin password. For servers and CI, pass \`--admin-password-file \` or \`--admin-password-stdin\` together with \`--yes\`.
+`;
+
+const linuxPackagesOfflineContent = `# Offline / air-gapped install
An air-gapped host has no route to PGDG either, and DocumentDB pulls PostgreSQL, \`pg_cron\`, \`pgvector\` and PostGIS from there — the release assets alone are not enough. Stage the full dependency closure on a connected machine with the **same distribution, release and architecture** as the target.
-### Stage the bundle (connected machine)
+For a connected host, use the [Linux Packages Quick Start](/docs/getting-started/packages) instead.
+
+## Stage the bundle (connected machine)
-With the same repositories configured as for an online install — run the [Install](#install) command for your distribution **up to and including \`apt update\` / the \`dnf config-manager\` line, but not the final \`install\`**:
+Configure the repositories exactly as for an online install: run the whole [Install](/docs/getting-started/packages#install) block for your distribution **except the final \`sudo apt install -y documentdb-18\` / \`sudo dnf install -y documentdb-18\` line** — delete that line and the \`&& \\\` that precedes it. On RHEL the DocumentDB repository is written by the \`tee /etc/yum.repos.d/documentdb.repo\` line near the end, so stopping earlier leaves \`dnf download\` with nothing to find. Then:
\`\`\`bash
# Debian / Ubuntu
@@ -370,9 +408,9 @@ createrepo_c bundle
> [!NOTE]
> **Use the full-closure flags, not \`--download-only\`.** \`apt-get install --download-only\` and a bare \`dnf download --resolve\` skip whatever is already installed on the staging machine; the bundle looks complete and the target dies with \`Depends: adduser but it is not installable\`.
-Expect ~200 packages / 200 MB (DEB) or ~270 / 170 MB (RPM), mostly PostGIS and GDAL. The \`unsandboxed as root\` and \`dpkg-scanpackages ... override file\` warnings are harmless.
+Expect ~200 packages / 200 MB (DEB) or ~270 / 170 MB (RPM), mostly PostGIS and GDAL. That is more than an online install downloads, because the closure includes packages already present on the staging machine. The \`unsandboxed as root\` and \`dpkg-scanpackages ... override file\` warnings are harmless.
-### Install from the bundle (air-gapped target)
+## Install from the bundle (air-gapped target)
Copy \`bundle/\` across — including the \`Packages\`/\`Packages.gz\` or \`repodata/\` index inside it, which is what makes the next step resolve — and point the package manager at it:
@@ -397,35 +435,16 @@ sudo dnf install -y --disablerepo='*' --enablerepo=documentdb-offline documentdb
\`[trusted=yes]\` / \`gpgcheck=0\` accept the unsigned local directory. Upstream signatures were verified at staging time; \`sha256sum\` the transfer if it crosses an untrusted boundary.
-Then continue with **Set up and connect** above — \`documentdb-setup\` needs no network.
+Then continue with [Set up and connect](/docs/getting-started/packages#set-up-and-connect) — \`documentdb-setup\` needs no network.
-### Smaller offline cases
+\`mongosh\` is **not** part of the bundle and the target cannot reach the MongoDB repository, so stage it in the same pass if you want to verify from the air-gapped host — add \`mongodb-mongosh\` to the package list after configuring the MongoDB repository shown in the quick start. Otherwise verify with \`sudo documentdb-setup --status\` and connect from a machine that does have \`mongosh\`.
+
+## Smaller offline cases
If the target already has PostgreSQL, the PGDG extension dependencies (\`postgresql-N-cron\`, \`-pgvector\`, \`-postgis-3\`) and \`jq\`, you do not need a bundle:
- **Extension only, one file** — \`sudo apt install ./ubuntu24.04-postgresql-18-documentdb_0.116-0_amd64.deb\`. No gateway and no \`documentdb-setup\`.
- **Full stack from the release assets** — pass all six files for your platform to a *single* \`apt install\` / \`dnf install\`. Local files resolve dependencies only against enabled repositories, so the meta package on its own fails with \`Depends: documentdb-18 ... but it is not installable\`.
-
-## Troubleshooting
-
-- \`sudo documentdb-setup --status\` reports the listener, service states and resolved paths
-- \`has no installation candidate\` / \`No match for argument\` — that target is extension-only, or PGDG was not added first. See [Other targets](#other-targets)
-- \`nothing provides libqhull_r.so.7\` — the \`crb\` line did not run
-- \`Depends: postgresql-N-documentdb but it is not installable\` — wrong \`arch=\` for the host
-- \`Bad GPG signature\` on \`pgdg-common\` — wrong architecture in the PGDG reporpm URL
-- \`apt install\` hangs in a container — \`export DEBIAN_FRONTEND=noninteractive\`
-- Debian 11 has no PostgreSQL 18 (no upstream Bullseye PostGIS); use 16 or 17
-
-## Next steps
-
-- [Docker Quick Start](/docs/getting-started/docker)
-- [Building the packages from source](https://github.com/documentdb/documentdb/blob/main/packaging/README.md)
-- [Mongo Shell Quick Start](/docs/getting-started/mongo-shell-quickstart)
-- [Node.js Quick Start](/docs/getting-started/nodejs-setup)
-- [Python Quick Start](/docs/getting-started/python-setup)
-- [API Reference](/docs/reference)
-- [Samples Gallery](/samples)
-- [Package Finder](/packages)
`;
const vscodeQuickStartGuideContent = `# Visual Studio Code Quick Start
@@ -1206,10 +1225,32 @@ function updateDocumentDbLocalContent(content: string): string {
export function getArticleContent(): Article {
const contentPath = path.join(articlesDirectory, 'content.yml');
const fileContents = fs.readFileSync(contentPath, 'utf8');
- return loadYaml(fileContents) as Article;
+ const article = loadYaml(fileContents) as Article;
+
+ // content.yml is cloned from the docs repo and does not know about sections
+ // served from this file, so surface them on the landing page here.
+ if (!article.landing.links.some((link) => link.link === '/docs/linux-packages')) {
+ const localIndex = article.landing.links.findIndex((link) => link.link === '/docs/documentdb-local');
+ const linuxPackagesLink = { title: 'Linux Packages', link: '/docs/linux-packages' };
+ article.landing.links.splice(
+ localIndex >= 0 ? localIndex + 1 : article.landing.links.length,
+ 0,
+ linuxPackagesLink,
+ );
+ }
+
+ return article;
}
export function getArticleNavigation(section: string): Link[] {
+ const virtual = virtualSections[section];
+ if (virtual) {
+ return virtual.pages.map(page => ({
+ title: page.title,
+ link: page.slug ? `/docs/${section}/${page.slug}` : `/docs/${section}`,
+ }));
+ }
+
const navPath = path.join(articlesDirectory, section, 'navigation.yml');
if (!fs.existsSync(navPath)) {
@@ -1279,7 +1320,7 @@ export function getAllSections(): string[] {
.filter(dirent => dirent.isDirectory())
.map(dirent => dirent.name);
- return sections;
+ return [...sections, ...Object.keys(virtualSections)];
}
export function getAllArticlePaths(): { section: string; slug: string[] }[] {
@@ -1287,6 +1328,14 @@ export function getAllArticlePaths(): { section: string; slug: string[] }[] {
const paths: { section: string; slug: string[] }[] = [];
sections.forEach(section => {
+ const virtual = virtualSections[section];
+ if (virtual) {
+ virtual.pages.forEach(page => {
+ paths.push({ section, slug: page.slug ? [page.slug] : [] });
+ });
+ return;
+ }
+
const sectionPath = path.join(articlesDirectory, section);
const files = fs.readdirSync(sectionPath, { withFileTypes: true })
.filter(dirent => dirent.isFile() && dirent.name.endsWith('.md'))
@@ -1329,6 +1378,32 @@ export function getArticleByPath(section: string, slug: string[] = []): {
const file = slug.length > 0 ? slug[slug.length - 1] : 'index';
const navigation = getArticleNavigation(section);
+ if (section === 'linux-packages' && file === 'index') {
+ return {
+ content: linuxPackagesOperationsContent,
+ frontmatter: {
+ title: 'Operating a Package Install',
+ description: 'Secure, manage, upgrade and remove a DocumentDB installed from Linux packages, plus known issues in 0.116.',
+ },
+ navigation,
+ section,
+ file,
+ };
+ }
+
+ if (section === 'linux-packages' && file === 'offline') {
+ return {
+ content: linuxPackagesOfflineContent,
+ frontmatter: {
+ title: 'Offline / Air-gapped Install',
+ description: 'Stage a full dependency closure on a connected machine and install DocumentDB on a host with no internet access.',
+ },
+ navigation,
+ section,
+ file,
+ };
+ }
+
if (section === 'getting-started' && file === 'docker') {
return {
content: dockerGuideContent,
diff --git a/tests/packageInstall.test.ts b/tests/packageInstall.test.ts
index c1c0ba8..15f309b 100644
--- a/tests/packageInstall.test.ts
+++ b/tests/packageInstall.test.ts
@@ -86,6 +86,15 @@ describe('buildAptInstallCommand', () => {
expect(command).toContain(`[arch=${arch} `);
});
+ it('resolves the architecture on the host when arch is "auto"', () => {
+ const command = buildAptInstallCommand('ubuntu24', 'auto', '18');
+ // The published doc example must be copy-pasteable on amd64 and arm64
+ // alike, so it shells out rather than baking in an architecture.
+ expect(command).toContain('[arch=$(dpkg --print-architecture) ');
+ expect(command).not.toContain('[arch=amd64 ');
+ expect(command).not.toContain('[arch=arm64 ');
+ });
+
it.each(aptDistros)('uses %s as the DocumentDB repository component', (distro) => {
const command = buildAptInstallCommand(distro, 'amd64', aptTargetPgVersions[distro][0]);
expect(command).toContain(`documentdb.io/deb stable ${distro}`);
@@ -130,6 +139,14 @@ describe('buildRpmInstallCommand', () => {
expect(command).toContain(`codeready-builder-for-rhel-9-${arch}-rpms`);
});
+ it('resolves the architecture on the host when arch is "auto"', () => {
+ const command = buildRpmInstallCommand('rhel9', 'auto', '18');
+ expect(command).toContain('EL-9-$(uname -m)/pgdg-redhat-repo-latest.noarch.rpm');
+ expect(command).toContain('codeready-builder-for-rhel-9-$(uname -m)-rpms');
+ expect(command).not.toContain('EL-9-x86_64');
+ expect(command).not.toContain('EL-9-aarch64');
+ });
+
it.each(rpmDistros)('points the DocumentDB repository at rpm/%s', (distro) => {
const command = buildRpmInstallCommand(distro, 'x86_64', '16');
expect(command).toContain(`baseurl=https://documentdb.io/rpm/${distro}`);