Step 3: Configure PHP-FPM to use the proxy
Add this to the bottom of your PHP-FPM pool configuration (typically /etc/php/8.5/fpm/pool.d/www.conf):
; --- SQUID PROXY INTEGRATION ---
; Prevent the master process from clearing environment variables
clear_env = no
; Route all outbound HTTP/HTTPS through the local Squid proxy
env[http_proxy] = http://127.0.0.1:3128
env[https_proxy] = http://127.0.0.1:3128
env[HTTP_PROXY] = http://127.0.0.1:3128
env[HTTPS_PROXY] = http://127.0.0.1:3128
; --- ACCESS LOGGING FOR SQUID CORRELATION ---
; Logs every PHP request with its script path and host — the Python
; audit script cross-references these against Squid's connection logs.
access.log = /var/log/php8.5-fpm.access.log
access.format = "[%t] %m %{REQUEST_METHOD}e %f %{HTTP_HOST}e"
The access log format:
%t— Timestamp. Produces[13/May/2026:10:30:45 +0000]. This is what the Python audit script parses to match events between the Squid log and the PHP log within a 2-second window.%m— Request duration in milliseconds.234means the PHP request took 234ms. Useful for spotting slow requests, but secondary to the audit script's correlation work.%{REQUEST_METHOD}e— The HTTP method. Almost alwaysGETorPOST. Included for completeness; the audit script doesn't use it directly.%f— The full script path on disk. Produces/var/www/mysite.com/public_html/wp-cron.php. This is the critical field — it tells the audit script exactly which PHP file handled the request, which gets cross-referenced against Squid's connection log to answer "which script made this outbound call?"%{HTTP_HOST}e— The host header from the request. Producesmysite.com. Tells the audit script which site the request belongs to. Without this, you'd know a script on the server phoned home but not which virtual host it was running under.
Without the script path and host, you'd know that an outbound connection happened — but not which site or which plugin initiated it. With both, the audit script can answer "who called home and from where."
While you're in the pool configuration, lock down the functions that could bypass the proxy or execute arbitrary commands. Add this after the access-logging block:
; --- RESTRICTED FUNCTIONS ---
; Block command execution, process control, and raw socket functions.
; These have no legitimate use in a PHP web application and are common
; targets for malicious code that tries to bypass HTTP-level controls.
php_admin_value[disable_functions] = exec,passthru,shell_exec,system,proc_open,popen,curl_multi_exec,parse_ini_file,show_source,pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,posix_kill,posix_mkfifo,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname
A few of these deserve explanation:
exec,passthru,shell_exec,system,proc_open,popen— Direct command execution. If a malicious script can call these, it doesn't need to phone home over HTTP — it can run a reverse shell, spawn a crypto miner, or dump your database locally.curl_multi_exec— The multi-curl interface. Some malware uses this as an alternative to the standard cURL functions, assuming onlycurl_execgets blocked. Single-request cURL still works through the Squid proxy; multi-curl — which has no practical use in a web request/response cycle — is disabled.pcntl_*(process control) — Forking, signaling, and waiting on child processes. A compromised script that can fork can spawn background processes that outlive the PHP request and bypass the proxy entirely.posix_kill,posix_setuid,posix_setgid— Privilege escalation and process manipulation. There is no scenario where a PHP web application should be sending signals to other processes or changing its UID.
Step 4: Pass the host header from Nginx to PHP-FPM
PHP-FPM's %{HTTP_HOST}e reads the HTTP_HOST environment variable, which Nginx must set. In your Nginx fastcgi_params or inside the location ~ \.php$ block, add:
fastcgi_param HTTP_HOST $host;
Most Nginx installations already include this in fastcgi_params — verify yours does. If HTTP_HOST is missing, the PHP access log will show a blank host field and the audit script won't be able to identify which site made the request.