23

I have a website that uses the same core .htaccess details as many other websites; however this website does not properly load the .htaccess directives -- giving a basic HTTP header set of:

    HTTP/1.1 200 OK
    Date: Mon, 12 Nov 2018 09:34:28 GMT
    Server: Apache
    Keep-Alive: timeout=5, max=100
    Connection: Keep-Alive
    Transfer-Encoding: chunked
    Content-Type: text/html; charset=UTF-8

The website itself loads fine, but additonal headers in .htaccess are not being agknowledged / loaded.

So .htaccess is being read, right?

Yes -- The htaccess file contains HTTPS forced redirects and domain name redirects (from the .co.uk to .com address (both to the same website account))

These work.

Headers supplied by PHP are being loaded fine, too

The PHP headers on a test page are loading just fine:

<?php
header("Cache-Control: no-cache, must-revalidate");
header('Content-Type: text/html; charset=utf-8');
header("X-Clacks-Overhead: GNU Terry Pratchett");
header("Content-Language: en");
header("X-XSS-Protection: 1; mode=block");
header("X-Frame-Options: SAMEORIGIN");
header("X-Content-Type-Options: nosniff");
?>

But the same headers set in the .htaccess are not being agknowledged.

So it's an .htaccess syntax error!

Not that I can see; usually with a .htaccess error the site loads an HTTP-500 error message, however here the site loads in the browser without issue.

When there IS a deliberate syntax error the error-500 HTTP response comes back as expected.

Ok bozo, check your error logs!

Absolutely; I couldn't agree more. The Apache error logs are empty!

