FreeBSD ships PHP 8.3 as binary packages, so PHP with Apache on FreeBSD 14 takes a few pkg install commands and one handler file. The packages you pull today also decide whether the box is exposed to PHP2Shell, the two remote code execution bugs PHP fixed in October 2026, and on FreeBSD the answer depends on which package branch your machine follows, not on what php -v prints.
This guide installs PHP 8.3 with the common extensions, wires it into Apache 2.4 through mod_php, tests it with a phpinfo page and a sample script, and then shows how to prove your own server runs a fixed build. Every pkg and service command below was run in October 2026 on a FreeBSD 14.0 VM with php83 and mod_php83 8.3.36 from the quarterly packages, using IGNORE_OSVERSION (explained in Step 1) and without running freebsd-update, and the text outputs come from that box.
PHP 8.3 added these language features over 8.2:
- Typed Class Constants: Support for declaring class, interface, trait, as well as enum constant types (collectively called “class constants” from now on for the sake of simplicity).
- New
#[Override]Attribute: By adding the#[\Override]attribute to a method, PHP will ensure that a method with the same name exists in a parent class or in an implemented interface. - Deep-cloning of readonly properties:
readonlyproperties may now be modified once within the magic__clonemethod to enable deep-cloning of readonly properties. - New
json_validate()function:json_validate()allows to check if a string is syntactically valid JSON, while being more efficient thanjson_decode(). - New
Randomizer::getBytesFromString()method: The Random Extension method is extended by a new method to generate random strings consisting of specific bytes only. This method allows the developer to easily generate random identifiers, such as domain names, and numeric strings of arbitrary length.
You need a FreeBSD 14 machine on 14.4 or later with network access and the root password. FreeBSD 15 uses the same package names, but we did not lab-test this guide on 15. For most web applications PHP runs alongside a database such as MariaDB on FreeBSD and a web server such as Nginx or Apache; this guide uses Apache.
Step 1. Update the FreeBSD repository
Every command in this guide runs as root, and the FreeBSD base system has no sudo, so switch to a root shell first.
su -
Bring the package catalogue and the base system up to date before installing anything, so PHP lands on current libraries.
pkg update && pkg upgrade
freebsd-update fetch
freebsd-update install
On a machine that is already current, both pkg commands end with Your packages are up to date. as in this 2024 capture.

On an older 14.x point release, pkg update can stop before it finishes. Our lab VM still ran 14.0 and refused the catalogue with this message:
Newer FreeBSD version for package zxfer:
To ignore this error set IGNORE_OSVERSION=yes
- package: 1404000
- running userland: 1400097
Ignore the mismatch and continue? [y/N]: pkg: repository FreeBSD contains packages for wrong OS version: FreeBSD:14:amd64
The FreeBSD:14 packages are built on 14.4 (1404000), the oldest 14.x release still supported, and 14.0 to 14.3 are past their end of life. FreeBSD 15.0 runs into the same mismatch, because the FreeBSD:15 packages are built on 15.1. Running with IGNORE_OSVERSION=yes lets pkg continue, and that is how we finished the lab, but it’s a stopgap. The real fix is moving to 14.4 or 14.5, which freebsd.org lists as supported until 31 December 2026 and 30 June 2027, or to FreeBSD 15 with the steps in our guide to upgrade FreeBSD 14 to 15 with freebsd-update.
Step 2. Install PHP 8.3 on FreeBSD
PHP 8.3 and its modules are in the FreeBSD binary package repositories, so there is nothing to compile. FreeBSD 13 is a different story: it reached end of life on 30 April 2026 and pkg.FreeBSD.org no longer serves FreeBSD:13 package sets, so this step only works on FreeBSD 14 or 15. Install the PHP package:
pkg install php83
The screenshot below was captured in March 2024, when the package was 8.3.1. A current install pulls a newer build, and the PHP2Shell step further down shows which one you need.

The base package gives you the PHP CLI and the PHP-FPM daemon. Extensions are separate packages on FreeBSD, so they come next.
Step 3. Install PHP 8.3 Extensions
Install the extensions most applications expect, plus the Apache module and two editors.
pkg install vim nano php83-xml mod_php83 php83-zip php83-mbstring php83-zlib php83-curl php83-mysqli php83-gd
pkg lists everything it will add before asking to proceed, and Apache is in that list because mod_php83 depends on it.

Each extension drops an ext-20-*.ini file into /usr/local/etc/php, which is how PHP loads it. Sessions live in a separate package, php83-session, which isn’t in the list above; add it if your application uses session_start().
Step 4. Install Apache Web Server
Apache serves the PHP pages. On our box mod_php83 had already pulled in apache24 as a dependency in Step 3, so this command only confirms it is there.
pkg install apache24
You can check the installation using the command below:
pkg info apache24
The name, version and origin www/apache24 confirm the package is in place.

