Настройка gzip-сжатия и кеширования в Apache2

Категория: Linux

Статья рассчитана на опытных пользователей, которые уже имеют некоторый опыт настройки Apache 2.4, использовали .htaccess и понимают нафига он нужен. Дальше речь пойдет о том, как настроить кеширование и gzip-сжатие файлов. Хотя правильно будет сказать не файлов, а ответа сервера (response). Поскольку ответ может формироваться динамически, те же изображения, JavaScript, CSS и т.д.

Чуть теории

Кеширование... Основной принцип заключается в том, что обмениваясь заголовками, сервер сообщает клиенту (браузеру) что такой-то контент можно закешировать на продолжительное время - неделя, месяц, год.. После чего, при последующих запросах этого контента, браузер будет вытягивать данные из кеша. Лафа может закончиться, когда:

  1. Время жизни кеша истекло;
  2. Пользователь очистил кеш вручную - Ctrl+F5
  3. Закончилось доступное под кеш пространство и закешированные данные был перезаписан более новым;
  4. Данные были обновлены на стороне сервера;

Используя кеширование вы снижаете нагрузку на сервер и экономите клиенту трафик и время. Однако нужно понимать, что у матерого серфера кеш может полностью затираться ежедневно, а то и чаще - все зависит от количества посещаемых сайтов и объема доступной под кеш квоты.

Сжатие. Полезная штука, которая позволяет сжимать (с помощью gzip) данные на сервере и распаковывать после получения на клиенте (в браузере). Клиент должен уметь распаковывать сжатые данные, о чем он сообщает в заголовке Accept-Encoding, например:

Accept-Encoding  gzip, deflate

Опять же мы экономим на трафике и, соответственно, сокращаем время ожидания. Но, при этом, чуть больше нагружаем ЦП при распаковке данных.

Необходимые модули Apache2

Для включения кеширования нам нужен модуль  mod_deflate, для кеширования - mod_headers или  mod_expires. Также  mod_headers вам пригодится чтобы удалять заголовок ETag, он лишний и могут быть проблемы с кешированием через  mod_header при включенном сжатии. Для включение выполните:

sudo a2enmod deflate headers expires
sudo /etc/init.d/apache2 restart

Для отключения модулей воспользуйтесь командой a2dismod:

sudo a2dismod deflate # пример отключения модуля mod_deflate
sudo /etc/init.d/apache2 restart

Итоговый .htaccess

Сразу приведу пример файла .htaccess, в котором настроено кеширование и сжатие. Файл будет содержать краткие примечания, а ниже разберем все директивы и правила более детально.

### Сжать ответ сервера для перечисленных MIME типов
<ifModule mod_deflate.c>
  <IfModule mod_filter.c>
      AddOutputFilterByType DEFLATE text/plain text/html
      AddOutputFilterByType DEFLATE text/css
      AddOutputFilterByType DEFLATE text/javascript application/javascript application/x-javascript
      AddOutputFilterByType DEFLATE text/xml application/xml application/xhtml+xml application/rss+xml
      AddOutputFilterByType DEFLATE application/json
      AddOutputFilterByType DEFLATE application/vnd.ms-fontobject application/x-font-ttf font/opentype image/svg+xml image/x-icon
  </ifModule>
</ifModule>


### Способ #1
### Подсказать браузеру схему кеширования через заголовки в ответе сервера
<ifModule mod_headers.c>
    # 43200 - день, 604800 - неделя, 2592000 - месяц
    <FilesMatch "\.(html|js|css)$">
	Header set Cache-Control "max-age=2592000"
        #Header unset Last-Modified
    </FilesMatch>
    <Files *.txt>
	Header add Cache-Control "max-age=43200"
    </Files>
    <FilesMatch "\.(flv|swf|ico|gif|jpg|jpeg|png)$">
	Header set Cache-Control "max-age=2592000"
    </FilesMatch>
    <FilesMatch "\.(pl|php|cgi|spl|scgi|fcgi)$">
	# отключить кэширование
	Header unset Cache-Control
    </FilesMatch>
