Enabling CORS .htaccess restrictions - apache

I am encountering some behaviour from a produciton server and I was wondering if someone could confirm if something is possible and how it might have been done.
I have a website www.example.com with SSL enabled and all traffic forwarding to https
On that site I have a font file https://www.example.com/wp-content/assets/fonts/icons.ttf
I have additional campaign sites (e.g www.examplecampaign.com) that use the css file from example.com which loads in a font face using that font file. I am actually adding all the relevant file types woff, etc but will refer to ttf for simplicity. The icon font displays fine on www.example.com but on www.examplecampaign.com because in Firefox I get the error
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://www.example.com/wp-content/assets/fonts/icons.ttf. This can be fixed by moving the resource to the same domain or enabling CORS.
So here begins my problem. On our stage server which we have full access to I can add
# BEGIN REQUIRED FOR WEBFONTS
AddType font/ttf .ttf
AddType font/eot .eot
AddType font/otf .otf
AddType font/woff .woff
<FilesMatch "\.(ttf|otf|eot|woff)$">
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin "*"
</IfModule>
# END REQUIRED FOR WEBFONTS
to the .htaccess file and that solves the problem. However on our produciton server which is owned and managed by the client this header modification is ignored. I am using http://web-sniffer.net/ to test this.
To further complicate things I hvae found that if I just added
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin "*"
</IfModule>
on my stage site the header would appear when requesting any page or resource BUT on the production server if I added that the Access-Control-Allow-Origin would appear on all pages apart from the font files (and possible other resources).
So my question is, is it possible in Apache to disable / ignore header modification for a certain file type(s) and how would that be done. It's weird that it's so specific. We no longer have sudo access and have to request changes to conf files which is one of the reasons im making this change in .htaccess not that I think that would matter where this is set? Also example.com is a wordpress site but I don't think that would affect anything? As it's working on stage but not produciton.
Does anyone know of the Apache configuration that would restrict the use of mod_header in that way?

Related

Why nginx does not forward Vary header sent by Apache in proxy mode?

I'm using Plesk (seems to be 17.8.11 provided by OVH) and nginx is configured as proxy. My PHP script returns images into WEBP format when the browser accept it, otherwise it returns orignal format (JPG or PNG).
In .htaccess I return header Vary: Accept so proxies know that the content depends on the Accept header.
In nginx settings of Plesk I only checked the 'Proxy mode' option, other checkboxes are cleared.
When I fetch the image the Vary: Accept is not present, I cannot imagine that nginx does not handle this header, please help me to figure this out.
For the Vary: header to be allowed and understood by nginx, you need the gzip on and gzip_vary on settings in your /etc/nginx/nginx.conf.
Plesk actually have a documentation about it, did you check the Plesk Support website ?
https://support.plesk.com/hc/en-us/articles/213380049-How-to-enable-disable-gzip-compression-in-nginx-on-a-Plesk-server
By the way, your Plesk version is quite old, I would recommend you update it.
I finally found the reason: I was not sending "Vary: Accept" header for ".webp" extension, only for ".jpg" and ".png". My URLs ends with .jpg or .png, never .webp and this is working good with Apache. Here was my htaccess directives:
<IfModule mod_setenvif.c>
SetEnvIf Request_URI "\.(jpe?g|png)$" REQUEST_image
</IfModule>
<IfModule mod_headers.c>
Header append Vary Accept env=REQUEST_image
</IfModule>
To fix it I added .webp in URLs filter:
<IfModule mod_setenvif.c>
SetEnvIf Request_URI "\.(jpe?g|png|webp)$" REQUEST_image
</IfModule>
<IfModule mod_headers.c>
Header append Vary Accept env=REQUEST_image
</IfModule>
Now it's all good.

Serving precompressed content with Brotli on Apache

