How can I pre-compress files with mod_deflate in Apache 2.x?

1,085

Solution 1

This functionality was misplaced in mod_gzip anyway. In Apache 2.x, you do that with content negotiation. Specifically, you need to enable MultiViews with the Options directive and you need to specify your encoding types with the AddEncoding directive.

Solution 2

To answer my own question with the really simple line I was missing in my confiuration:

Options FollowSymLinks MultiViews

I was missing the MultiViews option. It's there in the Ubuntu default web server configuration, so don't be like me and drop it off.

Also I wrote a quick Rake task to compress all the files.

namespace :static do
    desc "Gzip compress the static content so Apache doesn't need to do it on-the-fly."
    task :compress do
        puts "Gzipping js, html and css files."
        Dir.glob("#{RAILS_ROOT}/public/**/*.{js,html,css}") do |file|
            system "gzip -c -9 #{file} > #{file}.gz"
        end
    end
end

Solution 3

It is possible to serve pre-compressed files using mod_negotiation although it is a bit finicky. The primary difficulty is that only requests for files which do not exist are negotiated. So if foo.js and foo.js.gz both exist, responses for /foo.js will always be uncompressed (although responses for /foo would work correctly).

The easiest solution I've found (from François Marier) is to rename uncompressed files with a double file extension, so foo.js is deployed as foo.js.js so requests for /foo.js negotiate between foo.js.js (no encoding) and foo.js.gz (gzip encoding).

I combine that trick with the following configuration:

Options +MultiViews
RemoveType .gz
AddEncoding gzip .gz

# Send .tar.gz without Content-Encoding: gzip
<FilesMatch ".+\.tar\.gz$">
    RemoveEncoding .gz
    # Note:  Can use application/x-gzip for backwards-compatibility
    AddType application/gzip .gz
</FilesMatch>

I wrote a post which discusses the reasoning for this configuration and some alternatives in detail.

Solution 4

I am afraid MultiViews will not work as expected: the doc says Multiviews works "if the server receives a request for /some/dir/foo, if /some/dir has MultiViews enabled, and /some/dir/foo does not exist...", in other words: if you have a file foo.js and foo.js.gz in the same directory, just activating MultiViews will not cause the .gz file to be sent even if the AcceptEncoding gzip header is transmitted by the browser (you can verify this behavior by temporarily disabling mod_deflate and monitoring the response with e.g. HTTPFox).

I am not sure if there is a way around this with MultiViews (maybe you can rename the original file and then add a special AddEncoding directive), but I believe you can construct a mod_rewrite rule to handle this.

Solution 5

I have an Apache 2 built from source, and I found I had to modify the following in my httpd.conf file:

Add MultiViews to Options:

Options Indexes FollowSymLinks MultiViews

Uncomment AddEncoding:

AddEncoding x-compress .Z
AddEncoding x-gzip .gz .tgz

Comment AddType:

#AddType application/x-compress .Z
#AddType application/x-gzip .gz .tgz
Share:
1,085
Muhammad Atif Agha
Author by

Muhammad Atif Agha

Updated on June 03, 2022

Comments

  • Muhammad Atif Agha
    Muhammad Atif Agha almost 2 years

    I want to make a report, in which I want that user must be able to reposition the labels, text or images with his own choice. I am actually making a cheque maker software in Windows Forms .NET 4, and for different banks there needs different positions but same attributes, because we have to print on cheques of different banks so each one has different position of signature field, name field, money field, etc. So is there any option in any report or Crystal Reports that once we generate a report, we may able to move the labels with drag and drop, and can we adjust the text by drag and drop once the report is shown in the report viewer?

    • Muhammad Atif Agha
      Muhammad Atif Agha over 12 years
      Can anyone provide me link for designing project of .net windows forms, which have the ability to reposition the text and images with drag n drop, if report does not help?
  • Otto
    Otto over 15 years
    This will remove the original files, which means clients that don't have Aceept-Encoding: gzip won't be serviced.
  • Otto
    Otto over 15 years
    While you're editing, why not add -9 and get the highest compression possible. My 1500 files compressed in 38 seconds, so it's worth doing to save every byte possible in bandwidth and download time. :) (Also wishing I could edit my typo in my previous comment. Ugh)
  • Otto
    Otto over 15 years
    Not according to the man page on my Mac, it says -6 is the default.
  • Otto
    Otto over 12 years
    I'm sure it worked at the time, and I'm sure I didn't delete the original files. It's plausible mod_rewrite was involved, somehow. I probably had a rule that was "serve this statically if the file exists". I may have changed it to include the .gz extension, but I no longer have access to that system to verify.
  • Ian Jones
    Ian Jones over 10 years
    If in your example you request just foo rather than foo.js, it will work. If the client accepts gzip they will get foo.js.gz else they will get foo.js.
  • Kalpesh Soni
    Kalpesh Soni over 8 years
  • Kalpesh Soni
    Kalpesh Soni over 8 years
  • MvG
    MvG over 7 years
    This doesn't seem to work any more. With Apache 2.4.25 I always get uncompressed results, probably becuase the MultiViews only kicks in if the file doesn't exist as named. The doc says as much. Pity!
  • Kevinoid
    Kevinoid over 7 years
    Good catch @MvG, you are absolutely right! I've updated the answer with a workaround, although it is not ideal as it requires renaming the uncompressed file and a bit of configuration trickery. Hope it helps!
  • MvG
    MvG over 7 years
    @Kevinoid: That's exactly the workaround I came up with myself, after sleeping on it. Nice!