7.3 KiB
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).
composeravailable for dev tasks.- SSH/privileged access to configure the site pool and run provisioning scripts.
Quick overview
- Place
uploadshield.phpin a secure per-site folder (recommended.security). - Create
logs/,quarantine/,state/and set strict ownership and permissions. - Configure
uploadshield.jsonfor your environment; keepops.block_suspiciousoff for initial tuning. - Enable
auto_prepend_filein the site PHP-FPM pool to run the logger before application code. - 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):
git clone <repo-url> /srv/uploadshield
cd /srv/uploadshield
composer install --no-interaction --prefer-dist
Run tests locally:
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
; Ensure uploadshield runs before application code
php_admin_value[auto_prepend_file] = /var/www/sites/example-site/.security/uploadshield.php
Then reload PHP-FPM:
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_filevia 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
uploadline appears in the log. - Upload a file containing
<?phpto confirm detectors logsuspicious_uploadentries. - Check
logs/uploads.logfor events.
php -S 127.0.0.1:8000 -t . -d auto_prepend_file=/var/www/sites/example-site/.security/uploadshield.php
# from site root
php -S 127.0.0.1:8000 -t . -d auto_prepend_file=/var/www/sites/example-site/.security/uploadshield.php
# then curl a file POST to your test endpoint
curl -F "file=@/path/to/sample.txt" http://127.0.0.1:8000/upload_test.php
8. Tuning & staging
- Keep
ops.block_suspiciousset tofalsewhile monitoring logs and tuning:allowlists.base64_uris— add URIs for trusted base64 endpoints.allowlists.ctypes— add trusted content-types such asimage/svg+xmlif needed.limits.sniff_max_bytes/limits.sniff_max_filesize— tune scanning cost vs coverage.
- Run the system under representative traffic and check for false positives.
9. Gradual enable blocking
- After tuning, enable blocking in a controlled manner:
- Set
ops.block_suspicious→trueinuploadshield.jsonon a small subset of sites or a canary host. - Monitor errors, rollback quickly if issues appear.
- Gradually roll out to remaining hosts.
- Set
10. Monitoring & alerting
- Forward
logs/uploads.logto your SIEM or log aggregator (Filebeat/Fluentd). - Create alerts for
event == suspicious_uploadorevent == raw_bodyand for rapid flood counts. - Monitor disk usage for
logs/and ensurelogrotateis active.
11. Security & operational checklist
- Ensure
quarantine/and.security/logsare not accessible from the web server. - Verify SELinux/AppArmor contexts after running provisioning.
- Ensure owner/group are set to root and web group (e.g.,
root:www-data) and modes match the guide. Keepuploadshield.phpreadable by root (644) and the logs readable only by the intended group (640).
Rollback
- Disable
php_admin_value[auto_prepend_file]in the pool and reload PHP-FPM. - Remove or rotate the
uploadshieldfiles if needed.
Further reading & files
- Integration notes: INTEGRATION.md
- Provisioning script:
scripts/provision_dirs.sh - Ansible playbook:
scripts/ansible/uploadshield-provision.yml - Example configuration:
uploadshield.json
If you want, I can: (a) generate a site-specific copy of these snippets for your exact paths/PHP version, (b) open a PR with the updated documentation, or (c) produce a one-command installer playbook that runs the provisioning and copies files to a remote host. Tell me which option you prefer.