01.01 System Requirements
The operating-environment prerequisites for SimpleRisk — PHP version, MySQL version and required SQL modes, the 12 PHP extensions, web server options, hardware sizing guidance, and the directory-permission requirements.
Why this matters
SimpleRisk's installer is permissive about what infrastructure you bring; it's strict about that infrastructure satisfying its prerequisites. The installer's first substantive screen is the Health Check, which validates PHP version, the required PHP extensions, directory permissions, web connectivity, and the MySQL SQL-mode configuration. Failing the health check is the single most common reason first-time installs stall — the operator gets the error message but doesn't know which package or configuration line to add to fix it.
This article is the comprehensive prerequisite reference. Read it before downloading SimpleRisk; install the missing pieces; then run the installer expecting the Health Check to pass on the first try. The fifteen minutes of upfront preparation save hours of "why won't the installer move past Step 2."
The other thing worth knowing: SimpleRisk runs on commodity LAMP-stack infrastructure. There's no exotic dependency, no proprietary runtime, no specialized hardware. If your team can run a typical PHP application, you can run SimpleRisk. The list below is detailed but not unusual for a PHP/MySQL web application of SimpleRisk's scope.
Reference content
PHP version
Required: PHP 8.3.0 or newer.
The version requirement is enforced by composer.json (the require.php field, set to ^8.3, and the config.platform.php field set to 8.3.36). The installer's Health Check verifies this; running on a PHP version older than 8.3 produces a clear error and blocks installation.
For ongoing operation, stay current with PHP point releases for security updates. SimpleRisk is tested against actively-supported PHP versions; running on a PHP version that's reached end-of-life leaves both PHP and SimpleRisk on the security-update treadmill the wrong way around.
MySQL version and configuration
Required: MySQL 8.x. SimpleRisk uses standard MySQL features and is tested against the 8.x series. Which 8.x you land on depends on how you install. The Linux setup script adds MySQL's own 8.4 LTS repository on Debian, RHEL-family, and SLES hosts, pinned deliberately so a vendor repository default can't pull a 9.x release in behind your back. On Ubuntu, mysql-server comes from Ubuntu's own archive instead — that's 8.0.46 on Ubuntu 24.04 LTS as of this writing. The official all-in-one Docker image is built on Ubuntu 24.04 and takes the same Ubuntu-archive path, so it runs the same 8.0.x. Both paths are supported.
For a new deployment where you control the MySQL source — a dedicated Linux host via the setup script, or a Docker Compose file where you pick the database image yourself — prefer 8.4 LTS. Upstream support for MySQL 8.0 ended in April 2026; Ubuntu continues to patch its own 8.0 package for the life of the 24.04 LTS, but 8.4 is the release with more runway left. Stay off 9.x either way — the setup script pins away from it and nothing is tested against it.
A note on MariaDB: earlier versions of SimpleRisk treated MariaDB as a supported MySQL-protocol-compatible alternative, and many customers ran it that way for years. We've since narrowed support back to MySQL only. Small differences in how MariaDB handled certain data types and query results produced inconsistencies that weren't worth maintaining a second supported path. If you're currently running on MariaDB, you can keep operating, but plan a migration to MySQL — new development and testing target MySQL exclusively, and we don't intend to chase MariaDB-specific behavior going forward.
The installer's Health Check validates the MySQL connection during Step 3 (Database Credentials) and explicitly checks for problematic SQL modes. Three SQL modes must be disabled for SimpleRisk to operate:
STRICT_TRANS_TABLES— strict trans-table mode interferes with SimpleRisk's INSERT and UPDATE patterns. Disable.NO_ZERO_DATE— SimpleRisk uses zero-date sentinels in some columns; this mode rejects them. Disable.ONLY_FULL_GROUP_BY— SimpleRisk's reporting queries don't always include every non-aggregated column in the GROUP BY clause; this mode rejects those queries. Disable.
These modes are often enabled by default on fresh MySQL installations. Either configure them off in your MySQL server's my.cnf (the [mysqld] section's sql_mode setting), or set them off per-session for the SimpleRisk user. The installer's Health Check tests for them and fails the install if any of the three are enabled — fix at the MySQL level rather than working around it.
The installer also creates a restricted MySQL user during Step 6 with the minimum privileges SimpleRisk needs: SELECT, INSERT, UPDATE, ALTER, DELETE, CREATE, DROP, INDEX, REFERENCES on the SimpleRisk database. The user's host pattern is configurable in Step 4 (defaults to localhost; supports comma-separated lists for multi-instance deployments).
Required PHP extensions
The installer's Health Check verifies thirteen PHP extensions. All must be installed and enabled before the installer will proceed past Step 2.
pdo: The PHP Data Objects abstraction layer SimpleRisk uses for all database access.pdo_mysql: The MySQL driver for PDO.json: JSON encoding and decoding (used throughout for API responses, configuration storage).phar: PHP archive support (used by some Composer dependencies and by Extras that ship as packaged archives).zlib: Compression (used for archive handling and some output compression).mbstring: Multi-byte string handling (required for the multi-language UI).ldap: LDAP authentication support (required even when LDAP isn't in active use).dom: XML/DOM manipulation (used by the SAML SSO Authentication Extra and by import/export functionality).curl: HTTP client (used during installation to fetch the database schema, by the Vulnerability Management Extra to talk to scanners, by the AI Extra to talk to providers, etc.).posix: POSIX functions (used by cron-related code paths).zip: ZIP archive support (used by the Import/Export Extra and by some content delivery paths).gd: The GD graphics library (used for QR code generation in MFA enrollment, image manipulation in dashboards).fileinfo: File type detection (used to verify the real type of uploaded files; uploads and imports are refused when it is missing).
On Debian/Ubuntu systems, install the missing extensions with apt install php8.3-{extension} (for example, php8.3-curl, php8.3-mbstring, etc.). On RHEL/CentOS/Rocky, use dnf install php-{extension} with the appropriate Remi or EPEL repositories enabled.
After installing extensions, restart your web server (systemctl restart apache2 or systemctl restart php8.3-fpm plus systemctl restart nginx) so the new extensions become available to PHP processes.
Web server options
SimpleRisk runs on any web server that can serve PHP. The two common deployments:
- Apache HTTP Server with mod_php — historically the most common SimpleRisk deployment. The web server's document root is set to the
simplerisk/directory. URL rewriting is generally not required (SimpleRisk uses direct PHP file paths), but.htaccess-style overrides are supported. - Nginx with PHP-FPM — increasingly common, especially in containerized deployments. The PHP-FPM upstream handles the PHP execution; Nginx serves static content directly. Standard PHP-FPM/Nginx configuration patterns apply.
Either web server works. The installer doesn't require a specific server choice.
Operating system
Supported: Linux. SimpleRisk's supported deployments run on Linux. The patterns customers use most:
- Linux on bare metal or VM (Ubuntu LTS, Debian stable, RHEL/CentOS/Rocky/Alma) — the standard production deployment. See Installing on Linux for the step-by-step.
- Docker — the containerized deployment, with the container images maintained in the separate
simplerisk/dockerrepository. See Installing via Docker. - Cloud-managed images — AWS Marketplace AMIs and similar pre-built images are available for several major cloud providers. See Installing on Cloud.
Windows and macOS are not supported as the host OS. PHP and MySQL technically run on both, but we don't test or support SimpleRisk against either as a runtime. If the only hardware you have is a Windows or macOS machine, run SimpleRisk inside a supported Linux environment on top of it — Docker Desktop, WSL2 with a supported Linux distribution, or a virtual machine (VirtualBox, Hyper-V, VMware, Parallels) running a supported Linux distribution. The SimpleRisk install lives inside the Linux environment; the Windows or macOS host is just the substrate the Linux environment runs on. Don't attempt to run SimpleRisk against PHP and MySQL installed directly on Windows or macOS — you'll hit path, permission, and service-control differences that aren't covered by our installer or support.
Hardware sizing
SimpleRisk's hardware needs scale with the program's data volume. There's no hard minimum; reasonable starting points:
- Small deployment (single team, fewer than 100 risks, fewer than 5 frameworks installed): 1–2 vCPU, 2 GB RAM, 20 GB disk. A single VM or container handles Apache/Nginx, PHP, and MySQL together.
- Mid-size deployment (multi-team, hundreds of risks, multiple frameworks, the Vulnerability Management Extra producing scanner imports): 2–4 vCPU, 4–8 GB RAM, 50–100 GB disk. Often still single-VM but with attention to MySQL tuning.
- Large deployment (enterprise, thousands of risks, the SCF Extra ingesting hundreds of frameworks, heavy concurrent user load): split MySQL onto its own host, give the web tier room for multiple PHP-FPM workers, plan disk for the multi-year audit-trail accumulation. 4+ vCPU per tier, 8+ GB RAM per tier, 200+ GB disk for the database.
Scale through the typical PHP-application levers: more PHP-FPM workers for concurrent request volume, more MySQL memory for query caching, faster disk for the database. SimpleRisk doesn't have unusual scaling characteristics; apply standard PHP/MySQL tuning practice.
Directory permissions
The web server user (typically www-data on Debian/Ubuntu, apache on RHEL family, the configured user on custom deployments) needs read and write access to the entire simplerisk/ directory tree. The installer's Health Check recursively verifies this; SimpleRisk needs write access for several runtime patterns:
- Configuration: the installer writes
simplerisk/includes/config.phpduring Step 6. - Logs: SimpleRisk writes operational logs to
simplerisk/logs/during normal operation. - File uploads: evidence files, document attachments, and other uploaded content land in writable directories.
- Cache: some Composer dependencies and SimpleRisk components cache compiled output.
Standard ownership pattern: chown -R www-data:www-data simplerisk/ (adjust user/group for your distribution) followed by chmod -R u+rw simplerisk/. Restrict group/world permissions per your security policy; the web server user needs read/write, others can be more restrictive.
Network connectivity
SimpleRisk needs outbound HTTPS for several install-time and runtime operations:
- During installation: outbound HTTPS to
raw.githubusercontent.comto fetch the database schema (the schema URL ishttps://raw.githubusercontent.com/simplerisk/database/{branch}/simplerisk-{language}-{version}.sql). - During runtime: outbound HTTPS for several Extras (Vulnerability Management Extra to scanner APIs, AI Extra to provider APIs, ComplianceForge SCF Extra to its content sources, the Notification Extra for outbound email if SMTP is over the public internet, etc.).
- For framework installation: outbound HTTPS to the SimpleRisk content GitHub repository when adding frameworks via the GitHub install path.
- For asset discovery: the Discover assets action on the Manage Assets page probes a range of addresses from the SimpleRisk server, so the server needs network reach to the ranges you scan, and a system administrator has to name those ranges in
config.phpfirst; see Allowing asset discovery targets below. How it probes depends on what the queue worker's process is allowed to do; see Asset discovery and container privileges below. Discovery also needs the queue worker to be running; see The Cron Jobs.
Air-gapped or heavily-firewalled deployments need to plan for these dependencies — either an outbound proxy that whitelists the relevant hosts, or alternative content paths (manual schema load, manual framework installation, self-hosted AI gateway). The installation itself can be completed on an air-gapped server only if the schema SQL is staged locally before Step 6.
Allowing asset discovery targets
A discovery run sends probes from your SimpleRisk server to every address in the range someone types in. That makes the server a network scanner for anyone holding the discovery permission, so the networks it may scan are decided outside the application, by whoever controls config.php. Until that list exists, discovery refuses every range: the Discover assets dialog says discovery is not configured and its start button stays off.
Add the list to simplerisk/includes/config.php:
$asset_discovery_allowed_ranges = ['10.20.0.0/16', '192.168.50.0/24', '10.1.2.3'];
Each entry is a single IPv4 address or an IPv4 CIDR block. A requested range has to fall entirely inside the listed entries (it may span several adjacent ones); a range that reaches one address past them is refused with a message saying it's outside the allowed ranges. Hostnames are accepted in the list but never match anything, because discovery ranges are addresses and SimpleRisk doesn't look names up to compare them. Entries it can't use (IPv6, a start–end range, a malformed block) are skipped and noted once in the debug log at warning level.
The list only adds permission. Loopback, link-local addresses (including the 169.254.169.254 cloud metadata address), multicast, and 0.0.0.0/8 are refused even if an entry covers them.
The list is checked when a run is started and again before each slice of a running scan, so narrowing or removing it stops runs that were already queued; those runs fail with the same explanation. The queue worker reads config.php when it starts. It notices when the file changes, finishes the task in hand, and exits, and cron starts a fresh worker with the new list within a minute; you don't need to restart anything yourself. In a Docker deployment, config.php lives on the volume you mounted for it: edit it there, not inside a replaceable container layer.
The Discover assets dialog shows the allowed ranges under the address field, so the people starting runs know what they can scan without asking.
Asset discovery and container privileges
Discovery sends the probes from the queue worker, not from the browser, and it checks what that process may do each time a run starts. It picks the first method that works, in this order:
- ICMP ping (unprivileged socket). A normal ping that needs no special privilege. Linux allows it when one of the worker's groups falls inside the kernel setting
net.ipv4.ping_group_range. Docker sets that range to0 2147483647for containers, which covers every user, so the standard SimpleRisk container gets this method even when the worker runs aswww-data. On a plain Linux host the kernel default is1 0, which turns it off. - ICMP ping (raw socket). Needs the
NET_RAWcapability. Running as root is not enough on its own: a container started with--cap-drop NET_RAW, or a Kubernetes pod whose security context drops it, reads as unavailable. - ICMP ping (ping command). The
pingprogram, if one is installed on the worker'sPATH(on Debian-based images, theiputils-pingpackage) and can actually ping. Discovery tries it against the loopback address first: in a container withoutNET_RAWand without ping sockets, an installedpingfails with "Operation not permitted" and discovery moves on to TCP. - TCP connect. Needs nothing. Discovery tries a short list of TCP ports on each address; a host counts as live when a port accepts the connection or actively refuses it. A host that silently drops every port on the list is missed, so results depend on the ports you choose. Some networks answer TCP connections for every address (a transparent proxy, or a firewall that resets everything), which would make each address look live. Before scanning, discovery connects to 192.0.2.1, a documentation address that is never a real host; if it answers, or if nearly every address in a block answers, the run stops with a failure explaining why rather than adding an asset for every address.
The method a run used is recorded on the run and shown under the range in the Discovery runs list. A run keeps its method until it finishes. If a run was started with a method the worker later can't use (the container was redeployed with fewer privileges mid-run, for example), it fails with a message saying so and you start a new one.
The Discover assets dialog shows the method as Probe method: {method}. That line comes from the worker's own check the last time it started a run. When the worker hasn't run discovery in the past week, the web server checks instead, and the dialog says so. The two can differ, because the web server and the worker often run as different users.
When only TCP connect is available, the dialog shows a caution and a TCP ports for this run field. The default list is 22,80,135,139,443,445,3389,8080. An administrator changes it under Settings cog → Settings Hub → Preferences tile → Asset Management tab → Asset discovery TCP ports: up to 20 port numbers between 1 and 65535, separated by commas. Clearing the field goes back to the default list. If you'd rather have ping, give the worker one of the first three methods. In Docker, keep the default ping_group_range (or set it with --sysctl net.ipv4.ping_group_range="0 2147483647") or keep NET_RAW. On a Linux host, widen net.ipv4.ping_group_range to include the worker's group, or install ping.
For troubleshooting, the asset_discovery_probe_method setting forces one method (icmp_dgram, icmp_raw, ping_binary, or tcp; the default is auto). A forced method the worker can't use is ignored and the run falls back to the normal order, with a warning in the debug log.