(Last Updated On: April 21, 2019)

If you have an installation of Nginx and PHP-FPM, PHP Powered-By headers are exposed by default. But you may need to hide PHP headers such X-Powered-By and X-CF-Powered-By to limit server information exposed to the public. This is one of the security mechanism.

X-Powered-By and X-CF-Powered-By PHP headers are disabled on FastCGI section of your Nginx configuration for a site. To use this guide, you should be using Nginx and PHP-FPM. Here are configuration examples.

For generic nginx configuration file.

############
# Pass all .php files onto a php-fpm or php-cgi server
############

location ~ \.php$ {
        try_files                       $uri =404;
        include                         /etc/nginx/fastcgi_params;
        fastcgi_read_timeout            3600s;
        fastcgi_buffer_size             128k;
	fastcgi_connect_timeout 3s; 
	fastcgi_send_timeout 120s; 
	fastcgi_temp_file_write_size 256k; 
        fastcgi_param     SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_pass                    unix:/run/php-fpm/php7.3-fpm.sock;
        #fastcgi_pass                    127.0.0.1:9000;
        fastcgi_index                   index.php;
   
        # Hide PHP headers
        fastcgi_hide_header             X-Powered-By;
        fastcgi_hide_header             X-CF-Powered-By;
}

If you have a PHP-FPM configuration in a separate file, it should be set like below.

$ cat /etc/nginx/nginxconfig.io/php_fastcgi.conf 
# 404
try_files $fastcgi_script_name =404;

# default fastcgi_params
include fastcgi_params;

# fastcgi settings
fastcgi_pass			unix:/var/run/php-fpm/php7.3-fpm.sock;
fastcgi_index			index.php;
fastcgi_buffers			8 16k;
fastcgi_buffer_size		32k;

# Hide PHP headers
fastcgi_hide_header             X-Powered-By;
fastcgi_hide_header             X-CF-Powered-By;

# fastcgi params
fastcgi_param DOCUMENT_ROOT		$realpath_root;
fastcgi_param SCRIPT_FILENAME	$realpath_root$fastcgi_script_name;
fastcgi_param PHP_ADMIN_VALUE	"open_basedir=$base/:/usr/lib/php/:/tmp/";

The fastcgi_hide_header directive sets additional fields that will not be passed.  If, on the contrary, the passing of fields needs to be permitted, the fastcgi_pass_header directive can be used.

Validate your Nginx configurations.

$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Restart Nginx for the changes to take effect.

sudo systemctl restart nginx php-fpm

Confirm Settings

Here is the output of my website curl before disabling the headers.

$ curl -IL https://computingforgeeks.com
HTTP/2 200
date: Sat, 20 Apr 2019 20:44:38 GMT
content-type: text/html; charset=UTF-8
vary: Accept-Encoding
x-powered-by: PHP/7.3.1
x-cf-powered-by: WP Rocket 3.2.4

link: https://computingforgeeks.com/wp-json/; rel="https://api.w.org/"
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
x-content-type-options: nosniff
referrer-policy: no-referrer-when-downgrade
expect-ct: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
server: cloudflare
cf-ray: 4ca9f5130d66cb75-MBA

And after making the change and restarting Nginx.

$ curl -IL https://computingforgeeks.com
HTTP/2 200
date: Sat, 20 Apr 2019 20:44:38 GMT
content-type: text/html; charset=UTF-8
vary: Accept-Encoding
link: https://computingforgeeks.com/wp-json/; rel="https://api.w.org/"
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
x-content-type-options: nosniff
referrer-policy: no-referrer-when-downgrade
expect-ct: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
server: cloudflare
cf-ray: 4ca9f5130d66cb75-MBA

You can confirm there are no x-powered-by and x-cf-powered-by directives in the output. The same can be checked from the browser under Inspect > Network > Headers > Response Headers.

Also read:

How To Enable GZIP & Brotli Compression for Nginx on Linux

Resolve “413 Request Entity Too Large Error” on Nginx / Apache

Configure JFrog Artifactory behind Nginx reverse proxy and Let’s Encrypt SSL

Configure Jenkins behind Nginx reverse proxy and Let’s Encrypt SSL

Configure Jenkins behind Nginx reverse proxy and Let’s Encrypt SSL