> For the complete documentation index, see [llms.txt](https://nytshift.gitbook.io/nytshift-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://nytshift.gitbook.io/nytshift-docs/release-and-readiness/postgres-offsite-recovery.md).

# PostgreSQL off-host recovery

NYTSHIFT's same-host encrypted logical backup is operator-error recovery, not host-loss recovery and not point-in-time recovery. Before customer capital or real-money use, retain verified encrypted copies in a separately credentialed off-host destination and establish an independently rehearsed PITR path.

## Off-host logical-copy boundary

The repository provides `infra/postgres/offsite-rclone.sh` and matching systemd service/timer templates. The job is deliberately narrower than a generic sync:

* it accepts only the fixed local backup, rclone-config, state and lock paths;
* the rclone configuration must be a regular `root:root` mode `0600` file;
* the remote must already exist in that protected configuration;
* every encrypted dump, checksum and metadata companion must be a protected regular file; the encrypted SHA-256 is recomputed before transfer and the bounded metadata must identify the same timestamp, encrypted byte count and digest with `roundTripVerified: true`;
* legacy sets whose otherwise valid bounded metadata predates the round-trip field are counted and skipped without mutation; malformed or inconsistent metadata fails the entire job, and a protected explicit manifest limits the transfer to eligible sets only;
* `rclone copy --immutable` can add a missing object but cannot replace a conflicting object or propagate a local deletion;
* `rclone check --download --one-way` independently reads the retained remote objects after upload;
* output contains only the backup-set count, latest safe filename and a SHA-256 fingerprint of the remote identity. Provider error bodies and the remote path are not printed;
* the service receives no provider-RPC, wallet, signer, execution or alerting secret.

Install the reviewed files without enabling the timer:

```sh
install -o root -g root -m 0755 infra/postgres/offsite-rclone.sh /usr/local/sbin/nytshift-postgres-offsite
install -o root -g root -m 0644 infra/systemd/nytshift-postgres-offsite.service infra/systemd/nytshift-postgres-offsite.timer /etc/systemd/system/
systemctl daemon-reload
```

An owner must create or choose the off-host account and destination. Store its rclone configuration only at `/etc/nytshift/rclone.conf`, owned by `root:root` with mode `0600`. Install `/etc/nytshift/postgres-offsite.env` with the same ownership and mode, containing only the reviewed `remote:path` destination and, if an encrypted rclone configuration requires it, the protected rclone config password. Do not put either file in source control, chat, tickets or shell logs.

Before enabling unattended transfer:

1. Install the reviewed round-trip-verifying same-host backup script and create a new backup set; older metadata without `roundTripVerified: true` is deliberately ineligible for off-host publication and is reported as skipped rather than rewritten.
2. Confirm the destination account is separately credentialed from the VPS and has encryption, object-versioning or immutability, retention and access-alert policies appropriate to the recovery objectives.
3. Start the one-shot service manually and retain its secret-free state: `systemctl start nytshift-postgres-offsite.service`.
4. Independently inspect the destination from a recovery identity and verify the encrypted dump, checksum and metadata objects exist.
5. Restore the copied dump into an isolated PostgreSQL instance, verify its GPG decryption, `pg_restore --list`, migrations, constraints, row counts and application invariants. Never attach the rehearsal database to production.
6. Enable the timer only after that rehearsal passes: `systemctl enable --now nytshift-postgres-offsite.timer`.

The timer runs after the existing daily logical-backup window. It has no remote retention authority; remote retention must be enforced at the provider so a compromised host cannot erase historical recovery points.

## PITR remains separate

Logical-copy success does not prove PITR. Select a reviewed PostgreSQL-native PITR mechanism—managed-provider snapshots/PITR, pgBackRest, WAL-G, or an equivalent independently reviewed archive—after the destination and recovery objectives are known. Record at minimum:

* maximum tolerable data loss (RPO) and recovery time (RTO);
* base-backup cadence, continuous WAL archive destination and retention;
* encryption and keys controlled outside the database host;
* alerting for WAL archive lag/failure and a documented fail-closed response;
* an isolated timestamp-target restore proving migrations, constraints, counts, digests and application verification;
* quarterly rehearsal ownership and a rehearsal after material schema, retention, PostgreSQL-version or provider changes.

Do not turn on PostgreSQL `archive_mode` or install an `archive_command` until the chosen tool has durable spool/retry semantics, the off-host destination is ready, disk-pressure limits are reviewed, and a base backup plus target-time restore have been rehearsed. `archive_mode=on` without a healthy archive path can fill local storage and is not readiness.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://nytshift.gitbook.io/nytshift-docs/release-and-readiness/postgres-offsite-recovery.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
