# SafeTun database-free PHP backend

This directory contains the PHP 8.2+ authorization backend. It uses no database,
ORM, web installer, admin account, or web editor. Operator policy is held in one
literal-only `config.php` outside the HTTP document root. That file is tokenized
and validated before any value is used; it is never included or evaluated.

## cPanel installation

```sh
php bin/safetun-install.php \
  --private-dir=/home/USER/safetun-private \
  --public-dir=/home/USER/public_html/safetun-api
```

Then replace all `example.invalid` values, add only owned Iran IP/CIDRs, install
the tunnel certificate and offline-generated release public key/manifest, and run:

```sh
php /home/USER/safetun-private/bin/safetun-config-check.php \
  --docroot=/home/USER/public_html \
  /home/USER/safetun-private/config.php
```

Use `config.php.new -> php -l -> safetun-config-check -> atomic rename` for every
policy change. A new config is used only after complete parsing and validation.
Invalid config, unavailable file state, lock failure, and signing failure all fail
closed with a public error code and request ID.

The only public files are `index.php` and `.htaccess`. Source, config, signing
keys, nonce/rate state, manifests, and JSONL audit logs remain under the private
directory with `0700` directories and `0600` secrets. The audit log stores only
request IDs and one-way hashes; request bodies, IPs, nonces, leases, credentials,
and keys are never logged.

Add a cPanel cron job for bounded cleanup, for example:

```sh
php /home/USER/safetun-private/bin/safetun-cleanup.php \
  /home/USER/safetun-private/config.php
```

File-state replay protection is supported for a single cPanel host. Multiple
replicas without shared locking storage do not provide global nonce consumption
or rate limiting and are intentionally unsupported.