Enable Apache at boot, start it and check its status.
sysrc apache24_enable=YES
service apache24 start
service apache24 status
Our first status call, run right after start, printed apache24 is not running. because httpd hadn’t written its PID file yet. Two seconds later the same command reported apache24 is running as pid 90., so wait a moment before you go hunting through /var/log/httpd-error.log. The AH00558 warning about the server’s fully qualified domain name is harmless and goes away once you set ServerName in httpd.conf.
Step 5. Test PHP 8.3 Installation
Apache loads libphp.so as soon as mod_php83 is installed, but it still needs a handler that sends .php files to PHP and a DirectoryIndex that includes index.php. Create the handler file.
vim /usr/local/etc/apache24/Includes/php.conf
Add the following configuration:
<IfModule dir_module>
DirectoryIndex index.php index.html
<FilesMatch "\.php$">
SetHandler application/x-httpd-php
</FilesMatch>
<FilesMatch "\.phps$">
SetHandler application/x-httpd-php-source
</FilesMatch>
</IfModule>
This capture shows the same handler block open in nano, if you prefer that editor.

Next, create a phpinfo page in Apache’s document root, /usr/local/www/apache24/data (Nginx users would use /usr/local/www/nginx):
vim /usr/local/www/apache24/data/info.php
Put a single phpinfo call in it.
<?php
phpinfo();
?>
Save and close the file then restart Apache service.
service apache24 restart
Before opening a browser, ask Apache for the page from the server itself. This shows the version Apache is actually running, which isn’t always the version the CLI reports:
curl -s http://localhost/info.php | grep -o 'PHP Version [0-9.]*' | head -1
Our server answered with the patched build:
PHP Version 8.3.36
In a web browser, open http://localhost/info.php (or the server’s IP, such as http://10.0.1.50/info.php). You should see the full PHP information page with Apache 2.0 Handler as the Server API. The screenshot is from the March 2024 capture, so it still shows 8.3.1; delete info.php once you’re done, because it tells anyone exactly which build you run.

PHP is working, so try a small page that mixes HTML and PHP. Create index.php in the document root:
vim /usr/local/www/apache24/data/index.php
Paste this sample page into it.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Simple HTML Page with PHP</title>
</head>
<body>
<h1>Hello, World!</h1>
<p>This is a simple HTML page generated using PHP.</p>
<?php
// You can include PHP code within the HTML content
$name = "John";
echo "<p>Welcome, $name!</p>";
?>
</body>
</html>
The same file open in nano looks like this before you save it.

Now open http://localhost/index.php in your browser and you should see the Hello World heading with the welcome line under it. Use the full /index.php path, because on our box a bare http://localhost/ still returned Apache’s stock “It works!” index.html. Apache 2.4 appends a second DirectoryIndex to the one in httpd.conf instead of replacing it, so index.html stays first; delete that file if you want index.php served at the root.

