Переносим сайты на HTTPS с помощью Nginx, Varnish и Apache

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

В данной статье мы абстрагируемся от причин перехода к HTTPS и рассмотрим техническую сторону этого процесса. Мы перенесем наш сайт на HTTPS, воспользовавшись преимуществами Varnish Cache.

В чем заключается проблема с Varnish и HTTPS?

В прошлых статьях мы уже говорили о том, что Varnish позволяет ускорить работу сайта. Однако те, кто использует Varnish и хочет перейти на HTTPS, могут столкнуться с проблемой: Varnish не поддерживает HTTPS. Если вы перейдете на SSL, настроив Apache для безопасной работы с сайтом, вы лишитесь всех преимуществ скорости, которые предлагает Varnish.

Есть достаточно простой способ справиться с этой проблемой, и он состоит во введении дополнительного уровня, лежащего между входящими SSL-запросами и Varnish, – уровня, который будет обрабатывать безопасное соединение и SSL-сертификаты, после чего передавать запрос обратно к Varnish. Для реализации данного уровня мы воспользуемся Nginx. Вы, возможно, знаете, что Nginx является альтернативой Apache. Однако Nginx может также использоваться как прокси-сервер для обработки и передачи запросов к другим сервисам. Именно в таком ключе мы и будем его использовать в данной статье. Иными словами, мы создадим серверный «сэндвич», в центре которого будет располагаться наша аппетитная «котлета» — кэш Varnish.

Что мы имеем и что мы хотим сделать

Я буду исходить от предположения, что вы находитесь в той же самой ситуации, что и я – у вас имеется сервер, виртуальный или выделенный, на котором работают многочисленные веб-сайты. Некоторые из этих сайтов вы хотите полностью перевести на HTTPS, в то время как остальные могут пока оставаться с HTTP.

В вашей текущей конфигурации каждый запрос к порту 80 может обрабатываться Varnish. Затем Varnish на основе правил, добавленных к Varnish Configuration Language (VCL), решает, предложить ли кэшируемую копию страницы или передать запрос обратно Apache для создания новой страницы. После того как запрос поступит в Apache, веб-сервер может потребовать некоторую информацию из базы данных (либо он может выполнить какую-либо другую обработку перед созданием страницы).

К концу этого руководства мы получим следующее:

  • Nginx будет запущен с портом 443. Он будет обрабатывать входящие HTTPS-запросы, передавая их затем Varnish.
  • Varnish будет запущен с портом 80. Он будет обрабатывать входящие HTTP-запросы, включая те, которые были получены от Nginx, выдавая страницы из кэша или обращаясь к Apache.
  • Apache будет запущен с портом 8080. Он будет делать то, что должен делать Apache: выводить ваш сайт или приложение.

В такой ситуации Nginx становится прокси. Он не делает никакой обработки вашего сайта, он не выполняет PHP, не взаимодействует с базой данных. Все, что делает Nginx – просто принимает HTTPS-запросы и отдает их Varnish. Varnish затем уже принимает решение, вернуть ли кэшируемую копию или обратиться к Apache, чтобы тот уже поставил свежую версию контента. Все это происходит на основе правил Varnish, которые вы уже имеете.

Моя тестовая среда

Я буду работать с Vagrant, используя Ubuntu Trusty. Как уже было сказано выше, Apache у меня привязан к порту 8080, а Varnish 4 – к порту 80.

Вы можете загрузить мою тестовую среду с GitHub. Инструкции по ее установке находятся в файле readme.

У меня есть два сконфигурированных сайта. Если я посещу эти сайты в браузере, то Varnish обработает запрос в порте 80, либо поставив файл из кэша, либо обратившись к Apache.

В данный момент полезно проверить, какие порты у нас используются. Подключаемся по SSH к Vagrant:

vagrant ssh

Затем выполняем netstat:

sudo netstat -taupen

Мы получим список портов, а также информацию о том, какие процессы их используют. Вы должны отметить, что Varnish работает с портом 80, а Apache – с 8080.

01-netstat-opt-small

Вы также можете убедиться в том, что Varnish работает в обычном режиме и выдает страницы из кэша:

varnishstat

02-varnishstat-opt-small

Если вы перезагрузите страницу в браузере, вы сможете увидеть статистику обращения к кэшу.