I have installed mod_brotli on my WHM server via easyapache 4 - html, css, js files etc are all being compressed.
I then came across this in the offocial docs - https://httpd.apache.org/docs/2.4/mod/mod_brotli.html#precompressed
I have since added this to my Post VirtualHost include file in WHM (post_virtualhost_global.conf) instead of htaccess as I want this to be server wide.
How can I verify if this is working and indeed serving precompressed files? I haven't found anything to say either way, I can only confirm that brotli compression is in use. CPU loads are near enough the same with or without the include so I suspect it may not be saving the compressed files for next time.
This is the virtual host include:
<IfModule mod_headers.c>
# Serve brotli compressed CSS and JS files if they exist
# and the client accepts brotli.
RewriteCond "%{HTTP:Accept-encoding}" "br"
RewriteCond "%{REQUEST_FILENAME}\.br" "-s"
RewriteRule "^(.*)\.(js|css)" "$1\.$2\.br" [QSA]
# Serve correct content types, and prevent double compression.
RewriteRule "\.css\.br$" "-" [T=text/css,E=no-brotli:1]
RewriteRule "\.js\.br$" "-" [T=text/javascript,E=no-brotli:1]
<FilesMatch "(\.js\.br|\.css\.br)$">
# Serve correct encoding type.
Header append Content-Encoding br
# Force proxies to cache brotli &
# non-brotli css/js files separately.
Header append Vary Accept-Encoding
</FilesMatch>
</IfModule>
this is my /etc/apache2/conf.2/brotli.conf
<IfModule brotli_module>
# Compress only a few types
# https://httpd.apache.org/docs/trunk/mod/mod_brotli.html
AddOutputFilterByType BROTLI_COMPRESS text/plain text/css text/html application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript
SetOutputFilter BROTLI_COMPRESS
SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png)$ no-brotli
BrotliFilterNote Input instream
BrotliFilterNote Output outstream
BrotliFilterNote Ratio ratio
LogFormat '"%r" %{outstream}n/%{instream}n (%{ratio}n%%)' brotli
CustomLog "logs/brotli_log" brotli
</IfModule>
and this is /etc/apache2/conf.modules.d/115_mod_brotli.conf
# Enable mod_brotli
LoadModule brotli_module modules/mod_brotli.so
So if anyone can help me figure out how to confirm if the files are precompressed or not that would be great.
Edit: I don't think my files are being pre-compressed. Does anyone have any further info about this? I cannot find any further posts or docs on it at akk
To configure Apache to serve pre-compressed Brotli files:
Make sure brotli compressed files exist right next to the normal files in respective folders. Eg if you have a file /var/www/html/index.html there should also be /var/www/html/index.html.br
Add the following to the right VirtualHost configuration:
RewriteCond %{HTTP:Accept-Encoding} br
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME}.br -f
RewriteRule ^(.*)$ $1.br [L]
<Files *.js.br>
AddType "text/javascript" .br
AddEncoding br .br
</Files>
<Files *.css.br>
AddType "text/css" .br
AddEncoding br .br
</Files>
<Files *.svg.br>
AddType "image/svg+xml" .br
AddEncoding br .br
</Files>
<Files *.html.br>
AddType "text/html" .br
AddEncoding br .br
</Files>
To check if pre-compressed brotli files are being served:
You can log the rewrites to see if your rewrites are in action or no. If these are in action, your pre-compressed brotli files are being served. In your virtual host, add the following:
LogLevel alert rewrite:trace6
Restart your apache2, hit your URL and then grep for rewrite statements in your apache error log
tail -f /var/log/apache2/error.log | grep '[rewrite'
I'm late to the party, but in my crash course of Brotli through Apache, the OP isn't possible.
What the Apache docs show is how to properly serve the files "if" they are pre-compressed, hence the text: "if they exist".
From what I gather in my search to understand this better, Apache can't actually pre-compress the files, this must be accomplished through a binary or extension which is out of Apache's scope.
What Apache mod_brotli does for you is dynamically compress requests on-the-fly as it's being sent. In the case of the OP, using cPanel, if you enable mod_brotli, EasyApache4 adds the necessary bits to serve and compress the files outlined in AddOutputFilterByType as Brotli. Again, these are served dynamically. Generated and served on-the-fly. As far as I can tell, these are cached in memory and not on disk.
Enabling mod_brotli is the easy way to go about enabling brotli, however it's better to pre-compress the files being served as the OP wanted due to the overhead and performance hit on having to literally compress all requests flowing through Apache. I ran across a blog where they talk about this and the difference between dynamic vs static is worth using static pre-compressed files, however if you have a small site, or maybe a really beefy hosting platform, then dynamically serving might work just fine for you.
If I'm not mistaken, you don't even need mod_brotli enabled in order to serve the pre-compressed .br files if you can figure out a way to pre-compress them.
Here's an example of using PHP to pre-compress the files: https://github.com/kjdev/php-ext-brotli
So far, no-one has answered the OP with viable ways to pre-compress files as Brotli (as I too am searching for this) but what I need to point out is that Apache doesn't do the pre-compressing and you will have to continue your search if you're looking for a static way of serving Brotli .br files.
Just remove the reference to /etc/apache2/conf.2/brotli.conf temporarily and restart Apache, and you should see that your precompressed brotli files are still delivered with brotli compression whereas dynamic compressed files (e.g. HTML, or CSS or JS where a precompressed file does not exist) are now not compressed at all.

Why don't webroot/.htaccess rules do apply to themes?

