# Deployment Guide

BotGuard exposes a single web root: **`platform/public`**. Everything else (app code, `.env`, storage)
must stay outside the document root. All servers below rewrite non-file requests to `public/index.php`.

## Checklist (production)

- [ ] `APP_ENV=production` and `APP_DEBUG=false` in `.env`
- [ ] Set a random `APP_KEY`: `php -r "echo bin2hex(random_bytes(32));"`
- [ ] Change the seeded admin password (or set `ADMIN_*` before first migrate)
- [ ] MySQL user has least privilege on the `botguard` schema only
- [ ] `storage/` is writable by the web user; **not** web-accessible
- [ ] HTTPS enabled (HSTS is emitted automatically over TLS)
- [ ] If behind Cloudflare/a proxy, set `TRUSTED_PROXIES` so the real client IP is used

## Apache

`public/.htaccess` already handles rewriting and hardening. Ensure `mod_rewrite` is enabled and the
vhost allows overrides:

```apache
<VirtualHost *:443>
    ServerName verify.example.com
    DocumentRoot /var/www/botguard/platform/public

    <Directory /var/www/botguard/platform/public>
        AllowOverride All
        Require all granted
    </Directory>

    SSLEngine on
    SSLCertificateFile      /etc/ssl/certs/example.crt
    SSLCertificateKeyFile   /etc/ssl/private/example.key
</VirtualHost>
```

## Nginx

```nginx
server {
    listen 443 ssl http2;
    server_name verify.example.com;
    root /var/www/botguard/platform/public;
    index index.php;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
    }

    location ~ /\.(?!well-known) { deny all; }   # block dotfiles
}
```

## LiteSpeed

LiteSpeed reads `public/.htaccess` natively — point the vhost document root at `platform/public` and
enable rewrite. No extra configuration needed.

## Cloudflare

- Works behind Cloudflare out of the box. Set `TRUSTED_PROXIES` to Cloudflare's ranges (or your edge IP)
  so `CF-Connecting-IP` / `CF-IPCountry` are trusted — the latter powers Geo statistics with no MaxMind DB.
- Keep "Rocket Loader" **off** for `/verify` so the challenge script executes deterministically.
- The Content-Security-Policy already allows the reCAPTCHA/hCaptcha/Turnstile origins.

## Cron (housekeeping, optional)

```cron
*/15 * * * *  php /var/www/botguard/platform/bin/migrate.php --seed >/dev/null 2>&1   # keep seeds present
```

Stale verification sessions and expired rate-limit rows are cleaned opportunistically at request time;
no cron is strictly required.