Если вы используете мой VCL с GitHub, то вы можете видеть, что я добавил к конфигурации Varnish некоторый код, который передает браузеру заголовок HIT или MISS. Это означает, что вы можете видеть, какой заголовок был отправлен. Вы должны увидеть X-Cache: HIT, если страница была получена из кэша Varnish, и X-Cache: MISS, если страница поступила от Apache.

03-browser-HIT-opt

Установка Nginx

Теперь мы установим Nginx. В системе с Ubuntu это сделать очень просто:

sudo apt-get install nginx

Документация Nginx содержит в себе информацию об установке Nginx на разных системах, а также пакеты для систем, которые не входят в их систему управления пакетами. Помните, что мы используем Nginx только в качестве прокси, т.е. нам не понадобится заниматься настройкой поддержки PHP или MySQL. Nginx не запустится по умолчанию, поскольку в данный момент порт 80 уже используется Varnish. Если вы делаете это на работающем сервере, то вы можете легко выполнить этот шаг, не опасаясь за работоспособность ваших запущенных сайтов.

Создаем или устанавливаем SSL-сертификат

Следующий шаг – установка SSL-сертификата. Поскольку мы работаем локально, мы можем создать самоподписанный сертификат с целью тестирования SSL-соединения.

Чтобы создать самоподписанный сертификат для тестирования, выберите или создайте директорию, в которой он будет находиться. Я создал директорию nginx в /etc/ssl. Затем выполните следующую команду для генерации ключа и сертификата.

sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/ssl/nginx/smashing_ssl_one.tutorials.eoms.key -out /etc/ssl/nginx/smashing_ssl_one.tutorials.eoms.crt

Когда вы выполните эту команду, вам будет задана серия вопросов. Вы можете написать любую ерунду в качестве ответов; однако, когда у вас спросят «Common Name», используйте домен, который вы обычно вводите в строку URL для доступа к вашему сайту в Vagrant. В моем случае это smashing_ssl_one.tutorials.eoms:

04-self-signed-opt-small

Если вы теперь заглянете в папку, которую вы создали, вы должны увидеть в ней два файла: один с расширением .key и другой с расширением .crt.

Для работающего сервера вы должны, естественно, заказать сертификат от центра сертификации. В таком случае вы получите готовый ключ и файл сертификата – вам не придется создавать их вручную. Вам нужно будет разместить их на своем сервере перед тем, как выполнить следующий шаг.

Настраиваем SSL для сайтов в Nginx

Как только вы поместите в папку на сервере ваш самоподписанный или приобретенный SSL-сертификат, вы можете заняться настройкой ваших сайтов в Nginx.

Во-первых, удалите стандартный конфигурационный файл из /etc/nginx/sites-enabled. Вы можете удалить файл default или переместить его в другую папку.

Нам нужно настроить только те сайты, которые будут выводиться через SSL; все остальные сайты продолжат выводиться через Varnish, запущенный на порте 80. В моем случае я буду настраивать smashing_ssl_one.tutorials.eoms. Везде, где вы далее увидите этот домен, вам нужно будет его заменить на свой домен (локальный или онлайн). Исключение: тот случай, если вы используете мою рабочую среду, которая была приведена по ссылке выше.

В директории /etc/nginx/sites-available/ создаем конфигурационный файл your_domain.com.conf. В этот файл добавляем следующее:

server {
  listen *:443 ssl;
  server_name smashing_ssl_one.tutorials.eoms;

  ssl on;
  ssl_certificate /etc/ssl/nginx/smashing_ssl_one.tutorials.eoms.crt;
  ssl_certificate_key /etc/ssl/nginx/smashing_ssl_one.tutorials.eoms.key;

  location / {

    proxy_pass            http://127.0.0.1:80;
    proxy_read_timeout    90;
    proxy_connect_timeout 90;
    proxy_redirect        off;

    proxy_set_header      X-Real-IP $remote_addr;
    proxy_set_header      X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header      X-Forwarded-Proto https;
    proxy_set_header      X-Forwarded-Port 443;
    proxy_set_header      Host $host;
  }
}?

Первая строка говорит серверу, что мы «слушаем» порт 443. Это стандартный порт для HTTPS-соединений, так же как и порт 80 для HTTP. Затем мы задаем имя сервера.

Мы включаем SSL и добавляем сертификат с ключом, который мы создали или установили, указывая полный путь.

В разделе location мы используем proxy_pass для передачи запроса к порту 80, где Varnish ждет его. Затем мы устанавливаем заголовки, которые будут переданы дальше.