With the sample page rendering, the install itself is finished. The next step checks it against the October 2026 PHP security release.
Step 6. Check FreeBSD PHP for PHP2Shell (CVE-2026-109618, CVE-2026-109619)
PHP2Shell is a pair of critical bugs in PHP itself, CVE-2026-109618 and CVE-2026-109619, that allow remote code execution over HTTP. PHP’s 20 October pre-announcement rated both CVSS v4.0 9.2, and the PHP security advisory of 21 October 2026 shipped the fixes in 8.5.12, 8.4.27, 8.3.36 and 8.2.35. On FreeBSD the fix reached the package branches unevenly. The catalogues we pulled from pkg.FreeBSD.org at 20:18 UTC on 22 October 2026 showed:
- FreeBSD 14 quarterly (the default): php83 8.3.36, fixed
- FreeBSD 14 latest: php83 8.3.35, not fixed
- FreeBSD 15 latest: php83 8.3.36, fixed
- FreeBSD 15 quarterly: php83 8.3.35, not fixed
So a fresh FreeBSD 14 install from this guide on the default branch is already patched, and you can stop after the audit check below. An existing server needs the upgrade and the restarts that follow it. Start with the vulnerability database, which -F refreshes before checking:
pkg audit -F | grep -A4 '^php8'
A patched server prints nothing. On a box still running 8.3.35, the VuXML entry for PHP2Shell shows up like this:
php83-8.3.35 is vulnerable:
PHP -- Multiple vulnerabilities
CVE: CVE-2026-109618
CVE: CVE-2026-109619
WWW: https://vuxml.FreeBSD.org/freebsd/d8e16d08-cd2f-11f1-8135-8447094a420f.html
The audit only covers the php83 package. pkg audit mod_php83-8.3.35 reported zero problems in our test, yet mod_php83 is the library Apache actually loads, so check both versions yourself. Each must read 8.3.36 or later:
pkg query '%n %v' php83 mod_php83
Before upgrading, ask the repository what it would install. If pkg rquery still prints 8.3.35, your branch hasn’t caught up and pkg upgrade will report nothing to do:
pkg update -f && pkg rquery '%n %v' php83 mod_php83
Switch branch only if pkg rquery on your current branch shows 8.3.35 or older, and move to whichever branch offers 8.3.36 or later. Branches catch up at different times, so the snapshot list above can be out of date by the time you read this; the rquery output is what counts. The override is a file under /usr/local/etc/pkg/repos.
mkdir -p /usr/local/etc/pkg/repos
vim /usr/local/etc/pkg/repos/FreeBSD.conf
On FreeBSD 14 the default repository is named FreeBSD, so this switches it to the latest branch.
FreeBSD: {
url: "pkg+http://pkg.FreeBSD.org/${ABI}/latest"
}
We ran that form on our FreeBSD 14 box, and pkg -vv then listed pkg+https://pkg.FreeBSD.org/FreeBSD:14:amd64/latest with SRV mirrors and fingerprint signatures, and pkg update -f completed. FreeBSD 15 renamed the default repository to FreeBSD-ports, and an override still named FreeBSD there creates a second, unsigned repository instead of changing the default. The 15 form below follows the FreeBSD.conf that the 15.0 release ships, and we did not run it.
FreeBSD-ports: {
url: "pkg+https://pkg.FreeBSD.org/${ABI}/latest"
}
Run the pkg update -f and rquery line again to confirm the new branch offers 8.3.36. Deleting the file puts the machine back on quarterly. Once a fixed build is on offer, upgrade and restart everything that has PHP loaded:
pkg upgrade
service apache24 restart
service php_fpm restart
Skip the php_fpm line if you never set php_fpm_enable=YES, and restart long-running PHP CLI workers too. The restart isn’t optional: pkg didn’t restart anything in our test, and right after the upgrade php -v already printed 8.3.36 while Apache kept serving 8.3.35 from the old library. Confirm that both masters were started after the upgrade:
ps -o pid,etime,command -p $(cat /var/run/httpd.pid) $(cat /var/run/php-fpm.pid)
If you don’t run php_fpm, drop the $(cat /var/run/php-fpm.pid) part. Both elapsed times should be shorter than the time since the upgrade, and http://localhost/info.php should report 8.3.36:
PID ELAPSED COMMAND
566 00:03 /usr/local/sbin/httpd -DNOHTTPACCEPT
592 00:03 php-fpm: master process (/usr/local/etc/php-fpm.conf) (php-fpm)
If neither branch has a fixed package for your release, building lang/php83 and www/mod_php83 from a ports tree that already carries 8.3.36 is the other route. We didn’t run a ports build for this update. FreeBSD 13 has no package set at all any more, so a 13 server gets no fixed binary and needs to move to 14 or 15.
Until a fixed build is installed, PHP’s advisory lists mitigations that only reduce exposure, among them limits on field, part and header counts and nesting, so read it before relying on any of them. We tested three settings through real web requests. For mod_php, they go in a new Apache include file.
vim /usr/local/etc/apache24/Includes/php2shell.conf
Add the overrides, which apply to every request Apache hands to PHP:
<IfModule php_module>
php_admin_flag session.upload_progress.enabled off
php_admin_value memory_limit -1
php_admin_value post_max_size 8M
</IfModule>
Restart Apache with service apache24 restart so every child picks them up. If PHP-FPM serves your sites instead, the same settings go at the end of the pool file.
vim /usr/local/etc/php-fpm.d/www.conf
Append the pool form of the same settings, then run service php_fpm restart:
php_admin_flag[session.upload_progress.enabled] = off
php_admin_value[memory_limit] = -1
php_admin_value[post_max_size] = 8M
A probe page served by Apache went from upload_progress='1' memory_limit=128M to upload_progress='0' memory_limit=-1 post_max_size=8M under both mod_php and FPM, while php -r on the CLI still showed 1, so check through the web server. The upload progress setting only exists once php83-session is installed, and memory_limit -1 lets one request eat all the RAM, so watch memory and restore the limit after patching. Raise post_max_size to 32M if the site takes uploads, and keep upload_max_filesize below it. PHP is clear that these settings only reduce exposure: the upgrade is the fix.
Conclusion
You now have PHP 8.3 running under Apache on FreeBSD 14.4 or later, on a build you have checked against PHP2Shell. Keep pkg audit -F in your routine, because it catches the next PHP advisory the same way, and see how to manage packages and services on FreeBSD for the pkg and service commands this guide leaned on.