# Installation & Production Deployment Guide This guide shows a minimal, secure installation and rollout path for UploadShield's primary script (`uploadshield.php`). Follow these steps in a staging environment first; do not enable blocking until detectors are tuned. **Prerequisites** - A Linux host running PHP-FPM (PHP 8.0+ recommended). - `composer` available for dev tasks. - SSH/privileged access to configure the site pool and run provisioning scripts. **Quick overview** 1. Place `uploadshield.php` in a secure per-site folder (recommended `.security`). 2. Create `logs/`, `quarantine/`, `state/` and set strict ownership and permissions. 3. Configure `uploadshield.json` for your environment; keep `ops.block_suspicious` off for initial tuning. 4. Enable `auto_prepend_file` in the site PHP-FPM pool to run the logger before application code. 5. Verify logging, tune detectors, deploy log rotation, and enable alerting. **1. Clone & dependencies (developer workstation)** - Clone the repository and install dev deps (for tests/static analysis): ```bash git clone /srv/uploadshield cd /srv/uploadshield composer install --no-interaction --prefer-dist ``` Run tests locally: ```bash vendor/bin/phpunit --configuration phpunit.xml vendor/bin/phpstan analyse -c phpstan.neon ``` **2. Recommended file layout (per-site)** Use a hidden per-site security folder so `uploadshield.php` is not web-accessible. Example layout: ``` /var/www/sites/example-site/ ├── public/ ├── app/ ├── uploads/ ├── .security/ │ ├── uploadshield.php │ └── logs/ │ └── uploads.log ├── quarantine/ └── state/ Place `uploadshield.php` into `.security/uploadshield.php`. **3. Copy files & configure** - Place `uploadshield.php` into `.security/uploadshield.php`. - Copy `uploadshield.json` from the repository to the same directory and edit paths to absolute values, e.g.: - `paths.log_file` → `/var/www/sites/example-site/.security/logs/uploads.log` - `paths.quarantine_dir` → `/var/www/sites/example-site/quarantine` - `paths.state_dir` → `/var/www/sites/example-site/state` - Ensure `ops.block_suspicious` is `false` initially (observe mode). **4. Create directories & set permissions (run as root)** Adjust user/group to your site environment (`www-data` used in examples): ```bash # example: run on target host as root mkdir -p /var/www/sites/example-site/.security/logs mkdir -p /var/www/sites/example-site/quarantine mkdir -p /var/www/sites/example-site/state chown -R root:www-data /var/www/sites/example-site/.security chmod 750 /var/www/sites/example-site/.security chmod 750 /var/www/sites/example-site/.security/logs # quarantine must be restrictive chown -R root:www-data /var/www/sites/example-site/quarantine chmod 0700 /var/www/sites/example-site/quarantine # state directory writable by PHP-FPM if required (group-write) chown -R root:www-data /var/www/sites/example-site/state chmod 0750 /var/www/sites/example-site/state # ensure log file exists with safe perms touch /var/www/sites/example-site/.security/logs/uploads.log chown root:www-data /var/www/sites/example-site/.security/logs/uploads.log chmod 0640 /var/www/sites/example-site/.security/logs/uploads.log ``` Alternatively use the included provisioning scripts on the host: - `scripts/provision_dirs.sh` — run as root; idempotent and attempts to set SELinux fcontext. - `scripts/ansible/uploadshield-provision.yml` — Ansible playbook for bulk provisioning. **5. PHP‑FPM configuration (per-site pool)** Edit the site's FPM pool (example: `/etc/php/8.1/fpm/pool.d/example-site.conf`) and add: php_admin_value[auto_prepend_file] = /var/www/sites/example-site/.security/uploadshield.php ```ini ; Ensure uploadshield runs before application code php_admin_value[auto_prepend_file] = /var/www/sites/example-site/.security/uploadshield.php ``` Then reload PHP-FPM: ```bash sudo systemctl reload php8.1-fpm ``` Notes: - Use the absolute path to `uploadshield.php`. - If your host uses a shared PHP-FPM pool, consider enabling per-vhost `auto_prepend_file` via nginx/apache or create a dedicated pool for the site. **6. Log rotation** Create `/etc/logrotate.d/uploadshield` with content adapted to your paths: ``` /var/www/sites/example-site/.security/logs/uploads.log { rotate 7 size 10M compress missingok notifempty copytruncate create 0640 root www-data sharedscripts postrotate if systemctl is-active --quiet php8.1-fpm; then systemctl reload php8.1-fpm >/dev/null 2>&1 || true fi endscript } ``` `copytruncate` is safe and avoids needing to stop PHP; alternatively use `postrotate` to reload FPM. **7. Verify installation (smoke tests)** - Upload a benign file via your app or via a simple test form and confirm a JSON `upload` line appears in the log. - Upload a file containing `