Редирект c HTTP на HTTPS в Nginx

Дата: 23.08.2015Метки:

Важным моментом в настройке SSL, является перенаправление всего HTTP-трафика на защищенное HTTPS-соединение. Надежнее всего это реализуется на уровне веб-сервера. Для того что бы принудительно с HTTP переадресовать всех посетителей на защищенное HTTPS соединение, необходимо в Nginx прописать в секцию server 301 редирект:

if ($scheme = http) {
       return 301 https://$server_name$request_uri;
    }
if ($host ~* www.) {
       return 301 https://$server_name$request_uri;
    }

Код статуса 301 означает, что запрашиваемая страница на постоянной основе перемещена на новый адрес. Что касается поисковых систем, то 301 редирект будет сигналом для переноса PR, тИЦ и всей ссылочной массы сайта. В результате, позиции сайта после повторной индексации останутся на прежнем уровне.

Настройка SSL в Nginx

Дата: 20.08.2015Метки:

Ранее я уже описывал процесс установки сертификата StartSSL и приводил пример минимального набора параметров необходимого для использования SSL в Nginx. В этой статье речь пойдет о более тонкой настройке. Сайт, настроенный по рекомендациям в данной статье, проходит проверку SSL на А+.

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

Настройку SSL в Nginx лучше начинать с минимальных рабочих параметров:

server {
    listen 443 ssl;
    server_name domain.net;

    ssl_certificate /etc/nginx/ssl/domain_com/domain.pem;
    ssl_certificate_key /etc/nginx/ssl/domain_com/domain.key;

    location / {
        root /usr/share/nginx/html;
        index index.html index.htm;
    }
}

Далее привожу краткое описание используемых директив.

Указываем путь к файлу содержащему “связку” из сертификатов: к сертификату сервера мы присоединяем промежуточный сертификат. Важно соблюдать правильную последовательность, иначе во время запуска Nginx вы получите ошибку.

# cat ssl.crt sub.class1.server.ca.pem > domain.pem
ssl_certificate /etc/nginx/ssl/domain.pem;

Необходимо расшифровать приватный ключ и указать путь к его файлу:

# openssl rsa -in ssl.key -out private.key;
ssl_certificate_key /etc/nginx/ssl/domain.key;

Перезапустим Nginx, если все работает правильно, можно переходить к дальнейшим настройкам.

Для использования набора шифров DHE, необходимо создать ключ Диффи-Хеллмана и указывать путь к файлу в настройка Nginx:

# openssl dhparam -out /etc/nginx/ssl/dhparam.pem 2048
ssl_dhparam /etc/nginx/ssl/dhparam.pem;

С включенным SSL сервер использует дополнительные ресурсы процессора. Для снижения количества операций необходимо задать размер кэша и время хранения SSL-сессий. В 1 мегабайт кэша помещается около 4000 сессий.

ssl_session_cache shared:SSL:10m;
ssl_session_timeout 5m;

Дополнительно для снижения нагрузки, мы обрабатываем сразу несколько запросов в рамках одного keepalive-соединения:

keepalive_timeout 70;

Указываем поддерживаемые сервером протоколы SSL:

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

Указываем, что серверные шифры имеют больший приоритет, чем клиентские шифры. Рекомендуемый набор шифров можно взять с официально сайта MozillaWiki. Можно сразу использовать использовать генератор конфига для Nginx.

ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA !RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DES";

Для уменьшая время загрузки страниц, разрешаем серверу для валидации сертификата прикреплять OCSP-ответы. Для работы функции необходимо указать путь к файлу сертификата издателя и DNS-сервер.

ssl_stapling on;
ssl_trusted_certificate /etc/nginx/ssl/ca.pem;
resolver 8.8.8.8;

Что бы указать браузеру, что сайт доступен только по HTTPS, необходимо указать заголовок:

add_header Strict-Transport-Security max-age=31536000 always;

