Итак, был конец 2015 года, я смотрел на свой давний проект spaceismine.org, на котором всякие картинки-статика, и тут в голову ударило: “Вообще-то всю статику можно грузить по одному TCP-соединению гораздо эффективнее! Какого чёрта у меня до сих пор не поддерживается модный и красивый HTTP/2?!” Что ж, вопрос требовал скорее действий, чем ответа, поэтому недолго думая, я начал копать, как же там всё у nginx с этим обстоит. Я в течение всего года наблюдал, как постепенно в этом веб-сервере пилится поддержка HTTP/2 в версиях 1.9.x. И действительно, поддержка уже есть, но она всё ещё обкатывается, о чём свидетельствует название PPA, который мне пришлось добавить:

sudo add-apt-repository ppa:nginx/development

В ppa:nginx/stable всё ещё версия 1.8.0. Но, как я всегда говорю, жизнь меня ничему не учит мои пет-проекты вовсе никакие не супер-важные, поэтому я решил обновиться. Почему нет. Итак, поддержка HTTP/2 у меня была в кармане.

Немного проглядев информацию про сам протокол, стало понятно, что он может работать только в шифрованном режиме. Получать через пень-колоду бесплатный долгосрочный сертификат через китайцев, как я это делал прошлой весной, вовсе не хотелось. Хотелось попробовать что-то новое. И тут очень кстати мне вспомнился проект Let’s Encrypt.

Let’s Encrypt и бесплатный HTTPS всем

Этот амбициозный проект был начат двумя сотрудниками Mozilla, но теперь он уже существенно вырос и обзавёлся поддержкой многих гигантов (таких как Akamai, Cisco, Facebook). Центр сертификации Let’s Encrypt вошёл в стадию открытой беты в начале декабря 2015 года и с тех пор раздаёт бесплатные сертификаты. Сертификаты выдаются всего на 3 месяца, но процесс их получения заключается в запуске всего лишь одного скрипта с указанием e-mail’а и доменов. Мне сходу понравилась эта простота после китайцев, да и бесплатность была тоже очень кстати.

Этот скрипт, который вам придётся поставить на сервер, проверяет, что вы являетесь владельцем домена. Это возможно в нескольких режимах:

  • apache – его я не пробовал, у меня же nginx, но, поговаривают, этот режим весь такой красивый и полностью автоматизированный
  • standalone – через запуск встроенного веб-сервера на 80-м порту, что мне тоже не подошло, у меня же nginx на нём висит и работает в любой момент времени
  • webroot – выбрал именно этот вариант, проверка осуществляется созданием специального файла в корневой директории сайта, которую вы укажете в параметре --webroot

Я склонировал репозиторий себе:

git clone https://github.com/letsencrypt/letsencrypt
cd letsencrypt

Разобравшись с параметрами, у меня в итоге получилась примерно такая команда для получения сертификата:

./letsencrypt-auto certonly --webroot -w /var/www/spaceismine/html/ --email [email protected] -d spaceismine.org -d www.spaceismine.org

Вероятно, понадобится sudo-пароль, потому что скрипт будет записывать сертификаты в /etc. Но у меня sudo уже торчал в сессии, не помню, чтобы мне приходилось вводить пароль. После того, как команда успешно отработала, в директории /etc/letsencrypt/live/spaceismine.org аккуратным образом появились симлинки на ключ, сертификат, цепочки.

nginx ~ HTTP/2 ~ HTTPS

Далее нужно было настроить nginx. Прикладываю свой конфиг:

server {
    listen 80;
    server_name spaceismine.org www.spaceismine.org;
    rewrite ^(.*) https://spaceismine.org$1 permanent;
}

server {
    listen 443 ssl http2;

    server_name spaceismine.org;
    root /var/www/spaceismine/html;
    index index.html;

    ssl_certificate /etc/letsencrypt/live/spaceismine.org/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/spaceismine.org/privkey.pem;
    add_header Strict-Transport-Security 'max-age=604800';
}

Суть первых строк в том, что мы HTTP будем всегда кидать на HTTPS. Ну и для верности добавим хидер add_header Strict-Transport-Security 'max-age=604800';, чтобы браузерам было попроще и попонятнее перекидывать пользователя на нужный вариант протокола. Как видите, конфиг вышел на удивление простой, что не может не радовать.

Подвохи и рейтинг A на ssllabs

Затем у меня были некоторые проблемы с тем, что сайт открывался только в Safari. Я долго пытался понять, с чем это может быть связано. Но в итоге вспомнил, что слабые алгоритмы в последнее время активно выпиливаются браузерами, поэтому нашёл способ, как можно было настроить более “качественный” HTTPS в nginx.

Прикладываю конфиг секции http главного конфига nginx.conf, который позволил добиться мне A на тесте ssllabs:

ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_stapling on;
ssl_dhparam ssl/dhparam.pem;
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_dhparam ssl/dhparam.pem;. Да, пришлось сгенерить свой dhparam на 2048 бит:

openssl dhparam -out /etc/nginx/ssl/dhparam.pem 2048

Учтите, что директория /etc/nginx/ssl должна существовать, иначе openssl ничего не сделает.

Далее service nginx restart и всё стало хорошо во всех браузерах, а в ssllabs начала красоваться A:

HTTP/2 в nginx при помощи Let's Encrypt

Что ж, на этом всё, таков был мой опыт настройки HTTP/2 на своём проекте. Так что если вам это интересно, конечно берите и пробуйте, всё можно использовать уже сейчас.

Ссылки

  1. Хорошее пояснение/обзор/бенчмарк на тему HTTP/2 на хабре
  2. Проект Let’s Encrypt на github
  3. Неплохая статья о конфигурировании HTTPS на сайте nginx