HTTP response headers are small, but they punch above their weight: caching, security policy, content handling, and client behavior all hinge on what gets sent before the body. Adding a custom header can enforce a site-wide policy, standardize application metadata, or expose a narrowly-scoped diagnostic value without modifying application code.

Apache implements header manipulation through mod_headers and the Header directive, which can be placed globally, per-VirtualHost, or within more specific contexts such as Directory. Rules are evaluated during request processing, and can set, add, edit, or remove headers depending on the active configuration and the response being generated.

If mod_headers is missing or disabled, the Header directive fails on reload and can take the site offline until corrected. Conflicting rules (or a reverse proxy/CDN injecting the same headers) can cause duplicates or unexpected values, and some headers need the always modifier to appear on error responses as well. Commands and paths below follow the Debian and Ubuntu layout (/etc/apache2/ and the apache2 service name).

Steps to set custom response headers in Apache:

  1. Open a terminal with sudo privileges.
  2. Enable the headers module.
    $ sudo a2enmod headers
    Enabling module headers.
    To activate the new configuration, you need to run:
      systemctl restart apache2
    • On CentOS, RHEL, and Fedora, mod_headers is typically loaded by default, and the service name is usually httpd.
    • On openSUSE and SLES, the a2enmod workflow is commonly available, and configuration is typically under /etc/apache2/.
    Platform Enable mod_headers Primary config location Service name
    Debian, Ubuntu sudo a2enmod headers /etc/apache2/ apache2
    RHEL family Ensure headers_module is loaded (often default) /etc/httpd/ httpd
  3. Open the configuration file for the target Apache site.
    $ sudo vi /etc/apache2/sites-available/000-mysite.conf
  4. Locate the block where the header should apply, such as the matching VirtualHost.
    <VirtualHost *:80>
            #ServerName www.example.com
     
            ServerAdmin webmaster@localhost
            DocumentRoot /var/www/html
     
            ErrorLog ${APACHE_LOG_DIR}/error.log
            CustomLog ${APACHE_LOG_DIR}/access.log combined
    </VirtualHost>
  5. Add the custom header using the Header directive.
    <VirtualHost *:80>
            #ServerName www.example.com
     
            ServerAdmin webmaster@localhost
            DocumentRoot /var/www/html
     
            Header set MyCustomHeader "Set any values here"
     
            ErrorLog ${APACHE_LOG_DIR}/error.log
            CustomLog ${APACHE_LOG_DIR}/access.log combined
    </VirtualHost>
    • set replaces any existing header with the same name; add appends an additional header line with the same name.
    • always applies the rule on error responses and internal redirects, which is often desirable for security headers (example: Content-Security-Policy).

    A too-strict security header value can break pages (blocked scripts/styles) and should be validated in staging before broad rollout.

  6. Save the configuration file.
  7. Exit the text editor.
  8. Test the Apache configuration for syntax errors.
    $ sudo apache2ctl configtest
    AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 127.0.1.1. Set the 'ServerName' directive globally to suppress this message
    Syntax OK
  9. Reload the Apache service to apply the change.
    $ sudo systemctl reload apache2
    • Use a restart when a reload is not available: sudo systemctl restart apache2.
    • On CentOS, RHEL, and Fedora: sudo systemctl reload httpd.
  10. Verify the response includes the custom header.
    $ curl -I http://127.0.0.1/
    HTTP/1.1 200 OK
    Date: Sun, 03 Sep 2023 03:41:54 GMT
    Server: Apache/2.4.55 (Ubuntu)
    Last-Modified: Fri, 25 Aug 2023 12:12:15 GMT
    ETag: "29af-603be4163c6a4"
    Accept-Ranges: bytes
    Content-Length: 10671
    Vary: Accept-Encoding
    MyCustomHeader: Set any values here
    Content-Type: text/html

    Look for MyCustomHeader in the response to confirm it is being sent.

    • For name-based VirtualHost testing on localhost, set the Host header: curl -I -H 'Host: www.example.com' http://127.0.0.1/.
Discuss the article:

Comment anonymously. Login not required.