pfSense: Optimizing PHP-FPM for Long-Term Web UI Performance

pfSense screenshot: Optimizing PHP-FPM for Long-Term WebUI Performance

I’m sharing these PHP-FPM tweaks for pfSense publicly to solicit feedback and help anyone exploring similar optimizations. There may be more efficient methods or edge cases I haven’t covered. I welcome any suggestions, improvements, or alternative approaches.

pfSense’s Web UI runs on PHP-FPM, and although the defaults work well out of the box, a few targeted tweaks can make a stable environment even more performative over days, weeks, and months of uptime.

Over the weekend, I dove into pfSense’s PHP-FPM boot templates to discover exactly where those settings live. This article is not part 2 of My $300 pfSense Firewall Appliance – Part 1: Unboxing series. Consider it a small side quest.

Below are four key areas to tune: OPCode caching, PHP.ini timeouts, input-vars limit, and the PHP-FPM process manager.

Note: These recommendations apply only to pfSense 2.7.x on appliances with 4 GB or more of RAM. Use at your own risk!

Where is PHP-FPM tuned for pfSense?

pfSense keeps all (as far as I’ve found) of its PHP-FPM tuning logic in /etc/rc.php_ini_setup. Below is a brief overview of the tweaks I’ve made to that file and why they matter.

# ─── opcache section ─────────────────────────────────────────
- OPCACHEMEMSIZE="50"
+ OPCACHEMEMSIZE="100"

# ─── php.ini section ───────────────────────────────────
- max_execution_time = 900
- request_terminate_timeout = 900
- max_input_time = 1800
- max_input_vars = 5000
+ max_execution_time = 300
+ request_terminate_timeout = 300
+ max_input_time = 600
+ max_input_vars = 10000


# ─── PHP-FPM pool for >1 GB RAM ────────────────────────────
- PHPFPMREQ=5000
+ PHPFPMREQ=0

Let’s go over the changes. From shell type and enter vi /etc/rc.php_ini_setup and compare your settings with the recommendations below.

1. Increase OPCache Size

Increase PHP OPCache size

By default, pfSense allocates a max of 50 MB for PHP’s OPCache on systems with at least 1 GB of RAM. On an appliance with plenty of RAM, you can increase that to avoid unwanted cache pruning and keep compiled scripts in memory longer:

# ── in /etc/rc.php_ini_setup ──
if [ "$AVAILMEM" -gt "784" ]; then
OPCACHEMEMSIZE="100"
fi

With 8 GB installed, a 100 MB of PHP OPCache cache costs almost nothing but reduces the likelihood of OPCache restarts. Especially useful once you add more pfSense packages, and there are many useful packages available.

2. Tighten PHP-ini Timeouts, Raise Input Vars

pfSense template: PHP.ini tweaks.

pfSense’s default PHP timeouts let scripts run (and hang) for 15–30 minutes. You can safely trim them for WebUI tasks, and double the max_input_vars to handle larger config forms:

max_execution_time     = 300
request_terminate_timeout = 300
max_input_time         = 600
max_input_vars         = 10000

Here’s my reasoning (if I find any bugs over time, I will be sure to update):

  • Lowering max_execution_time and request_terminate_timeout to 5 minutes is more than enough for any legitimate WebUI task to complete, while making it faster to clean up stuck processes.
  • Dropping max_input_time to 10 minutes keeps input processing generous but avoids unnecessarily long lockups on stalled uploads or bad sessions.
  • Doubling max_input_vars to 10,000 prepares the system to handle larger config saves without hitting the default input variable limits, especially if you add more firewall rules, NAT settings, or packages like pfBlockerNG.

3. Use ‘pm static’ for max performance

Switched pfSense PHP-FPM from dynamic to static.

In a previous article on PHP-FPM performance tuning, I wrote:

“I have pm.max_requests set extremely high because this is a production server with no PHP memory leaks. You can use pm.max_requests = 0 with static if you have 110% confidence in your current and future PHP scripts. However, it’s recommended to restart scripts over time.”

So I have my pfSense pm.max_requests=0 (PHPFPMREQ). However, I would just recommend increasing the default ‘5000’ limit (frequency of restarts/clearing process cache).  A fixed (“static”) pool of PHP-FPM workers avoids on-the-fly spawning latency of hitting max requests. I updated the template for systems with more than >1 GB of memory from:

PHPFPMREQ=5000

Changed to:

PHPFPMREQ=50000
fi

Next, this is the block of code responsible for setting the process manager to ondemand, dynamic or static:

if [ $REALMEM -lt 350 ]; then
/bin/cat >> /usr/local/lib/php-fpm.conf <<EOF

