Clickjacking loads a trusted page inside a misleading or hidden frame so an ordinary click performs an unintended action. Sending an anti-framing policy from Apache stops the browser from rendering that embedded page in the first place, which protects admin panels, checkout flows, and any page that should not accept framed clicks from another site.
Apache adds anti-framing policies as HTTP response headers through mod_headers. Content-Security-Policy with frame-ancestors is the modern control for deciding which origins may embed a page, while X-Frame-Options still covers the simpler DENY and SAMEORIGIN cases for browsers that do not rely on frame-ancestors.
Examples below use the Debian and Ubuntu layout with /etc/apache2/, a2enmod, and the apache2 service name. If an application already sends its own Content-Security-Policy header, merge frame-ancestors into that existing policy instead of emitting a second conflicting header, and use Header always set so the policy is still present on redirects, error pages, and internal rewrites.
Steps to prevent clickjacking in Apache:
- Open a terminal session with an account that can use sudo.
- Enable the headers module if the platform manages Apache modules with a2enmod.
$ sudo a2enmod headers Enabling module headers. To activate the new configuration, you need to run: systemctl restart apache2
If the command reports that the module is already enabled, continue with the next step. RHEL-style packages usually ship mod_headers loaded by default instead of using a2enmod.
- Open the Apache configuration file for the site or scope that should send the anti-framing headers.
$ sudoedit /etc/apache2/sites-available/000-default.conf
Use a VirtualHost for site-wide coverage, or a narrower Directory or Location block when only part of the application needs the policy.
- Locate the VirtualHost, Directory, or Location block that serves the pages to protect.
<VirtualHost *:80> ServerName host.example.net DocumentRoot /var/www/html ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined </VirtualHost>
- Add the anti-framing headers in that scope.
<VirtualHost *:80> ServerName host.example.net DocumentRoot /var/www/html Header always set Content-Security-Policy "frame-ancestors 'self'" Header always set X-Frame-Options "SAMEORIGIN" ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined </VirtualHost>
Use frame-ancestors 'none' plus X-Frame-Options “DENY” when the site should never appear inside any frame. Use frame-ancestors 'self' plus SAMEORIGIN when same-origin framing is still legitimate, and declare frame-ancestors explicitly because it does not inherit from default-src.
- Replace the frame-ancestors value with an explicit allowlist when approved external origins must embed the page.
Header always set Content-Security-Policy "frame-ancestors 'self' https://portal.example.net https://admin.example.net"
X-Frame-Options ALLOW-FROM is obsolete and modern browsers ignore it. When third-party origins must frame the page, keep frame-ancestors as the authoritative control and remove any X-Frame-Options value that would contradict that requirement.
- Save the configuration file.
- Test the Apache configuration for syntax errors.
$ sudo apache2ctl -t Syntax OK
Debian and Ubuntu expose apache2ctl, while many other distributions use apachectl -t or httpd -t for the same check.
Related: How to test Apache configuration
- Reload the Apache service to apply the policy without dropping active connections.
$ sudo systemctl reload apache2
Use sudo systemctl reload httpd on many RHEL-family systems, or sudo apache2ctl graceful when systemd is not managing the service.
- Verify the normal response includes the anti-framing headers.
$ curl -I -sS -H 'Host: host.example.net' http://127.0.0.1/ HTTP/1.1 200 OK Date: Thu, 09 Apr 2026 04:39:48 GMT Server: Apache/2.4.58 (Ubuntu) X-Frame-Options: SAMEORIGIN Content-Security-Policy: frame-ancestors 'self' ##### snipped ##### Content-Type: text/html
If a reverse proxy, CDN, or application layer also emits Content-Security-Policy, confirm the final response still contains the intended frame-ancestors rule and does not send a contradictory policy.
- Verify the header is still present on an error response.
$ curl -I -sS -H 'Host: host.example.net' http://127.0.0.1/definitely-not-a-page HTTP/1.1 404 Not Found Date: Thu, 09 Apr 2026 04:39:48 GMT Server: Apache/2.4.58 (Ubuntu) X-Frame-Options: SAMEORIGIN Content-Security-Policy: frame-ancestors 'self' Content-Type: text/html; charset=iso-8859-1
If the 404 or redirect response drops the header, recheck that the configuration uses Header always set instead of Header set.
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.