Заголовок запрещает браузеру показывать сайт в фрейме:

add_header X-Frame-Options DENY;

Чтобы предотвратить MITM атаки с поддельными сертификатами, указываем заголовок Public-Key-Pins:

add_header Public-Key-Pins 'pin-sha256="base64+info1="; max-age=31536000' always;

Для директивы pin-sha256 используем одну из команд ниже:

openssl rsa  -in domain.key -outform der -pubout | openssl dgst -sha256 -binary | base64
openssl req  -in domain.csr -pubkey -noout | openssl rsa -pubin -outform der | openssl dgst -sha256 -binary | base64
openssl x509 -in domain.crt -pubkey -noout | openssl rsa -pubin -outform der | openssl dgst -sha256 -binary | base64

Указываем браузеру что бы он использовал отданный сервером Сontent-type, вместо автоматического его определения:

add_header X-Content-Type-Options nosniff;

Заголовок активирует XSS-защиту:

add_header X-XSS-Protection "1; mode=block";

Используем переадресацию на защищенное соединение:

server {
        listen 80 default_server;
        listen [::]:80 default_server ipv6only=on;

        server_name domain.net;
        return 301 https://domain.com;
}

Пример конфигурационного файла:

Влияние GZIP на производительность Nginx

Дата: 16.08.2015Метки:

Использование GZIP в Nginx может создавать сильную нагрузку на процессор и серьезно снизить производительность. Для устойчивой работы веб-сервера под нагрузкой, важно заранее подобрать оптимальные параметры. В процессе приходится искать своего рода компромисс межу степенью сжатия GZIP и производительностью Nginx.

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

Для замеров на виртуальной машине под Debian 8.1 была установлена последняя на текущий момент версия Nginx 1.9.3, собранного с параметром --with-http_gzip_static_module. Для тестирования использовался статический HTML-документ с главной страницы моего блога.

Производительности Nginx измерялась утилитой ApacheBench, запущенная со следующими параметрами:

service nginx restart && ab -c 100 -n 25000 -H "Accept-Encoding: gzip,deflate" "http://192.168.1.32/static.html"

Посмотреть полные данные тестирования можно на сайте GitHab. Для лучшей наглядности данные представлены в виде графиков ниже.

Поочередно изменяя значения параметра gzip_comp_level от 1 до 9 запускался ApacheBench. В конце каждого теста записывались данные о количестве обработанных запросов и объеме переданных данных.

Результаты измерений можно увидеть на графике ниже.

Следующий график содержит информацию о количестве переданных данных для различного уровня сжатия.

На последнем графике мы можем сравнить скорость работы Nginx с включенным и отключенным сжатием GZIP и использованием модуля gzip_static.

Исходя из полученных данных, можно сделать вывод о том, что уровень сжатия GZIP существенно влияет на производительность Nginx. На первом графике видно, что разница между максимальным и минимальным значениями достигает почти 2,5 раза.

Производительность операции упирается в ресурсы процессора. Начина с значения параметра gzip_comp_level равным 3, скорость начинает значительно проседать. По сравнению с данными полученными без использования сжатия, дальнейшее увеличение уровня компрессии не приносит существенного результата. Использование степени сжатия больше 6 вовсе не имеет смысла и приносит больше вреда чем пользы.

Дополнительно выполнены замеры для отдачи предварительно сжатых данных.  Результаты показывают, что использования модуля http_gzip_static_module является хорошей альтернативой GZIP сжатию на лету и позволяет существенно увеличить производительность Nginx.

Таким образом, на основе полученных данных можно сделать вывод, что наиболее эффективно будет передавать предварительно сжатые данные с использованием максимального уровнем сжатия. Для сжатия всех имеющихся CSS и JS файлов, необходимо выполнить команду:

for i in `find /home/www/* -type f -name '*.js'`; do echo $i; gzip -c -9 $i > $i.gz; touch -r $i $i.gz; done;
for i in `find /home/www/* -type f -name '*.css'`; do echo $i; gzip -c -9 $i > $i.gz; touch -r $i $i.gz; done;

Для того что бы удалит .gz архивы:

for i in `find /home/www/* -type f -name '*.js.gz'`; do echo $i; rm $i; done;
for i in `find /home/www/* -type f -name '*.css.gz'`; do echo $i; rm $i; done;

Для сжатия динамически создаваемых страниц напротив лучше использовать минимальные параметры уровня сжатия, я рекомендую становить значение параметра gzip_comp_level равным 2.

Рекомендуемые параметры GZIP для Nginx:

gzip on;
gzip_static on;
gzip_comp_level 2;

Установка Nginx с поддержкой HTTP/2

Дата: 14.08.2015Метки:

Завершение разработки протокола HTTP/2 стало первым крупным обновлением HTTP за последние 16 лет. При проектировании HTTP/2 основной фокус был направлен на оптимизацию алгоритмов передачи данных и ускорение загрузки страниц.

В качестве основы для HTTP/2 был взят уже существующий открытый протокол SPDY/3, первую версию которого Google представила в 2009 году. Согласно планам, HTTP/2 должен быстро вытеснить протокол SPDY, став его эволюционным продолжением. Уже в начале 2016 года Google планирует полностью перейти на новый стандарт и отказаться от поддержки SPDY в браузере Chrome.

Недавно была представлен тестовая версия модуля HTTP/2 для Nginx. В данный момент доступна альфа версия патча. Полную поддержку протокола HTTP/2 планируется ввести к концу этого года, а пока все желающие могут протестировать его в своих проектах.

Для сборки Nginx с поддержкой HTTP/2 необходим NGINX 1.9.0 и OpenSSL 1.0.2 или новее.

Добавим в /etc/apt/sources.list официальный репозиторий для mainline-ветки Nginx:

deb http://nginx.org/packages/mainline/debian/ codename nginx
deb-src http://nginx.org/packages/mainline/debian/ codename nginx

Скачиваем и устанавливаем PGP-ключ, затем обновляем индекс пакетов apt:

cd /tmp/ && wget http://nginx.org/keys/nginx_signing.key && apt-key add nginx_signing.key
apt-get update

Скачиваем необходимые для компиляции и сборки пакета программы, устанавливаем зависимости необходимые для Nginx:

apt-get install dpkg-dev
apt-get build-dep nginx

Скачиваем исходники Nginx:

cd /tmp
apt-get source nginx

Страница с патчами HTTP/2 для Nginx. Скачиваем патч HTTP/2 для нашей версии Nginx, проверяем возможность применения и если нет ошибок, по устанавливаем патч:

cd /tmp/nginx-1.9.3
wget http://nginx.org/patches/http2/patch.http2.txt
patch -p1 --dry-run < patch.http2.txt
patch -p1 < patch.http2.txt

Скачиваем и распаковываем исходники OpenSSL:

cd /tmp
wget https://openssl.org/source/openssl-1.0.2d.tar.gz
tar ixzvf openssl-1.0.2d.tar.gz

Перед началом сборки и компиляции необходимо внести изменения в файл:

nano /tmp/nginx-1.9.3/debian/rules

В секциях override_dh_auto_build и configure_debug необходимо удалить строку $(WITH_SPDY) и добавить в конец следующие опции:

--with-http_v2_module 
--with-openssl=/tmp/openssl-1.0.2

Для примера привожу фрагмент с изменениями из моего файла:

override_dh_auto_build:
	dh_auto_build
	mv objs/nginx objs/nginx.debug
	CFLAGS="" ./configure 
		--prefix=/etc/nginx 
		--sbin-path=/usr/sbin/nginx 
		--conf-path=/etc/nginx/nginx.conf 
		--error-log-path=/var/log/nginx/error.log 
		--http-log-path=/var/log/nginx/access.log 
		--pid-path=/var/run/nginx.pid 
		--lock-path=/var/run/nginx.lock 
		--http-client-body-temp-path=/var/cache/nginx/client_temp 
		--http-proxy-temp-path=/var/cache/nginx/proxy_temp 
		--http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp 
		--http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp 
		--http-scgi-temp-path=/var/cache/nginx/scgi_temp 
		--user=nginx 
		--group=nginx 
		--with-http_ssl_module 
		--with-http_gzip_static_module 
		--with-threads 
		--with-file-aio 
		--with-cc-opt="$(CFLAGS)" 
		--with-ld-opt="$(LDFLAGS)" 
		--with-ipv6 
		--with-http_v2_module 
		--with-openssl=/tmp/openssl-1.0.2
	dh_auto_build

После чего выполняем компиляцию и сборку deb-пакета:

cd /tmp/nginx-1.9.3
dpkg-buildpackage -rfakeroot -uc -b

После сборки пакета, установим Nginx командой:

dpkg -i nginx_1.9.3-1~jessie_i386.deb

Для включения поддержки HTTP/2 добавьте в конфигурационный файл Nginx вашего сайта параметры ssl и http2 к директивам listen:

server {
    listen 443 ssl http2 default_server;

    ssl_certificate     server.crt;
    ssl_certificate_key server.key;
    ...
}

На момент написания статьи в браузерах не реализована поддержка HTTP/2 без SSL шифрования, поэтому параметр ssl является обязательным. Как вариант — можно создать самоподписанный сертификат.

На данный момент статья частично потеряла свою актуальность, Начиная с версии Nginx 1.9.5 присутствует встроенная поддержка протокола. Информация о том как включить HTTP/2 в Nginx.

Установка Nginx из исходников

Дата: 13.08.2015Метки:

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

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

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

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

Для начала необходимо добавить официальный репозиторией Nginx. Для Debian замените codename на кодовое имя дистрибутива, и добавьте в конец файла /etc/apt/sources.list строки:

Для mainline-ветки.

deb http://nginx.org/packages/mainline/debian/ codename nginx
deb-src http://nginx.org/packages/mainline/debian/ codename nginx

Или для стабильной ветки.

deb http://nginx.org/packages/debian/ codename nginx
deb-src http://nginx.org/packages/debian/ codename nginx

Для проверки подлинности подписи репозитория Nginx, скачиваем PGP-ключ и устанавливаем его в связку ключей программы apt:

cd /tmp/ && wget http://nginx.org/keys/nginx_signing.key && apt-key add nginx_signing.key

Для обновления индекса пакетов выполним команду:

apt-get update

Выполним установку необходимых для компиляции и сборки программ, установим все необходимые зависимости для nginx:

apt-get install dpkg-dev
apt-get build-dep nginx
apt-get install libxslt1-dev libgd2-dev libgeoip-dev

На момент написания поста, я использовал последнюю версию nginx-1.9.3. Для сборки deb-пакета скачиваем с официального репозитория исходники Nginx:

cd /tmp
apt-get source nginx

Для того что бы изменить параметры компиляции, добавить или удалить модули Nginx, необходимо отредактировать файл:

nano /tmp/nginx-1.9.3/debian/rules

Нас интересует содержимое секции override_dh_auto_build. Здесь мы можем включить в сборку необходимы нам модули или удалить ненужные. Ниже приведен пример используемой мной конфигурация:

override_dh_auto_build:
	dh_auto_build
	mv objs/nginx objs/nginx.debug
	CFLAGS="" ./configure 
		--prefix=/etc/nginx 
		--sbin-path=/usr/sbin/nginx 
		--conf-path=/etc/nginx/nginx.conf 
		--error-log-path=/var/log/nginx/error.log 
		--http-log-path=/var/log/nginx/access.log 
		--pid-path=/var/run/nginx.pid 
		--lock-path=/var/run/nginx.lock 
		--http-client-body-temp-path=/var/cache/nginx/client_temp 
		--http-proxy-temp-path=/var/cache/nginx/proxy_temp 
		--http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp 
		--http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp 
		--http-scgi-temp-path=/var/cache/nginx/scgi_temp 
		--user=nginx 
		--group=nginx 
		--with-http_ssl_module 
		--with-http_gzip_static_module 
		--with-threads 
		--with-file-aio 
		$(WITH_SPDY) 
		--with-cc-opt="$(CFLAGS)" 
		--with-ld-opt="$(LDFLAGS)" 
		--with-ipv6
	dh_auto_build

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

cd /tmp/nginx-1.9.3
dpkg-buildpackage -rfakeroot -uc -b

Если в процессе не было ошибок, в каталоге /tmp мы увидим собранный из исходников deb-пакет nginx_1.9.3-1~jessie_i386.deb. Для его установки необходимо выполнить команду:

dpkg -i nginx_1.9.3-1~jessie_i386.deb

 

Обновление 07.03.16
Начиная с версии Nginx 1.9.11 используется поддержка динамических модулей. Связи с чем в процессе сборки пакета произошли изменения. При отключении некоторых модулей процесс сборки может завершаться ошибкой.

Создание самоподписанного SSL сертификата

Дата: 12.08.2015Метки:

Для публичных сайтов важно использовать SSL сертификаты подтвержденные в специальных центрах сертификации, наиболее известные из них: Comodo, GeoTrust, Rapid SSL, Symantec. Помимо защиты соединения, сертификат выданный удостоверяющим центром дает гарантию, что информация о домене была проверена независимым доверенным источником.

Как и доверительный, самоподписанный сертификат обеспечивает шифрование передаваемых данных между сервером и браузером пользователя. Главный недостаток самоподписанных сертификатов: необходимость подтверждения его в браузере. Для внутреннего использования, если нет необходимости в проверке домена, вполне нормально использовать самоподписанные сертификаты.

Генерируем ключ, в процессе необходимо будет ввести пароль.

openssl genrsa -des3 -out server.key.secure 2048

Расшифруем ключ:

openssl rsa -in server.key.secure -out server.key

Создаем файл сертификата:

openssl req -new -key server.key -out server.csr

В процессе необходимо будет указать информацию о себе.

Перейдем к процессу самоподписания сертификата:

openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

Сертификат готов, для использования необходимо скопировать файлы ключа server.key и сертификата server.crt в необходимую нам директорию.

Установка сертификатов StartSSL

Дата: 05.08.2015Метки:

Данная статья предполагает, что мы уже успешно прошли процедуру регистрации на сайте StartSSL и в нашем распоряжении есть следующие файлы: сертификат ssl.crt с проверкой домена и приватный ключ ssl.key. Копируем эти два файла на сервер. Приватный ключ перед использованием необходимо расшифровать командой:

openssl rsa -in ssl.key -out private.key

На этом этапе необходимо будет ввести пароль, который мы указывали в процессе заказа сертификата на сайте StartSSL.

Для безопасности установим права доступа на private.key:

# Только владелец может читать файл
chmod 400 /etc/nginx/ssl/*

Скачиваем сертификат Class 1 Intermediate Server CA:

wget http://www.startssl.com/certs/sub.class1.server.ca.pem

Объединяем сертификаты в один файл:

cat ssl.crt sub.class1.server.ca.pem > domain.pem

Минимальная конфигурацию NGINX для проверки работы SSL:

server {
    listen       443 ssl;
    server_name  domain.net;

    ssl_certificate      /etc/nginx/ssl/domain_com/domain.pem;
    ssl_certificate_key  /etc/nginx/ssl/domain_com/domain.key;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }
}

После изменения настроек необходимо перезапустить NGINX:

service nginx restart

Для проверки правильности установки сертификатов используем сервис Symantec SSL Toolbox.