После добавления этого файла мы создаем символьную ссылку на файл, меняя sites-available на sites-enabled. Если вы когда-либо захотите отключить сайт, вы сможете просто удалить символьную ссылку. Следующая команда создаст символьную ссылку:

ln -s /etc/nginx/sites-available/smashing_ssl_one.tutorials.eoms.conf /etc/nginx/sites-enabled/smashing_ssl_one.tutorials.eoms.conf

Теперь делаем рестарт Nginx:

sudo service nginx restart

Если вы столкнулись с выводом restarting nginx nginx, следуемым за [fail], то, скорее всего, проблема скрывается в опечатке в конфигурационном файле. Моя обычная проблема: либо я забываю разделить ключи и значения с помощью двоеточия, либо я забываю точку с запятой в конце строки.

Если Nginx не может запуститься, изучите лог по адресу /var/log/nginx/error.log, поскольку большинство проблем можно решить именно так.

Если Nginx успешно запустился, вы увидите [OK]. Теперь, если вы проверите, какой процесс работает с каждым портом, вы должны увидеть, что Nginx работает с 443, Varnish — с 80 и Apache — с 8080.

sudo netstat -taupen

Теперь нам нужно будет посетить сайт по протоколу https://. Если вы используете самодподписанный сертификат, то в таком случае вы должны получить следующее предупреждение – ваш браузер сообщит вам, что сертификат выпущен неизвестным центром сертификации.

05-exception-opt-small

Если вы увидите замок в адресной строке браузера, то в таком случае HTTPS теперь обслуживается через Nginx. Если вы проверите заголовки HIT или MISS или запустите varnishstat в командной строке, вы сможете посмотреть, какие страницы были переданы от Varnish без обращения к Apache.

06-secure-opt-small

Редирект к SSL с помощью Varnish

Как показывает моя практика, вы можете захотеть выполнить некоторые улучшения.

Если ваш сайт запущен на HTTP и вы хотите запустить его на HTTPS, то вам понадобится задать редирект для всех HTTP-запросов. Вы можете сделать это с помощью Varnish. Varnish в данный момент запущен на порте 80, обрабатывая все не-SSL запросы. Мы хотим сделать так, чтобы Varnish фиксировал запрос к нашему сайту и перенаправлял его по HTTPS.

В нашем VCL файле по адресу /etc/varnish/default.vcl мы добавим следующую подпрограмму:

# handles redirecting from http to https
sub vcl_synth {
  if (resp.status == 750) {
    set resp.status = 301;
    set resp.http.Location = req.http.x-redir;
    return(deliver);
  }
}

Затем в блоке sub vcl_recv добавим следующее:

if ( (req.http.host ~ "^(?i)smashing_ssl_one.tutorials.eoms") && req.http.X-Forwarded-Proto !~ "(?i)https") {
  set req.http.x-redir = "https://" + req.http.host + req.url;
  return (synth(750, ""));
}

Вы можете видеть полный VCL, включая весь представленный код, в GitHub.

Я сопоставляю домен с паттерном, после чего перенаправляю его к HTTPS с кодом 301 (Moved Permanently). Таким образом, теперь все должно быть перенесено на SSL-рельсы. Перезапускаем Varnish и пробуем перейти к HTTP версии сайта, проверив работу переправления.

Еще одна хорошая проверка – использование cURL в командной строке. Следующая команда вернет только заголовки вашего запроса. Вы можете убедиться в том, что вы получаете 301 при тестировании HTTP URL-адреса.

curl -I http://smashing_ssl_one.tutorials.eoms

07-headers-redirect-opt-small

Если вы получаете слишком много обращений к Apache (MISS), то в таком случае вам нужно проверить работу с cookies в Varnish. Varnish не кэширует контент с cookies, поскольку он предполагает, что это персонализированный контент. Однако такие вещи, как cookie от Google Analytics, не должны приводить к тому, что ваш контент становится некэшируемым. В моем VCL я обрабатываю некоторые популярные cookie, однако вы можете прочитать также следующий пост от Mattias Geniar о том, какие cookie передаются в бэкэнд.

Тестируем SSL

Вы, наверно, слышали о различных уязвимостях в OpenSSL. Если вы хотите переключить все ваши сайты на HTTPS, то в таком случае убедитесь в том, что вы защищены от всех этих проблем.

Как только у вас будет работающий веб-сайт с SSL, вам понадобится протестировать его при помощи SSL Server Test от Qualys SSL Labs. Добавьте ваше доменное имя и ждите, пока тесты выполнятся. Тест покажет вам самые популярные проблемы с SSL конфигурацией – ваша цель: пройти тесты с рейтингом A.