pm = ondemand
pm.process_idle_timeout = $PHPFPMIDLE
pm.max_children = $PHPFPMMAX
pm.max_requests = $PHPFPMREQ
EOF

elif [ $REALMEM -gt 1000 ]; then
/bin/cat >> /usr/local/lib/php-fpm.conf <<EOF

pm = dynamic
pm.process_idle_timeout = $PHPFPMIDLE
pm.max_children = $PHPFPMMAX
pm.start_servers = $PHPFPMSTART
pm.max_requests = $PHPFPMREQ
pm.min_spare_servers=1
pm.max_spare_servers= $PHPFPMSPARE

EOF
else

/bin/cat >> /usr/local/lib/php-fpm.conf <<EOF

pm = static
pm.max_children = $PHPFPMMAX
pm.max_requests = $PHPFPMREQ
EOF

To switch to static process manager, I changed this line:

elif [ $REALMEM -gt 1000 ]; then

to this:

elif [ $REALMEM -gt 100000 ]; then

4. Putting It All Together

Check the generated php-ini, check the active PHP-FPM pool file and verify via the PHP-FPM status page

After restarting PHP-FPM, verify your settings. To confirm which values actually made it into your running config, inspect the files after PHP-FPM restart:

Check the generated php-ini

grep -E 'opcache.memory_consumption|max_execution_time|request_terminate_timeout|max_input_time|max_input_vars' /usr/local/etc/php.ini

Check the active PHP-FPM pool file

grep -E 'pm =' /usr/local/lib/php-fpm.conf

You should see pm = static—showing which manager mode is in use.

Verify via the PHP-FPM status page

curl -k https://127.0.0.1/status

Look for “process manager: static” and your max_children value. Note: That the PHPFPMIDLE (pm.process_idle_timeout) setting only applies on dynamic and ondemand, it’s by design ignored by static pm. The static process manager then keeps the number of running processes most and stable without any overhead.

If you have PHP-FPM crashes or otherwise unstable Web UI, avoid these tweaks.

Next Steps:
• If you install heavy packages or multiple admins using the Web UI concurrently (unlikely), consider raising PHPFPMMAX to 10–12.
• Revisit and increase PHPFPMREQ after stability is proven. Longer lifespans mean less cache churn but more risk of memory leaks.

With OPCache, tightened timeouts, generous input limits, and a static worker pool, your pfSense PHP-FPM setup will deliver reliable, long-term performance. If login today and then two weeks later, you will benefit from cache. With the default ondemand and dynamic it means after an idle timeout of a few mins to 1 hour, things reset and clear.

Making these pfSense PHP and PHP-FPM tweaks permanent

Any edits you make under /etc/rc.php_ini_setup or to the generated files in /usr/local will get blown away the next time pfSense gets updated. To make your tweaks stick, put them into a patch or a boot-time script that’s stored in your config—pfSense will reapply it every reboot or upgrade, revert if broken after update:

Install the System Patches package.

Create a new patch targeting src/etc/rc.php_ini_setup.

Paste your diffs (the changes to OPCACHEMEMSIZE, php-ini values, the REALMEM thresholds, etc.):

--- etc/rc.php_ini_setup
+++ etc/rc.php_ini_setup
@@ -92,7 +92,7 @@
-if [ "$AVAILMEM" -gt "784" ]; then
-    OPCACHEMEMSIZE="50"
+if [ "$AVAILMEM" -gt "784" ]; then
+    OPCACHEMEMSIZE="100"
 fi

@@ -115,7 +115,7 @@
-max_execution_time        = 900
-request_terminate_timeout = 900
-max_input_time            = 1800
-max_input_vars            = 5000
+max_execution_time        = 300
+request_terminate_timeout = 300
+max_input_time            = 600
+max_input_vars            = 10000

@@ -170,7 +170,7 @@
-elif [ ${REALMEM} -gt 1000 ]; then
-    PHPFPMMAX=8
-    PHPFPMIDLE=60
-    PHPFPMSTART=2
-    PHPFPMSPARE=7
-    PHPFPMREQ=5000
+elif [ ${REALMEM} -gt 1000 ]; then
+    PHPFPMREQ=500
 fi

@@ -200,1 +200,1 @@
-elif [ $REALMEM -gt 1000 ]; then
+elif [ $REALMEM -gt 100000 ]; then

Save and Apply.

The patch lives inside your config.xml, so it’s automatically reapplied on upgrades. Using System Patches in pfSense is designed to be safe and transparent. Failed patches are clearly flagged, do not silently break your system. This makes the process upgrade-safe and user-friendly. Some of the things I’m enjoying already about pfSense.

Tags: , , ,



Top ↑