I added the following to the 'app/webroot/.htaccess' file to enable a far future expires header for resource files such as .css and .js. While this works fine for any content served out of the /js /css /img folders, it will not apply to anything placed in a CakePHP theme webroot/js|css|img folder.
Is there a similar method that should be used to control resource caching from themes? All of my theme resource files expire the next day as if its grabbing some sort of default.
There are no other Apache rules in place for mod_expires as I'm trying to keep it all in .htaccess.
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType text/css "access plus 1 week"
# ... Also added png,js etc...
</IfModule>
With the default settings of CakePHP, themed (and plugin-) assets are served via PHP, not directly handled by Apache. I'm not 100% sure, but this probably causes the htaccess settings not to be applied, because Apache does not see those files as 'static' files.
For a production site, it is advisable to change the settings, as is described here Increasing performance of plugin and theme assets
Additional tips on performance
As a side-note, for additional performance;
Have a look at the Server configuration files of Html5 Boilerplate. They are very well documented and offer a lot of valuable settings to speed up the performance of your website. A lot of research has been put into those settings, so that you dont have to do that yourself. Many of those settings also apply to CakePHP websites. You can find the configuration files here: https://github.com/h5bp/server-configs/tree/master/apache
Don't use .htaccess files, but move all rules/settings of your .htaccess files to your VirtualHost configuration and disable override. This way, Apache doesn't have to scan every directory for possible .htaccess files for each request

Garbled text when including remote .shtml file using mod_include and mod_proxy

I'm experimenting with apache mod_include.
I got two servers running apache: I'm trying to include in my test_local.shtml (server1) some simple text from test_remote.shml (server2).
test_local.shtml:
<html>
<head>
<title></title>
</head>
<body>
<!--#include virtual="http://www.server2.com/test_remote.shtml"-->
</body>
</html>
test_remote.shtml:
<b>this is a test</b>
At first it didn't work (got "File does not exist" error in error_log).
It looks like that for security reasons the only files I manage to include are on my local server (server1), with a local path, but not a remote url.
Then I understood that I needed to use mod_proxy (and mod_proxy_html) in combination with mod_include to make remote inclusion work.
So I added the following to my httpd.conf (on server1):
ProxyPass /server2 http://www.server2.com
Then I changed the include line in test_local.shtml to:
<!--#include virtual="/server2/test_remote.shtml"-->
No errors this time, something gets included, but the resulting text is all garbled:
‹³I²+ÉÈ,V¢D…’Ôâý$;.j¿è
Am I missing something in my configuration? What's wrong?
UPDATE: I suspect it's something about the way data is sent (and then read) between the two servers.. such as compression or similar. I checked mod_deflate configuration section, which is included and working in both servers, and it's the same. Any idea? Thanks
UPDATE 2: disabling SetOutputFilter DEFLATE on server2, the text included with mod_include on server1 is perfectly readable. So that's the source of the issue: how can I configure server1 to handle the gzipped content and display it correctly? (Hypotetically I'd imagine some sort of inputfilter opposed to outputfilter..)
I found two solutions, but I prefer the second one because it doesn't need to change the configuration of the remote server.
Solution 1:
By adding the following to the remote server configuration, we disable the gzip compression for .shtml files:
<IfModule mod_deflate.c>
SetEnvIfNoCase Request_URI \.shtml$ no-gzip dont-vary
</IfModule>
This is not the best solution for me, because I don't have always access to the remote server from which I include contents.
Solution 2:
On the "local" server (the one hosting pages that use SSI inclusion), adding the following:
ProxyPass /server2 http://www.server2.com/
ProxyPassReverse /server2 http://www.server2.com/
<Location "/server2/">
RequestHeader unset Accept-Encoding
</Location>
Basically, I'm telling Apache to disable the Accept-Encoding request header; when requesting .shtml pages to the remote server, we ask the page without compression. Consequently, we get plain text, avoiding the garbled content.
Further info: http://wiki.apache.org/httpd/ReInflating

Set Content-Disposition header to attachment only on files in a certain directory?

I've got this this rule in my htaccess file to force linked files to download rather than open in the browser:
<FilesMatch "\.(gif|jpe?g|png)$">
ForceType application/octet-stream
Header set Content-Disposition attachment
</FilesMatch>
Is there a way to alter the RegExp so it only applies to files in a certain directory?
Thanks
Like #gumbo said, put the .htaccess file in the highest level folder you want to affect. and those settings will trickle down to sub folders. You may also want to make sure the headers module is enabled before using this in your htaccess file. The following line will generate an error if the headers module is not enabled:
Header set Content-Disposition attachment
here's an example that forces download of mp3 files only if the headers module is enabled:
<IfModule mod_headers.c>
<FilesMatch "\.(mp3|MP3)$">
ForceType audio/mpeg
Header set Content-Disposition "attachment"
Allow from all
</FilesMatch>
</IfModule>
Note: it does not enable the module, it just ignores anything inside the IfModule tags if the module is not enabled.
To enable apache modules you'll either need to edit your httpd.conf file or in wamp server you can click the wamp tray icon and select "Apache -> Apache Modules -> headers_module" or make sure it is checked.
You will probably need to put the directives in the .htaccess file in the particular directory.
Put it in a <Location> directive, and/or modify the regex to exclude slashes or as appropriate.