Updated: 4 November 2026 · Applies to: nginx 1.26.3 (Debian 13), 1.24.0 (Ubuntu 24.04) and 1.28.3 (Ubuntu 26.04), PHP 8.4 FPM and Apache 2.4.68 on Debian 13, tested; AlmaLinux 10.2 default files checked

To hide the nginx version, add server_tokens off; to the http {} block of /etc/nginx/nginx.conf and reload nginx. The header then reads Server: nginx instead of Server: nginx/1.28.3 (Ubuntu). Open-source nginx cannot drop the Server header completely with its own settings: for that, load the headers-more module and add more_clear_headers Server;. To hide the PHP version, set expose_php = Off in PHP-FPM's php.ini, or add fastcgi_hide_header X-Powered-By; in nginx.

1. Check what your server sends now

Ask for the headers only with curl -I, and look at the footer of an error page:

curl -I https://example.com/
curl -s https://example.com/no-such-page | grep center

Lab example on a fresh Ubuntu 26.04 nginx install:

HTTP/1.1 200 OK
Server: nginx/1.28.3 (Ubuntu)

<hr><center>nginx/1.28.3 (Ubuntu)</center>

The default differs by distribution. In our tests:

  • Debian 13: nginx.conf already has server_tokens off;, so the header is just Server: nginx.
  • Ubuntu 24.04: the line is commented out (# server_tokens off;), so nginx sends nginx/1.24.0 (Ubuntu).
  • Ubuntu 26.04: the file sets server_tokens build; (version plus build name), and nginx sent nginx/1.28.3 (Ubuntu).
  • AlmaLinux 10.2 (nginx 1.26.3) and the official nginx Docker image (1.30.5): there is no server_tokens line, so the default on applies and the version is shown.

2. Hide the nginx version with server_tokens off

  1. Open /etc/nginx/nginx.conf and find the http { block. Add the line, or change an existing server_tokens line:
    http {
        server_tokens off;
        ...
    }
  2. Test the configuration: nginx -t
  3. Reload: systemctl reload nginx
  4. Check again with curl -I.

Lab result on Ubuntu 26.04 after the change:

Server: nginx
<hr><center>nginx</center>

The version is gone from the header and from nginx's built-in error pages, but the word "nginx" stays in both. server_tokens also works in a single server {} or location {} block, but the http block covers every site at once.

3. Remove the Server header completely (headers-more)

According to nginx, setting server_tokens to a custom string, or to an empty string to drop the header, is only available in the commercial subscription. On open-source nginx, use the headers-more module. Debian and Ubuntu package it:

  1. Install it: apt install libnginx-mod-http-headers-more-filter (the package adds a load_module line under /etc/nginx/modules-enabled/).
  2. In the http {} block, next to server_tokens off;, add:
    more_clear_headers Server;
  3. Run nginx -t and systemctl reload nginx.

Lab result on Debian 13: the Server line is gone, also on error responses:

$ curl -I http://127.0.0.1/
HTTP/1.1 200 OK
Date: Mon, 12 Oct 2026 10:02:32 GMT
Content-Type: text/html
Content-Length: 10703

To send your own value instead, use more_set_headers "Server: webserver";, which gave Server: webserver. Two things that do not work:

  • Without the module loaded, nginx -t fails with unknown directive "more_clear_headers".
  • add_header Server "webserver"; does not replace the header. It adds a second one, so the response carried both Server: nginx and Server: webserver.

4. Remove "nginx" from error pages

Even with the header removed, nginx's built-in error pages still end with <center>nginx</center>. Serve your own page instead. In the server {} block:

error_page 404 /404.html;
location = /404.html {
    root /var/www/errors;
    internal;
}

With /var/www/errors/404.html in place, a missing page returned only our own HTML. List more status codes on one line for other errors, as nginx's own default config does with error_page 500 502 503 504 /50x.html;.

5. Hide the PHP version (X-Powered-By)

With expose_php = On, every PHP page sends a header such as X-Powered-By: PHP/8.4.26. There are two ways to stop it:

  1. In PHP: set expose_php = Off in the php.ini that PHP-FPM reads (/etc/php/8.4/fpm/php.ini on Debian 13, with your PHP version in the path on Ubuntu; /etc/php.ini on AlmaLinux and Rocky Linux), then restart PHP-FPM, for example systemctl restart php8.4-fpm. According to PHP, this setting can only be changed in php.ini, not with ini_set().
  2. In nginx: add fastcgi_hide_header X-Powered-By; next to fastcgi_pass. In our test the header disappeared while expose_php was still On. For an app behind proxy_pass, the equivalent is proxy_hide_header X-Powered-By;.

Check with curl -I https://example.com/index.php. The production php.ini shipped for PHP-FPM on Debian 13, Ubuntu 24.04 and Ubuntu 26.04 already has expose_php = Off, so if you still see the header there, check which file PHP-FPM really loads: php-fpm8.4 -i | grep -E "Loaded Configuration|expose_php" (lab output: expose_php => Off => Off). The CLI php.ini says On, but it does not affect web requests. On AlmaLinux 10.2, /etc/php.ini (PHP 8.3) has expose_php = On, so the header is sent until you change it.

6. Apache: ServerTokens and ServerSignature

If Apache serves the site (alone or behind nginx), set these two lines in /etc/apache2/conf-enabled/security.conf on Debian and Ubuntu, or in /etc/httpd/conf/httpd.conf on AlmaLinux and Rocky Linux (the AlmaLinux 10.2 file has neither line, so add both):

ServerTokens Prod
ServerSignature Off

After apachectl configtest and a graceful reload, the lab header changed from Server: Apache/2.4.68 (Debian) to Server: Apache, and the <address> line with the version disappeared from error pages. Header unset Server and Header always unset Server did not remove the header in our test. More detail is in How to Hide the Apache Version Number?

Is it worth doing?

Hiding versions makes automated scans a little less precise, but it does not fix anything. Keeping nginx, PHP and Apache updated is what protects the server. If you run your own server, for example a Ucartz KVM VPS, you can make these changes yourself as root.

Official documentation: nginx server_tokens, headers-more module and PHP expose_php.

Was this answer helpful?

Still stuck? Open a ticket