</IfModule>

### Способ #2
### Подсказать браузеру схему кеширования через заголовки в ответе сервера
<IfModule mod_expires.c>
    # Enable expires
    ExpiresActive On
    
    # Default a cache expiration
    ExpiresDefault "access plus 10 month"
    
    # Images
    ExpiresByType image/gif                 "access plus 1 month"
    ExpiresByType image/png                 "access plus 1 month"
    ExpiresByType image/jpg                 "access plus 1 month"
    ExpiresByType image/jpeg                "access plus 1 month"
    
    # CSS, JavaScript
    ExpiresByType text/css                  "access plus 1 year"
    ExpiresByType application/javascript    "access plus 1 year"
    ExpiresByType text/javascript           "access plus 1 year"
</IfModule>


### Удалить заголовок ETag (иначе есть проблемы с кешированием при включенном сжатии)
<IfModule mod_headers.c>
    Header unset ETag
</IfModule>
FileETag None
Примечание

FilesMatch и  Files ~ сопоставляют шаблон только с именем файла, поэтому вы не можете указывать пути к файлам в этих директивах.

Чтобы указать область видимости кеша, используйте следующие правила:

Header set Cache-Control "max-age=2592000"
Header append Cache-Control "public"
// то же самое в одну строку
Header set Cache-Control "max-age=2592000, public"

gzip-сжатие

Apache2 больше не поддерживает модуль mod_gzip, теперь основным модулем является mod_deflate, который мы включили ранее. Чтобы проверить что сжатие работает - убедитесь что ответ содержит заголовок Content-Encoding:

Content-Encoding  gzip

Сжатие может быть настроено для определенных MIME-типов файлов, за это отвечает правило AddOutputFilterByType

Внимание!

Модуль deflate при сжатии может удалять заголовок Content-Length, поскольку длина сжатого ответа неизвестна на момент передачи заголовков. Однако, при удалении из ответа заголовка ETag - ситуация нормализуется. Почему?

Примечание

Сжимать изображения и видео файлы особого смысла нет - толку это даст мало, поскольку jpeg или gif уже сами по себе являются сжатыми форматами.

Кеширование

Для кеширования мы активировали модули  mod_headers и  mod_expires. Эти модули позволяют устанавливать заголовки в ответе сервера и подсказать браузеру схему кеширования.

Внимание!

Я замечал не понятное для меня поведение при включении mod_deflate и настройке кеширования через  mod_headers. Пропадал заголовок Content-Length и кеширование переставало работать. Решение нашлось - удаление заголовка из ответа:

<IfModule mod_headers.c>
    Header unset ETag
</IfModule>
FileETag None

В случае с mod_expires сжатие и кеширование работало нормально даже с выключенным модулем mod_headers. Отпишитесь, если вы знаете почему происходит так.

Немного в цифрах

Проанализируем профит от gzip-сжатия на примере библиотеки jquery-2.0.3.js. По факту, файл (не минифицированный) весит 236,5KB. mod_deflate сжимает его до 70 KB - не плохо. При следующем запросе, если включено кеширование, даже эти 70 KB не будут загружаться по сети - браузер достанет jQuery из кеша.

Проверим как жмутся минифицированные CSS/JS файлы на примере исходников Twitter Bootstrap 3. Имеем 2 файла bootstrap.min.css (100,5 KB) и bootstrap.min.js (27,1 KB) общим весом 127,6 KB. При включенном сжатии мы получаем 16,5 KB и 7,1 KB соответственно, в общем 23,6 KB.

В обеих случаях экономия порядка 70% трафика!

Полезное

  • https://github.com/h5bp/html5-boilerplate/blob/master/.htaccess (базовая настройка .htaccess)
  • http://habrahabr.ru/post/154643/ (Почти идеальный .htaccess)

#apache2, #.htaccess, #cache, #gzip, #оптимизация

категория: Linux