I would like to add HTTP Strict Transport Security directive to my .htaccess file. I've added the lock at the end of the code here but when I test Testing the HSTS preload process it show the setting not set. I checked my Apache config and see the headers module enabled.
What am I missing?
<Files .htaccess>
order allow,deny
deny from all
</Files>
<FilesMatch "\.(png|gif|js|css)$">
ExpiresActive on
ExpiresDefault "access plus 1 month"
</FilesMatch>
# disable directory autoindexing
Options -Indexes
ErrorDocument 400 http://%{HTTP_HOST}
ErrorDocument 401 http://%{HTTP_HOST}
ErrorDocument 402 http://%{HTTP_HOST}
ErrorDocument 403 http://%{HTTP_HOST}
ErrorDocument 405 http://%{HTTP_HOST}
ErrorDocument 404 /incl/pages/error404.php
ErrorDocument 500 http://%{HTTP_HOST}
RewriteEngine On
RewriteBase /
RewriteCond %{SERVER_PORT} ^80$
RewriteRule ^.*$ https://%{SERVER_NAME}%{REQUEST_URI} [R=301,L]
# BEGIN GZIP
<ifmodule mod_deflate.c>
AddOutputFilterByType DEFLATE text/text text/html text/plain text/xml text/css application/x-javascript application/javascript
</ifmodule>
# END GZIP
# Use HTTP Strict Transport Security to force client to use secure connections only
<ifmodule mod_headers.c>
Header set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" env=HTTPS
</ifmodule>
I tested here and here.
For redirects you need to use always attribute:
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" env=HTTPS
From the mod_headers documentation:
You're adding a header to a locally generated non-success (non-2xx) response, such as a redirect, in which case only the table corresponding to always is used in the ultimate response.
For Apache 2.2 somehow Header always set x x env=HTTPS is never matched for redirects whether you specify SSLOptions +StdEnvVars or not.
My suggestion: separate your VirtualHosts so that they not mix plaintext/ssl ports, and then on the ssl-only VirtualHosts specify simply Header always set x x without any conditions.
Checked on httpd-2.2.15-60.el6.centos.6.x86_64
Related
Implement a redirect to HTTPS to website
Earlier we have a website with HTTP, and recently we have purchased in to HTTPS. Now I am tried to implement the redirect to HTTPS.
For this I tried below code in
<IfModule mod_rewrite.c>
## enable rewrites
Options +FollowSymlinks
RewriteEngine On
RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ www.example.com/$1 [R,L]
</IfModule>
When I uploaded the .htaccess file with above code. The website is not able to display.
And my entire .htaccess file as below.
#DirectoryIndex index.html
#AddType application/x-httpd-php5 .html .htm
#AddType application/x-httpd-php .html .htm
#RemoveHandler .html .htm
#AddType application/x-httpd-php .html .htm
#RewriteRule ^/?inscription/map\.html$ - [F,L]
<FilesMatch "\.html$" >
#ForceType application/x-httpd-php
</FilesMatch>
#Canonicalization issue
RewriteCond %{HTTP_HOST} !^www.example.com$ [NC]
RewriteRule ^(.*)$ www.example.com/$1 [L,R=301]
#Google Caching Issue
RewriteCond %{HTTP_HOST} ^example\.com [NC]
RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ www.example.com/$1 [R,L]
<IfModule mod_rewrite.c>
## enable rewrites
Options +FollowSymlinks
RewriteEngine On
RewriteCond %{SERVER_PORT} 80
#RewriteRule ^(.*)$ www.example.com/$1 [R,L]
#Redirect from http to https
#RewriteCond %{HTTP:X-Forwarded-Proto} !https
#RewriteCond %{HTTPS} off
#RewriteRule ^ www.example.com/ [L,R=301]
ErrorDocument 404 www.example.com
</IfModule>
<IfModule mod_expires.c>
ExpiresActive on
ExpiresDefault "access plus 1 month"
ExpiresByType application/javascript "access plus 1 year"
ExpiresByType image/x-icon "access plus 1 year"
ExpiresByType image/jpg "access plus 1 month"
ExpiresByType image/jpeg "access plus 1 month"
ExpiresByType image/gif "access plus 1 month"
ExpiresByType image/png "access plus 1 month"
ExpiresByType text/css "access plus 1 month"
</IfModule>
<IfModule mod_deflate.c>
# Compress HTML, CSS, JavaScript, Text, XML and fonts
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/rss+xml
AddOutputFilterByType DEFLATE application/vnd.ms-fontobject
AddOutputFilterByType DEFLATE application/x-font
AddOutputFilterByType DEFLATE application/x-font-opentype
AddOutputFilterByType DEFLATE application/x-font-otf
AddOutputFilterByType DEFLATE application/x-font-truetype
AddOutputFilterByType DEFLATE application/x-font-ttf
AddOutputFilterByType DEFLATE application/x-javascript
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE font/opentype
AddOutputFilterByType DEFLATE font/otf
AddOutputFilterByType DEFLATE font/ttf
AddOutputFilterByType DEFLATE image/svg+xml
AddOutputFilterByType DEFLATE image/x-icon
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/javascript
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/xml
# Remove browser bugs (only needed for really old browsers)
BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch ^Mozilla/4\.0[678] no-gzip
BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
Header append Vary User-Agent
</IfModule>
<Files "phpinfo.php">
Order Allow,Deny
Deny from all
</Files>
#<Files >
#AddType application/x-httpd-php .html .htm
#</Files>
Options -Indexes
Can you please help on this. to implement the redirection from http to https.
RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ www.example.com/$1 [R,L]
You need to include the scheme, ie. https in the substitution string. For example:
RewriteRule ^(.*)$ https://www.example.com/$1 [R,L]
The same applies to all the other redirects in your .htaccess file.
If you don't explicitly include the HTTPS scheme in a HTTP to HTTPS redirect then it's never going to redirect to HTTPS. However, a relative path substitution (ie. one that does not start with a scheme or slash) is seen as relative to the current directory (unless RewriteBase is defined). So, a substitution string like www.example.com will effectively be treated as a subdirectory from the current directory (document root) and attempting to convert this into an external redirect will result in a malformed redirect like http://www.example.com/path/to/public_html/www.example.com/<foo>.
ErrorDocument 404 www.example.com
You have a similar issue with your ErrorDocument directive. However, you should not be "redirecting" to the custom error document (which is what will happen if you specify an absolute URL here). You should define a custom error document. eg. /errors/my404.html and state this in the ErrorDocument directive:
ErrorDocument 404 /errors/my404.html
The custom error document is then served using an internal subrequest. There is no "external redirect" here.
UPDATE#1:
Can you please edit above .htaccess file and post here?
I've removed all the commented-out code sections - so add those back as appropriate. Although several of the mod_rewrite sections that were commented out I assume are just earlier/incorrect attempts. I've also reordered some bits (eg. it is more logical to define Options and ErrorDocument directives early in the file - you certainly shouldn't split these up). I've omitted the mod_expires and mod_deflate sections for brevity.
I've also updated the deprecated mod_access_compat (Order, Deny, etc.) directives for Apache 2.4 Require all denied.
I'm also assuming the www subdomain is canonical and you have no other subdomains.
# Allow FollowSymlinks (required for mod_rewrite)
# and prevent directory listings (mod_autoindex)
Options +FollowSymlinks -Indexes
# Define custom error documents
ErrorDocument 404 /errors/my404.html
# Block access to specific files
<Files "phpinfo.php">
Require all denied
</Files>
# Enable mod_rewrite rewrite engine
RewriteEngine On
# Canonical redirect: non-www to www (and HTTPS)
RewriteCond %{HTTP_HOST} !^www\.
RewriteRule (.*) https://www.%{HTTP_HOST}/$1 [R=301,L]
# Canonical redirect: HTTP to HTTPS
RewriteCond %{SERVER_PORT} 80
RewriteRule (.*) https://www.example.com/$1 [R=301,L]
# mod_expires directives go here...
# mod_deflate directives go here...
Clear your browser cache before testing and test first with 302 (temporary) redirects to avoid potential caching issues.
Note I assume you have already tested the SERVER_PORT 80 check and this works as intended on your server*1. I notice in your commented-out code you are also checking the X-Forwarded-Proto HTTP request header - this is only required if your application server is behind a front-end proxy that manages the HTTPS connection. If this is the case then checking SERVER_PORT (or HTTPS) may fail.
*1 UPDATE#2: It seems this is not the case and you are having to implement a non-standard check for %{ENV:HTTPS} instead of checking the SERVER_PORT, which is resulting in a redirect loop. This implies that your webhost (a shared hosting platform I assume) is using some kind of front-end proxy to manage the SSL connection and your application server is actually communicating over plain HTTP to the front-end proxy.
# Force from http to https
RewriteCond %{ENV:HTTPS} !on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
Solved with below code.
#Force from http to https
RewriteCond %{ENV:HTTPS} !on
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
I have an LAMP server for my Drupal 8 site.
I do not know what I can optimize to improve the performance of my site.
This is a dynamic site.
Should I use the htaccess files or disable them and put everything in vhost ?
Is the file below correct ?
What can I add ?
.htaccess :
#
# Apache/PHP/Drupal settings:
#
# Protect files and directories from prying eyes.
<FilesMatch "\.(engine|inc|install|make|module|profile|po|sh|.*sql|theme|twig|tpl(\.php)?|xtmpl|yml)(~|\.sw[op]|\.bak|\.orig|\.save)?$|^(\.(?!well-known).*|Entries.*|Repository|Root|Tag|Template|composer\.(json|lock))$|^#.*#$|\.php(~|\.sw[op]|\.bak|\.orig|\.save)$">
<IfModule mod_authz_core.c>
Require all denied
</IfModule>
<IfModule !mod_authz_core.c>
Order allow,deny
</IfModule>
</FilesMatch>
# Don't show directory listings for URLs which map to a directory.
Options -Indexes
# Set the default handler.
DirectoryIndex index.php index.html index.htm
# Add correct encoding for SVGZ.
AddType image/svg+xml svg svgz
AddEncoding gzip svgz
# Most of the following PHP settings cannot be changed at runtime. See
# sites/default/default.settings.php and
# Drupal\Core\DrupalKernel::bootEnvironment() for settings that can be
# changed at runtime.
# PHP 5, Apache 1 and 2.
<IfModule mod_php5.c>
php_value assert.active 0
php_flag session.auto_start off
php_value mbstring.http_input pass
php_value mbstring.http_output pass
php_flag mbstring.encoding_translation off
# PHP 5.6 has deprecated $HTTP_RAW_POST_DATA and produces warnings if this is
# not set.
php_value always_populate_raw_post_data -1
</IfModule>
# Requires mod_expires to be enabled.
<IfModule mod_expires.c>
# Enable expirations.
ExpiresActive on
ExpiresDefault "access plus 30 seconds"
ExpiresByType text/html "access plus 15 days"
ExpiresByType image/gif "access plus 1 months"
ExpiresByType image/jpg "access plus 1 months"
ExpiresByType image/jpeg "access plus 1 months"
ExpiresByType image/png "access plus 1 months"
ExpiresByType text/js "access plus 1 months"
ExpiresByType text/javascript "access plus 1 months"
<FilesMatch \.php$>
# Do not allow PHP scripts to be cached unless they explicitly send cache
# headers themselves. Otherwise all scripts would have to overwrite the
# headers set by mod_expires if they want another caching behavior. This may
# fail if an error occurs early in the bootstrap process, and it may cause
# problems if a non-Drupal PHP file is installed in a subdirectory.
ExpiresActive Off
</FilesMatch>
</IfModule>
# Set a fallback resource if mod_rewrite is not enabled. This allows Drupal to
# work without clean URLs. This requires Apache version >= 2.2.16. If Drupal is
# not accessed by the top level URL (i.e.: http://example.com/drupal/ instead of
# http://example.com/), the path to index.php will need to be adjusted.
<IfModule !mod_rewrite.c>
FallbackResource /index.php
</IfModule>
# Various rewrite rules.
<IfModule mod_rewrite.c>
RewriteEngine on
# Set "protossl" to "s" if we were accessed via https://. This is used later
# if you enable "www." stripping or enforcement, in order to ensure that
# you don't bounce between http and https.
RewriteRule ^ - [E=protossl]
RewriteCond %{HTTPS} on
RewriteRule ^ - [E=protossl:s]
# Make sure Authorization HTTP header is available to PHP
# even when running as CGI or FastCGI.
RewriteRule ^ - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
# Block access to "hidden" directories whose names begin with a period. This
# includes directories used by version control systems such as Subversion or
# Git to store control files. Files whose names begin with a period, as well
# as the control files used by CVS, are protected by the FilesMatch directive
# above.
#
# NOTE: This only works when mod_rewrite is loaded. Without mod_rewrite, it is
# not possible to block access to entire directories from .htaccess because
# <DirectoryMatch> is not allowed here.
#
# If you do not have mod_rewrite installed, you should remove these
# directories from your webroot or otherwise protect them from being
# downloaded.
RewriteRule "/\.|^\.(?!well-known/)" - [F]
# If your site can be accessed both with and without the 'www.' prefix, you
# can use one of the following settings to redirect users to your preferred
# URL, either WITH or WITHOUT the 'www.' prefix. Choose ONLY one option:
#
# To redirect all users to access the site WITH the 'www.' prefix,
# (http://example.com/foo will be redirected to http://www.example.com/foo)
# uncomment the following:
RewriteCond %{HTTP_HOST} .
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^ http%{ENV:protossl}://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
# To redirect all users to access the site WITHOUT the 'www.' prefix,
# (http://www.example.com/foo will be redirected to http://example.com/foo)
# uncomment the following:
# RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
# RewriteRule ^ http%{ENV:protossl}://%1%{REQUEST_URI} [L,R=301]
# Modify the RewriteBase if you are using Drupal in a subdirectory or in a
# VirtualDocumentRoot and the rewrite rules are not working properly.
# For example if your site is at http://example.com/drupal uncomment and
# modify the following line:
# RewriteBase /drupal
#
# If your site is running in a VirtualDocumentRoot at http://example.com/,
# uncomment the following line:
# RewriteBase /
# Redirect common PHP files to their new locations.
RewriteCond %{REQUEST_URI} ^(.*)?/(install.php) [OR]
RewriteCond %{REQUEST_URI} ^(.*)?/(rebuild.php)
RewriteCond %{REQUEST_URI} !core
RewriteRule ^ %1/core/%2 [L,QSA,R=301]
# Rewrite install.php during installation to see if mod_rewrite is working
RewriteRule ^core/install.php core/install.php?rewrite=ok [QSA,L]
# Pass all requests not referring directly to files in the filesystem to
# index.php.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !=/favicon.ico
RewriteRule ^ index.php [L]
# For security reasons, deny access to other PHP files on public sites.
# Note: The following URI conditions are not anchored at the start (^),
# because Drupal may be located in a subdirectory. To further improve
# security, you can replace '!/' with '!^/'.
# Allow access to PHP files in /core (like authorize.php or install.php):
RewriteCond %{REQUEST_URI} !/core/[^/]*\.php$
# Allow access shariff-backend-php.
RewriteCond %{REQUEST_URI} !/shariff-backend-php/
# Allow access to test-specific PHP files:
RewriteCond %{REQUEST_URI} !/core/modules/system/tests/https?.php
# Allow access to Statistics module's custom front controller.
# Copy and adapt this rule to directly execute PHP files in contributed or
# custom modules or to run another PHP application in the same directory.
RewriteCond %{REQUEST_URI} !/core/modules/statistics/statistics.php$
# Deny access to any other PHP files that do not match the rules above.
# Specifically, disallow autoload.php from being served directly.
RewriteRule "^(.+/.*|autoload)\.php($|/)" - [F]
# Rules to correctly serve gzip compressed CSS and JS files.
# Requires both mod_rewrite and mod_headers to be enabled.
<IfModule mod_headers.c>
# Serve gzip compressed CSS files if they exist and the client accepts gzip.
RewriteCond %{HTTP:Accept-encoding} gzip
RewriteCond %{REQUEST_FILENAME}\.gz -s
RewriteRule ^(.*)\.css $1\.css\.gz [QSA]
# Serve gzip compressed JS files if they exist and the client accepts gzip.
RewriteCond %{HTTP:Accept-encoding} gzip
RewriteCond %{REQUEST_FILENAME}\.gz -s
RewriteRule ^(.*)\.js $1\.js\.gz [QSA]
# Serve correct content types, and prevent mod_deflate double gzip.
RewriteRule \.css\.gz$ - [T=text/css,E=no-gzip:1]
RewriteRule \.js\.gz$ - [T=text/javascript,E=no-gzip:1]
<FilesMatch "(\.js\.gz|\.css\.gz)$">
# Serve correct encoding type.
Header set Content-Encoding gzip
# Force proxies to cache gzipped & non-gzipped css/js files separately.
Header append Vary Accept-Encoding
</FilesMatch>
</IfModule>
</IfModule>
# Various header fixes.
<IfModule mod_headers.c>
# Disable content sniffing, since it's an attack vector.
Header always set X-Content-Type-Options nosniff
# Disable Proxy header, since it's an attack vector.
RequestHeader unset Proxy
</IfModule>
<IfModule mod_gzip.c>
mod_gzip_on Yes
mod_gzip_dechunk Yes
mod_gzip_item_include file .(html?|txt|css|js|php|pl)$
mod_gzip_item_include handler ^cgi-script$
mod_gzip_item_include mime ^text/.*
mod_gzip_item_include mime ^application/x-javascript.*
mod_gzip_item_exclude mime ^image/.*
mod_gzip_item_exclude rspheader ^Content-Encoding:.*gzip.*
</IfModule>
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/rss+xml
AddOutputFilterByType DEFLATE application/vnd.ms-fontobject
AddOutputFilterByType DEFLATE application/x-font
AddOutputFilterByType DEFLATE application/x-font-opentype
AddOutputFilterByType DEFLATE application/x-font-otf
AddOutputFilterByType DEFLATE application/x-font-truetype
AddOutputFilterByType DEFLATE application/x-font-ttf
AddOutputFilterByType DEFLATE application/x-javascript
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE font/opentype
AddOutputFilterByType DEFLATE font/otf
AddOutputFilterByType DEFLATE font/ttf
AddOutputFilterByType DEFLATE image/svg+xml
AddOutputFilterByType DEFLATE image/x-icon
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/javascript
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/xml
</IfModule>
/etc/apache2/sites-available/www-domaine-com-le-ssl.conf :
<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerAdmin contact#domaine.com
ServerName domaine.com
ServerAlias www.domaine.com
Protocols h2 http/1.1
DocumentRoot /var/www/www-domaine-com/web/
<Directory /var/www/www-domaine-com/web>
Options FollowSymLinks MultiViews
AllowOverride All
Require all granted
</Directory>
<FilesMatch \.php$>
SetHandler "proxy:unix:/var/run/php/php7.2-fpm.sock|fcgi://localhost/"
</FilesMatch>
<Proxy "fcgi://localhost/" enablereuse=on flushpackets=on max=10>
</Proxy>
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
Include /etc/letsencrypt/options-ssl-apache.conf
SSLCertificateFile /etc/letsencrypt/live/domaine.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/domaine.com/privkey.pem
Header always set Strict-Transport-Security "max-age=15768000; includeSubDomains; preload"
Header always set X-Content-Type-Options "nosniff"
Header always set X-XSS-Protection "1; mode=block"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set X-Download-Options "noopen"
Header always set X-Permitted-Cross-Domain-Policies "none"
Header always set Content-Security-Policy "default-src https: data: wss: 'unsafe-inline' 'unsafe-eval'; base-uri 'self';"
Header edit Set-Cookie ^(.*)$ $1;HttpOnly;Secure
</VirtualHost>
</IfModule>
Using dynamic configuration files (".htaccess") will definitely slow down your server. That is documented and actually easy to understand:
The static configuration is read exactly once at startup time. When dynamic configuration files are enabled, then the server has to check each physical folder from the root up to the requested object (if mapped to the file system) whether there are such configuration files (which can occur on every level of the file system). And if some are found then each has to be read and interpreted for every single request. All that is additional load.
These files are only supported for two typical situations:
when you have no access to the actual host configuration of the server (read: really cheap hosting providers)
for applications that insist on writing their own rewriting rules (which is an obvious security nightmare once you start thinking about it)
If none of the two situations apply to you, then the clear recommendation is to not use dynamic configuration files but use the static configuration instead. And possibly even to disable those files completely.
Take care however for the details. You cannot simply move the directives in all cases, sometimes you need to adapt them:
there are directives you cannot use in all locations (consult the http server documentation for details on that, it is of excellent quality and comes with great examples and details)
you may have to adjust a few details, for examples the matching pattern in RewriteRules which is applied to absolute paths in the static configuration but to relative paths in dynamic configuration files. Again this is clearly documented.
I have a static web page and want to improve the loading performance by providing gzip-versions of all available files. The page is running on an apache server mod_gzip and I can't change any configuration except the .htaccess file.
Thus I create gzip files during the build process and want to rewrite the incoming requests to the .gz files.
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteBase /
ReWriteCond %{HTTP:accept-encoding} gzip
ReWriteCond %{REQUEST_FILENAME} !.+\.gz$
RewriteCond %{REQUEST_FILENAME}.gz -f
RewriteRule (.+) $1.gz [L]
</IfModule>
The rewriting works perfectly, but unfotunately the server also changes the Content-Type of the response to application/x-gzip which makes the browser downloading the file and not rendering it. Is there a way to prevent the apache server from changing the content type and to render the page instead of downloading the gz?
This requires you to have 2 versions of the file in the following format. For instance:
index.html
index.html.gz
styles.css
styles.css.gz
scripts.js
scripts.js.gz
This htaccess will rewrite the request to send the gz version to the browser but also maintain the type of the original file. You have to force the type of the file you want to send. Otherwise it will use the application/x-gzip and the browser will download the file.
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE text/html text/plain text/css application/json application/javascript application/vnd.ms-fontobject application/font-ttf application/font-woff application/font-otf image/svg+xml
</IfModule>
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP:Accept-Encoding} gzip
RewriteCond %{REQUEST_FILENAME}.gz -f
RewriteRule (.*\.(html|css|js|eot|ttf|woff|otf|svg))$ $1.gz [L]
</IfModule>
AddEncoding x-gzip .gz
<FilesMatch .*\.html.gz>
ForceType text/html
</FilesMatch>
<FilesMatch .*\.css.gz>
ForceType text/css
</FilesMatch>
<FilesMatch .*\.js.gz>
ForceType application/javascript
</FilesMatch>
<FilesMatch .*\.eot.gz>
ForceType application/vnd.ms-fontobject
</FilesMatch>
<FilesMatch .*\.ttf.gz>
ForceType application/font-ttf
</FilesMatch>
<FilesMatch .*\.woff.gz>
ForceType application/font-woff
</FilesMatch>
<FilesMatch .*\.otf.gz>
ForceType application/font-otf
</FilesMatch>
<FilesMatch .*\.svg.gz>
ForceType image/svg+xml
</FilesMatch>
All I am trying to do is:
rewrite /static/styles/min.css to /static/styles/min.css.gz
rewrite /static/scripts/min.js to /static/scripts/min.js.gz
The trick is that those files are on a remote (public) server which I'm reverse proxying to.
I am doing this so I can workaround the same-origin issue with our javascript, and to speed up delivery in general. The .gz files already exist.
No matter what I do, I cannot request the .js file and have the .gz file returned.
I have tried this with numerous different RewriteConds to no avail.
I have also tried it with RequestHeader unset Accept-Encoding enabled, and commented out.
Google PageSpeed keeps telling me that it is not receiving the compressed versions, and when I request using curl and manually setting the "Accept-Encoding: gzip, deflate" header, I continue to receive the non-compressed versions. I cannot put the rewrites in the .htaccess file because the reverse proxy is processed before the .htaccess, and I need the rewrite to already be in effect when the reverse proxy happens. I'm at a total loss.
Here is my non-production setup (I know it needs securing):
<VirtualHost *:80>
ServerName ww.test.com
DocumentRoot "/htdocs/public"
Options +MultiViews
AddEncoding x-gzip .gz
AddEncoding gzip .gz
RewriteEngine on
RewriteCond %{HTTP:Accept-Encoding} gzip
RewriteRule ^\.js$ $1\.js\.gz [L]
RewriteCond %{HTTP:Accept-Encoding} gzip
RewriteRule ^\.css$ $1\.css\.gz [L]
<FilesMatch .*\.css\.gz>
ForceType text/css
Header append Content-Encoding gzip
</FilesMatch>
<FilesMatch .*\.js\.gz>
ForceType text/javascript
Header append Content-Encoding gzip
</FilesMatch>
ProxyRequests off
ProxyPass /static/ http://www.ourCDN.com/ourAccount/environmentName/
<Location /static/>
ProxyPassReverse /
#RequestHeader unset Accept-Encoding
</Location>
<Directory />
Options FollowSymLinks
AllowOverride All
Order deny,allow
</Directory>
</VirtualHost>
FilesMatch rules apply only to files on disk - a proxied request isn't a file on disk and therefore won't be captured by a FilesMatch rule.
You probably want
<LocationMatch "^/static/.*\.css\.gz$">
ProxyPassReverse /
....
</LocationMatch>
When running the assets:precompile rake task, gzipped versions of your app's assets are created. According to the Rails guide for the asset pipeline, you can configure your web server (in my case Apache 2.2) to serve these precompressed files instead of having the web server do the work.
What I can't figure out is how to get mod_deflate configured so that these files are served instead of being double-compressed and then served?
I have mod_deflate enabled via httpd.conf:
AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript
BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch ^Mozilla/4\.0[678] no-gzip
BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
And I've converted the code on the rails guide to go into the .htaccess in public/assets:
# Some browsers still send conditional-GET requests if there's a
# Last-Modified header or an ETag header even if they haven't
# reached the expiry date sent in the Expires header.
Header unset Last-Modified
Header unset ETag
FileETag None
# RFC says only cache for 1 year
ExpiresActive On
ExpiresDefault "access plus 1 year"
# Serve gzipped versions instead of requiring Apache to do the work
RewriteEngine on
RewriteCond %{REQUEST_FILENAME}.gz -s
RewriteRule ^(.+) $1.gz [L]
# without it, Content-Type will be "application/x-gzip"
<FilesMatch .*\.css.gz>
ForceType text/css
</FilesMatch>
<FilesMatch .*\.js.gz>
ForceType text/javascript
</FilesMatch>
Any ideas how to set this up properly?
First, you don't want mod_deflate to operate here. So in your assets .htaccess file add:
SetEnv no-gzip
This should turn off mod_deflate for your assets.
Second, I hate to disagree with the rails folks, but I think there are a couple deficiencies in their assets .htaccess recipe. The top part is fine but for RewriteEngine and beyond I'd have:
RewriteEngine on
# Make sure the browser supports gzip encoding before we send it
RewriteCond %{HTTP:Accept-Encoding} \b(x-)?gzip\b
RewriteCond %{REQUEST_URI} .*\.(css|js)
RewriteCond %{REQUEST_FILENAME}.gz -s
RewriteRule ^(.+) $1.gz [L]
# without it, Content-Type will be "application/x-gzip"
# also add a content-encoding header to tell the browser to decompress
<FilesMatch \.css\.gz$>
ForceType text/css
Header set Content-Encoding gzip
</FilesMatch>
<FilesMatch \.js\.gz$>
ForceType application/javascript
Header set Content-Encoding gzip
</FilesMatch>