# Explorer Access Edge Enforcement Runbook

Operational runbook for enforcing explorer-issued API keys at the RPC edge for Chain 138 service lanes such as:

- `alltra-rpc` on VMID `2102`
- `thirdweb-rpc` on VMID `2103`
- approval-gated `core-rpc` on VMID `2101`

This complements the explorer access console and backend access APIs. The explorer can already issue, rotate, revoke, and validate keys; this runbook covers how to enforce those keys on nginx-facing RPC endpoints.

## Preconditions

- Explorer config/API backend is running on VMID `5000` and reachable at `127.0.0.1:8081`
- `ACCESS_INTERNAL_SECRET` is configured on the explorer API service
- Users and subscriptions are already managed through `/access`
- The target RPC lane is behind nginx or another proxy that can make a subrequest to the explorer API

## Canonical validator endpoint

- Internal: `http://127.0.0.1:8081/api/v1/access/internal/validate-key`
- Public-prefixed equivalent through explorer nginx: `https://explorer.d-bis.org/explorer-api/v1/access/internal/validate-key`

### Validator modes

- `GET` for nginx `auth_request`
  - supply `X-API-Key` or `Authorization: Bearer ...`
  - supply `X-Access-Internal-Secret`
  - returns `200` on success or `401` on rejection
  - includes headers such as:
    - `X-Validated-Product`
    - `X-Validated-Tier`
    - `X-Validated-Scopes`
    - `X-Quota-Remaining`
- `POST` for richer internal clients
  - JSON body with `api_key`, `method_name`, `request_count`, `last_ip`
  - returns JSON payload with validated key metadata

## Canonical nginx pattern

Use [`common/nginx-rpc-api-key-gate.conf`](./common/nginx-rpc-api-key-gate.conf) as the starting template.
For lane-specific rendered configs, use [`../scripts/render-rpc-access-gate-nginx.sh`](../scripts/render-rpc-access-gate-nginx.sh).

The important behavior is:

1. nginx receives user traffic
2. nginx subrequests `/__access_validate_rpc`
3. that subrequest calls the explorer validator with:
   - the client API key
   - the shared internal secret
   - request method and source IP
4. only validated requests are proxied to the protected RPC upstream

## Render a product-specific config

Instead of editing the template manually, render a concrete config for the target lane:

```bash
bash explorer-monorepo/scripts/render-rpc-access-gate-nginx.sh \
  --product thirdweb-rpc \
  --server-name thirdweb-rpc.example.org \
  --internal-secret "$ACCESS_INTERNAL_SECRET" \
  --output /etc/nginx/conf.d/thirdweb-rpc-gated.conf
```

Example for `alltra-rpc`:

```bash
bash explorer-monorepo/scripts/render-rpc-access-gate-nginx.sh \
  --product alltra-rpc \
  --server-name alltra-rpc.example.org \
  --internal-secret "$ACCESS_INTERNAL_SECRET" \
  --output /etc/nginx/conf.d/alltra-rpc-gated.conf
```

Example for `core-rpc` with an explicit upstream override:

```bash
bash explorer-monorepo/scripts/render-rpc-access-gate-nginx.sh \
  --product core-rpc \
  --server-name rpc-http-prv.d-bis.org \
  --internal-secret "$ACCESS_INTERNAL_SECRET" \
  --upstream http://192.168.11.211:8545 \
  --output /etc/nginx/conf.d/core-rpc-gated.conf
```

After rendering, verify syntax before reload:

```bash
nginx -t
systemctl reload nginx
```

## Recommended product mapping

| Product | Suggested public host | Upstream target |
|---|---|---|
| `core-rpc` | `rpc-http-prv.d-bis.org` | `http://192.168.11.211:8545` |
| `alltra-rpc` | partner/internal hostname | `http://192.168.11.212:8545` |
| `thirdweb-rpc` | managed SaaS/internal hostname | `http://192.168.11.217:8545` |

For `core-rpc`, keep manual approval enabled and consider IP allowlists in addition to API keys.

## Safe remote install workflow

For an operator-friendly rollout, use the dry-run-first installer:

```bash
bash explorer-monorepo/scripts/install-rpc-access-gate-nginx-via-ssh.sh \
  --product thirdweb-rpc \
  --server-name thirdweb-rpc.example.org \
  --ssh-host root@192.168.11.217 \
  --internal-secret "$ACCESS_INTERNAL_SECRET"
```

That prints the rendered config and planned remote target without mutating anything.

Apply only after review:

```bash
bash explorer-monorepo/scripts/install-rpc-access-gate-nginx-via-ssh.sh \
  --product thirdweb-rpc \
  --server-name thirdweb-rpc.example.org \
  --ssh-host root@192.168.11.217 \
  --internal-secret "$ACCESS_INTERNAL_SECRET" \
  --apply
```

By default the installer copies the config, runs `nginx -t`, and only then reloads nginx.

## Explorer API service env

At minimum, set:

```dotenv
ACCESS_ADMIN_EMAILS=ops@example.org,platform@example.org
ACCESS_INTERNAL_SECRET=replace-with-long-random-secret
```

## Verification

Use the dedicated verifier:

```bash
bash explorer-monorepo/scripts/verify-explorer-access-edge-hook.sh \
  --base-url https://explorer.d-bis.org \
  --internal-secret "$ACCESS_INTERNAL_SECRET"
```

To test a real key:

```bash
bash explorer-monorepo/scripts/verify-explorer-access-edge-hook.sh \
  --base-url https://explorer.d-bis.org \
  --internal-secret "$ACCESS_INTERNAL_SECRET" \
  --api-key "sk_live_example"
```

## Rollout order

1. Deploy explorer config/API backend so the validator endpoint is live
2. Confirm `ACCESS_INTERNAL_SECRET` is loaded in the service env
3. Apply nginx config for one protected lane first, usually `thirdweb-rpc`
4. Verify validation responses and upstream reachability
5. Expand to `alltra-rpc`
6. Apply stricter controls for `core-rpc` only after admin approval flow is tested

## Honest limits

- This repo now provides the validator hook, operator docs, and example edge config
- Actual enforcement still depends on where the RPC traffic is terminated
- Billing settlement, Stripe, or x402 monetization is a separate commercial layer