Когда я первый раз прошел тесты с Vagrant — Ubuntu Trusty, Nginx, Varnish и Apache – я получил рейтинг B, поскольку сервер был уязвим к атакам Logjam. Защита от таких атак детально описана в статье: «Weak Diffie-Hellman and the Logjam Attack».

Возвращаемся к нашему серверу, переходим (cd) к директории, в которой хранится SSL-сертификат, после чего выполняем следующее:

openssl dhparam -out dhparams.pem 2048

Это приведет к созданию файла dhparams.pem.

Вы можете теперь добавить к вашей конфигурации Nginx код, представленный в разделе Nginx статьи «Weak Diffie-Hellman and the Logjam Attack».

server {
  listen *:443 ssl;
  server_name smashing_ssl_one.tutorials.eoms;

  ssl on;
  ssl_certificate /etc/ssl/nginx/smashing_ssl_one.tutorials.eoms.crt;
  ssl_certificate_key /etc/ssl/nginx/smashing_ssl_one.tutorials.eoms.key;
  ssl_dhparam /etc/ssl/nginx/dhparams.pem;
  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
  ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';

  ssl_prefer_server_ciphers on;

  location / {

   proxy_pass            http://127.0.0.1:80;
   proxy_read_timeout    90;
   proxy_connect_timeout 90;
   proxy_redirect        off;

   proxy_set_header      X-Real-IP $remote_addr;
   proxy_set_header      X-Forwarded-For $proxy_add_x_forwarded_for;
   proxy_set_header      X-Forwarded-Proto https;
   proxy_set_header      X-Forwarded-Port 443;
   proxy_set_header      Host $host;

  }
}?

Перезагружаем Nginx и заново тестируем сайт. После того, как вы добьетесь рейтинга А, вы можете периодически проводить тесты для проверки соблюдения всех правил.

08-ssl-test-opt-small

Уведомления о смешанном контенте

Ваш сайт может иметь ресурсы, загружаемые с других доменов, которые не являются HTTPS – это может привести к появлению предупреждений на вашем сайте. В большинстве случаев третья сторона будет иметь конечные точки HTTPS, на которые вы можете ставить ссылки. Однако мне пришлось удалить значок Lanyrd с моего сайта, поскольку JavaScript был размещен только на HTTP.

Блог про WordPress
Комментарии: 8
  1. Petrozavodsky

    Может тогда кто нибудь скажет где можно легко и не очень дорого купить такой сертификат чтоб было на домен и один его поддомен

    1. Дмитрий (автор)

      Вообще, для защиты сайта и поддоменов нужен Wildcard SSL сертификат, по типу вот такого:
      https://www.instantssl.su/suppliers/comodo/products/wildcard.
      Но он стоит довольно дорого и в основном его берут хостинг-компании. А если для личного пользования, то выгоднее два SSL-сертификата отдельных покупать.

      К примеру, вот таких: https://www.instantssl.su/suppliers/comodo/products/positivessl

      Или вот таких: https://www.instantssl.su/suppliers/comodo/products/essentialssl

      1. Salik

        reg.ru бесплатно раздает сейчас ssl сертификаты :)

        1. Дмитрий (автор)

          Не нашел у них бесплатных сертификатов.

  2. Иван

    Хотел перейти но пока дороговато. На моем хостинге стоимость сертификата составляет 2000 рублей в год (включая выделенный IP адрес). Хотя есть интернет-магазин, его надо бы перевести

    1. Дмитрий (автор)

      Для начала подойдет какой-нибудь DV — просто ради защиты транзакций. От фишинга он не спасет.

      А вообще пользователи замечают только визуальный сигнал по типу зеленой строки в браузере и наименования компании в ней. Это помогает реализовать только EV.

      Покупка у хостинга — не самый лучший вариант. Если потом захотите уйти от него, то возникнут проблемы. Вряд ли кто-то будет возвращать деньги, которые вы оплатили за сертификат. Лучше брать у сторонних компаний, ссылку я приводил в комментарии выше. Так больше гибкости.

  3. Иван

    Благодарю за совет, но ссылки выше не отрываются, пишет нет соединения

    1. Дмитрий (автор)

      Небольшой дизастер, скоро должно все заработать.

      p.s. Уже.

Добавить комментарий

Получать новые комментарии по электронной почте.