What have you tried to do to fix this?

  • Confirmed httpd.conf allows reading of .htaccess
  • Confirmed that mod_headers.c is loaded on the server
  • Commented out and re-written various rules, to no effect
  • Read lots (maybe 6-8) of posts on Stack Overflow and Server Fault - Stackoverflow posts don't appear to relate or their issues had distinct differences.
  • Confirmed my .htaccess has the correct permissins (0644)
  • Told my staff (He's a Graphic Designer).
  • Cried myself to sleep.

Right then - Get your file out! Show me the magic!

Here:

Options +FollowSymLinks
Options -Indexes
RewriteEngine On
ErrorDocument 404 /index.php?msg=404
ErrorDocument 403 /index.php?msg=403

#Set asset items to cache for 1 week.
<FilesMatch "\.(gif|jpe?g|png|ico|css|js|swf|mp3)$">
     Header set Cache-Control "max-age=1972800, public, must-revalidate"
</FilesMatch>

RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

## This does not appear to work (for either)
#Header always set Strict-Transport-Security "max-age=31536000;" env=HTTPS
Header always set Strict-Transport-Security "max-age=31536000; includeSubdomains;" "expr=%{HTTPS} == 'on'"
Header set Expect-CT enforce,max-age=2592000

RewriteCond %{HTTP_HOST} ^(www\.)?thewebsite\.co\.uk$ [NC]
RewriteRule ^/?(.*)$ https://www.thewebsite.com%{REQUEST_URI} [R=301,L]

###
##### Seems to workdown to roughly this point.
###

#force requests to begin with a slash.
RewriteCond  %{REQUEST_URI}  !^$
RewriteCond  %{REQUEST_URI}  !^/
RewriteRule  .*              -    [R=403,L]

RewriteCond %{HTTP_HOST} !^$
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

RewriteCond %{ENV:REDIRECT_STATUS} 200
RewriteRule .* - [L]

### This file does not exist on the directory at present. 
<Files .account-user.ini>
    order allow,deny
    deny from all
</Files>

###
#### None of these appear on assessment tools such as Security Headers 
#### Or redbot.
###
Header set Cache-Control no-cache,must-revalidate
Header set X-Clacks-Overhead "GNU Terry Pratchett"
Header set X-XSS-Protection 1;mode=block
Header set X-Content-Type-Options nosniff
Header always set X-Frame-Options SAMEORIGIN
Header set Expect-CT enforce,max-age=2592000
Header set Content-Language en
Header set Referrer-Policy origin-when-cross-origin
    
<LimitExcept GET POST HEAD>
    deny  from all
</LimitExcept>

And finally it would really help if you gave me a final summary of all of the above!

  • Header setting commands in .htaccess do not appear to work.
  • ALL parts of the file are used on other live sites elsewhere without issue.
  • Headers can be set in PHP without issue
  • No errors arise from these Headers in the .htaccess.
  • Headers appear to fail silently.
  • No Apache error logs are recorded.
  • The .htaccess is being read by Apache because other commands (such as mod_Rewrites) are being actioned

UPDATE:

From research by other parties (the hosting providers) it seems that somehow the .htaccess works and loads all the correct headers for non PHP pages.

For even plain PHP pages; the headers are blank.

Clarification

  • whatever.html pages load the headers all ok.
  • PHP pages display headers set by Header("...");
  • PHP pages refuse to load any headers set by .htaccess. This is the problem.

So it looks like my .htaccess can't set headers for PHP pages. How can I fix this?

Community
  • 1
  • 1
Martin
  • 22,212
  • 11
  • 70
  • 132
  • Have you tried AllowOverride All? https://httpd.apache.org/docs/2.4/en/mod/core.html#allowoverride – digijay Nov 12 '18 at 22:38
  • @D.Joe if allow override was off then other commands in the htaccess would also fail. As stated -- the HTTPS and `www.` commands do work as expected. – Martin Nov 13 '18 at 09:53
  • @D.Joe I have updated the question to better highlight this. – Martin Nov 13 '18 at 11:50
  • It **must** be mod_headers then. Is that a Debian/Ubuntu server? Could you check the config in `/etc/apache2/mods_enabled/headers.conf` and `.load` or post them here? – digijay Nov 13 '18 at 20:36
  • It's a LAMP stack. Apache 2.4 on Linux CentOS 7.5 – Martin Nov 13 '18 at 20:53
  • Bash outout comfirms that mod_headers is loaded by Apache. – Martin Nov 13 '18 at 20:54
  • Okay, I'll check tomorrow on a centos 7.5 vm. – digijay Nov 13 '18 at 21:15
  • @D.Joe hi. I have looked for the headers file but there is only a `headers.so` (unreadable as it's ~binary) and no `headers.conf` file in the apache conf directory (or nearby) . Apache is run through "Easy Apache 4". – Martin Nov 23 '18 at 14:14
  • This question may also be related to a follow up question I posted just today, [here](https://stackoverflow.com/questions/53447469/setting-headers-in-httpd-conf-not-setting-headers-in-htaccess) – Martin Nov 23 '18 at 14:16
  • 1
    Are you by chance running PHP as CGI? If so, I had this same problem myself: [Apache won't set headers for PHP script](https://stackoverflow.com/questions/32147413/apache-wont-set-headers-for-php-script). – Álvaro González Nov 24 '18 at 16:28
  • @ÁlvaroGonzález yes I found the issue was PHP handler being fastCGI rather than suphp – Martin Nov 26 '18 at 09:08

4 Answers4

12

It seems that PHP ignores headers defined in .htaccess when working as a FastCGI module.

There are a lot of suggestions how to fix this. In your case I would recommend to have a file that defines all your headers

<?php
// file headers.php
header('Cache-Control: no-cache,must-revalidate');
header('X-Clacks-Overhead: "GNU Terry Pratchett"');
header('X-XSS-Protection: 1;mode=block');
header('X-Content-Type-Options: nosniff');
header('X-Frame-Options: SAMEORIGIN');
header('Expect-CT: enforce,max-age=2592000');
header('Content-Language: en');
header('Referrer-Policy: origin-when-cross-origin');
?>

and save it to your DocumentRoot directory. Then add this entry to your .htaccess file to include it with every request:

php_value auto_prepend_file /var/www/html/headers.php     

Testing it:

<?php
// file test.php
die("hello world");
?>

And the headers are being sent:

$ curl -I ubuntu-server.lan/test.php
HTTP/1.1 200 OK
Date: Sun, 25 Nov 2018 09:37:52 GMT
Server: Apache/2.4.18 (Ubuntu)
Cache-Control: no-cache,must-revalidate
X-Clacks-Overhead: "GNU Terry Pratchett"
X-XSS-Protection: 1;mode=block
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Expect-CT: enforce,max-age=2592000
Content-Language: en
Referrer-Policy: origin-when-cross-origin
Content-Type: text/html; charset=UTF-8

Always keep in mind that when you change headers in .htaccess to also change them in headers.php.

Hope this helps!


➥ previous answer

I think this problem results from the httpd/apache2 headers_module not being loaded correctly (although you state otherwise in one of the above comments). You can check this by executing this command in the terminal:

apachectl -M | grep headers_module

If you get no output headers_module (shared) (or similar), then you have to activate the httpd/apache2 headers module. On a CentOS system you have to load the respective source file in your configuration (default /etc/httpd/conf/httpd.conf).

You have to add this line

LoadModule headers_module /usr/lib/apache2/modules/mod_headers.so

and then restart the http server wih sudo systemctl restart httpd.service

With EasyApache 4 the folder where httpd/apache2 modules are located might differ and be /usr/lib64/apache2/modules/.

I hope this helps!

digijay
  • 1,329
  • 4
  • 15
  • 25
  • Thanks for your help here D.joe, but I can only give the bounty to one, and you have come to some pretty similar conclusions to `covener` they've got it -- that it was the FastCGI and while I appreciate your answers it's more of a work around rather than a solution to using a Fast-CGI. Thanks – Martin Nov 27 '18 at 20:18
  • @digijay This worked great, but with a caveat. Using the FastCGI handler is what causes the problem. But the `php_value` directive given in this comment is for the mod_php handler. So adding that line to `.htaccess` won't work. Instead, you have to create a PHP configuration file (e.g., `.user.ini`) with the following: `auto_prepend_file = /var/www/html/headers.php` – Chad Cloman Feb 26 '19 at 23:25
  • 4 hours of my life trying to work out why CORS was excluding php generated server responses in an API, and the answer was here all along! Damn you FastCGI! If you are receiving messages in the browser that Access to XMLHttpRequest at from origin has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. then it is because you are only looking at .htaccess to set the header. You need to set it in the PHP file using the above solution if PHP is forced upon you in FastCGI – Beerswiller Oct 23 '19 at 10:11
  • @ChadCloman If `auto_prepend_file = /var/www/html/headers.php` is added to `.user.ini`, do I still need `php_value auto_prepend_file /var/www/html/headers.php` in `.htaccess`? – Mr J Wolf Feb 02 '23 at 09:05
  • 1
    @MrJWolf It's my understanding that both have the same effect, and that you only need one. – Chad Cloman Feb 03 '23 at 12:27
10

It is not so much FastCGI as it is mod_proxy_fcgi, the method of asking Apache to "execute" FastCGI by passing it to some other listener.

When you use any mod_proxy* module, .htaccess isn't processed at all, because you're acting as a proxy and short-circuiting any disk-related configuration sections.

php-fpm will be looking at the request URL and reading data from disk, but Apache isn't. It is just confusing to people because they can be running on the same host and the files are often in a directory httpd could serve directly.

covener
  • 17,402
  • 2
  • 31
  • 45
  • I found the handler was the cause -- swapping from a CGI to a suphp handler immediately resolved the issues. I a not sure if it was anything to do with *proxy*s but the hander, yes. Cheers – Martin Nov 26 '18 at 09:08
0

After much exploration it was found the issue was the PHP Handler -- the fastCGI (cgi) handler was not keeping the headers.

Changing to the suphp handler immediately resolved the issues.

Martin
  • 22,212
  • 11
  • 70
  • 132
  • @swa66 this is the solution. Regardless of me finding it myself or elsewhere. BOTH other answers insinuate a similar solution (aka fast-CGI to blame) and that actually makes it more tricky.... – Martin Nov 27 '18 at 20:12
0

I had same problem. Please enable cache module in Linux Ubuntu.

sudo a2enmod cache

Then run:

sudo service apache2 start