# OpenClaw VPS Hardening Acceptance Contract

Use this contract on a **fresh throwaway Ubuntu 24.04 VPS** before it receives
production credentials or traffic. It separates automated local checks from
the cloud, reboot, OpenClaw-audit, and handoff gates that still require an
operator.

- Checker: [openclaw-vps-readiness-check.sh](/openclaw-vps-readiness-check.sh)
- SHA-256: [openclaw-vps-readiness-check.sh.sha256](/openclaw-vps-readiness-check.sh.sha256)
- Checker version: `1.0.0`
- Outbound requests made by the checker: none
- Configuration changes made by the checker: none
- Hostnames, IP addresses, configuration values, environment values, and
  secret values printed by the checker: none
- Status: a newly built, brand-owned synthetic acceptance asset, not a claim
  about prior customer work
- Boundary: evidence and a repeatable checklist, not a security certification

## Inspect, verify, then run

```bash
curl -O https://agent-rescue-desk.netlify.app/openclaw-vps-readiness-check.sh
curl -O https://agent-rescue-desk.netlify.app/openclaw-vps-readiness-check.sh.sha256
sha256sum -c openclaw-vps-readiness-check.sh.sha256
less openclaw-vps-readiness-check.sh

sudo bash openclaw-vps-readiness-check.sh \
  --runtime-user openclaw \
  --openclaw-bin /home/openclaw/.local/bin/openclaw \
  --env-file /home/openclaw/.config/openclaw/gateway.env
```

Substitute the actual dedicated account and user-local paths. Root is required
only to read effective host and service state. The checker uses Ubuntu's
`unshare` utility to run its read-only OpenClaw CLI queries in a network-isolated
process namespace and fails closed if that isolation is unavailable. Do not run
code fetched from the internet with `sudo` until you have inspected it.

## Gate 1 — runtime and trust boundary

Pass only when:

1. the host is Ubuntu 24.04;
2. OpenClaw runs as a dedicated non-root account outside `sudo`, `admin`, and
   `wheel`;
3. the explicit OpenClaw binary resolves inside that account's home;
4. the state directory and `openclaw.json` are regular, runtime-owned paths
   with no group or world access;
5. `openclaw config validate --json` succeeds;
6. `gateway.bind` is `loopback`; and
7. gateway authentication is enabled.

OpenClaw's documented trust model assumes one trusted operator boundary per
gateway. Use separate gateways and preferably separate users or hosts for
mixed or adversarial trust boundaries.

## Gate 2 — SSH and firewall

Pass only when:

1. effective SSH configuration enables public-key authentication and disables
   password and keyboard-interactive authentication;
2. root SSH login is disabled and SSH uses TCP 22;
3. UFW is active, defaults to deny incoming, and allows no inbound service
   beyond SSH;
4. fail2ban and its `sshd` jail are active;
5. no non-loopback TCP listener exists except port 22; and
6. the VPS-provider firewall separately exposes only the agreed SSH source
   range.

Verify UDP and provider-private-network exposure separately. The checker does
not pretend a local TCP snapshot proves those surfaces.

## Gate 3 — OpenClaw audit

Run these explicitly as the dedicated OpenClaw account:

```bash
openclaw doctor
openclaw security audit
openclaw security audit --deep
openclaw health
```

Resolve every critical finding. Document each intentionally accepted warning
by its `checkId`. The checker deliberately does not run the deep audit because
it probes the live local gateway and deserves an explicit operator action.

## Gate 4 — systemd and secrets

Pass only when:

1. exactly one intended OpenClaw systemd unit is active and enabled;
2. a user unit has lingering enabled, or a system unit explicitly runs as the
   dedicated account;
3. the effective restart policy is `Restart=always`;
4. the unit references the declared environment file;
5. that file is runtime-owned, regular, not a symlink, and mode `0600`;
6. no secret-shaped value appears inline in `Environment=` or `ExecStart=`;
7. local shell-history review confirms no secret value was entered; and
8. a controlled reboot restores the gateway and monitoring without an
   interactive shell.

Review history locally and record only “clear” or “not clear.” Never copy shell
history or an environment file into a report, ticket, recording, or chat.

## Gate 5 — monitoring

The strict contract expects:

- active CrowdSec;
- an active CrowdSec firewall bouncer;
- active Netdata; and
- a loopback-only Netdata TCP listener when port `19999` is used.

An alternative passes only when the buyer accepts it in writing and the
runbook explains detection, alert delivery, retention, and recovery without
creating a new public control surface.

## Final handoff

Preserve:

1. exact Ubuntu, Node, OpenClaw, and monitoring versions plus the pinned
   install command;
2. redacted systemd, firewall, listener, audit, health, and reboot evidence;
3. the architecture and trust boundary;
4. backup, upgrade, rollback, credential-rotation, and access-removal steps;
5. a narrated screen recording of the important checks with no secret,
   customer data, public IP, or reusable credential visible.

“Service is running” is not acceptance. A second operator must be able to
identify exposure, reproduce validation, and reverse the change without
guessing.

## Official OpenClaw references

- [Security model and audit](https://docs.openclaw.ai/gateway/security)
- [Security audit check IDs](https://docs.openclaw.ai/gateway/security/audit-checks)
- [Gateway exposure runbook](https://docs.openclaw.ai/gateway/security/exposure-runbook)
- [Linux VPS and systemd guidance](https://docs.openclaw.ai/platforms/linux)
- [Read-only redacted configuration queries](https://docs.openclaw.ai/cli/config)

## Need a bounded recovery?

The [$1,000 12-Hour Agent Rescue](/#intake) covers one accepted broken agent
workflow or gateway path. The clock starts only after cleared payment, accepted
scope, a reproducible failure, and agreed access are all in place.
