Закрываем доступ к админке WordPress

Если у вас до сих пор свободно открыт доступ к админке WordPress, во избежание лишних проблем, я советую закрыть эту потенциальную дыру в безопасности. Возможно вы считаете, что для WordPress надежного пароля будет вполне достаточно. Но поверьте, закрыв доступ к админке WordPress вы не только снизите вероятность взлома, но и устраните одну из лазеек через которую могут положить ваш сайт.

Один из самых распространенных методов защиты админки сайта — использование HTTP-авторизации на уровне веб-сервера. Для этого нам необходимо предварительно сгенерировать файл .htpasswd, в котором будут хранится данные для авторизации. Затем указываем путь к .htpasswd в конфигурационном файле Nginx. Теперь при переходе по адресу /wp-admin или /wp-login.php Nginx запросит данные для авторизации.

Для генерации пароля необходимо использовать утилита генерации паролей .htpasswd. Пример конфигурации Nginx:

server {
    listen       80;
    server_name  localhost;

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

    location ~ ^/(wp-admin|wp-login.php) {
        auth_basic "closed site";
        auth_basic_user_file conf/.htpasswd;
        location ~ .php$ {
            root           html;
            fastcgi_pass   127.0.0.1:9000;
            fastcgi_index  index.php;
            fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
            include        fastcgi_params;
        }
    }
    
    location ~ .php$ {
        root           html;
        fastcgi_pass   127.0.0.1:9000;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
        include        fastcgi_params;
    }
}

Для удобства можно вынести секцию location ~ .php$ в отдельный файл:

# nano /etc/nginx/php-fpm.conf

location ~ .php$ {
    root           html;
    fastcgi_pass   127.0.0.1:9000;
    fastcgi_index  index.php;
    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
    include        fastcgi_params;
}

Тогда конфигурация Nginx будет выглядеть следующим образом:

server {
    listen       80;
    server_name  localhost;

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

    location ~ ^/(wp-admin|wp-login.php) {
        auth_basic "closed site";
        auth_basic_user_file conf/.htpasswd;

        include php-fpm.conf;
    }
    
    include php-fpm.conf;
}

Как по мне, метод описанный выше не самый удобным вариант для защиты WordPress. Поэтому, вместо HTTP-авторизации по паролю, я предпочитаю ограничить доступ к админке WordPress используя фильтр на основе ip-адреса. Данный способ не совсем правильно использовать если ваш провайдер использует динамическую адресацию, но как вариант придется указать диапазон адресов подсети провайдера.

server {
    listen       80;
    server_name  localhost;

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

    location ~ ^/(wp-admin|wp-login.php) {
        allow 82.82.82.82;    // Указываем адрес вашего подключения
        allow 82.82.82.0/24;  // Или подсети вашего провайдера (ip-calculator.ru)
        deny all;

        include php-fpm.conf;
    }
    
    include php-fpm.conf;
}

Удалить сайт из Internet Archive

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

Поэтому, для всех своих сайтов я предпочитаю закрыть доступ для робота Internet Archive. Для этого необходимо добавить в robots.txt следующие строки:

User-agent: ia_archiver
Disallow: /

Это не только запретить Internet Archive сканировать ваш сайт, но и даст сигнал на удаления всех сохраненных ранее страниц из Wayback Machine.

Исключить себя из статистики Яндекс.Метрики

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

Для этих целей в Яндекс.Метрике есть специальные фильтры, позволяющие не учитывать посетителей по указанному ip или диапазону адресов. Для того что бы добавить новый фильтр необходимо зайти в панель управления сайтом, после чего переходим в меню Настройки — Фильтр. После чего необходимо выбрать опцию «Не учитывать мои визиты» и добавить соответствующие параметры фильтрации.

Как вариант, можно сделать собственный фильтр адресов на стороне сервера. Данный метод хорошо подойдет как для Яндекс.Метрики так и для других сервисов оценки посещаемости сайтов. Для этого необходимо добавлять код счетчика в тело HTML документа только для тех посетителей, ip которых не попадает под заданный нами фильтр адресов. Для этого необходимо добавить в PHP шаблон страницы следующий код:

<?php if ( $_SERVER["REMOTE_ADDR"] != '127.0.0.1' ): ?>
// Код счетчика
<?php endif; ?>

Изменение часового пояса в Linux

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

Как правило, на Linux-серверах для настройки аппаратных часов используют время установленное по Гринвичу. Во время загрузки, Linux синхронизирует время с аппаратными часами с учетом сдвига для конкретной временной временной зоны. Абсолютное большинство программ в процессе работы используют время системных часов. После установки нового сервера важно указать правильные настройки часового пояса.

Делаем резервную копию файла с текущими настройками:

mv /etc/localtime  /etc/localtime-old

Создаем символическую ссылку на необходимый нам timezone:

ln -sf /usr/share/zoneinfo/Europe/Nederlands /etc/localtime

Для того чтобы убедиться что системное время соответствует выбранному часовому поясу, необходимо выполнить команду date. Результат выполнения команды:

Sat Sep 12 14:01:37 EEST 2015

Как вариант для изменения часового пояса в Debian можно использовать специальную утилиту. Для этого в терминале необходимо выполнит следующую команду:

dpkg-reconfigure tzdata

На экране появится псевдографический интерфейс, в котором необходимо выбрать регион и город.

Установка PHP 7 из исходников в Debian

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

Материал устарел, для установки PHP 7 читайте Установка PHP 7 в Debian 8.

Существенным аргументом в ползу перехода на PHP 7 является значительное увеличение производительности. Несмотря на отсутствие встроенного JIT-компилятора, в большинстве тестов PHP 7 удалось обогнать по производительности HHVM — транслятор исходного кода, специально созданный компанией Facebook для высокой производительности с целью экономии ресурсов серверов.

На протяжении разработки PHP 5, разработчикам с каждой новой версией удавалось добиться увеличения производительности. Но ближе к PHP 5.5 дальнейшее развитие сдерживала система выделения и освобождения памяти. В течении около пяти месяцев велась работа по рефрактору и изменению ядра, результаты работы получили кодовое имя phpng, так же известном как Zend Engine 3.

На момент написания записи доступен релиз кандидат PHP 7 RC2, финальная версия должна выйти в октябре этого года. На данный момент PHP 7 нет в стандартных репозиториях Debian, поэтому для установки PHP 7 его необходимо собирать исходников.

Для начала нам необходимо установить все необходимые для сборки PHP 7 пакеты:

apt-get install git-core cmake gawk libmysqlclient-dev 
  libxml2-dev libmcrypt-dev libicu-dev openssl build-essential binutils-dev 
  libcap-dev zlib1g-dev libtbb-dev libonig-dev libpcre3-dev 
  autoconf libtool libcurl4-openssl-dev wget memcached 
  libreadline-dev libncurses5-dev libmemcached-dev libbz2-dev 
  libc-client2007e-dev php5-mcrypt php5-imagick libgoogle-perftools-dev 
  libcloog-ppl-dev libelf-dev libdwarf-dev libunwind8-dev subversion 
  libtbb2 g++-4.8 gcc-4.8 libjemalloc-dev 
  libc6-dev libmpfr4 libgcc1 binutils 
  libc6 libc-dev-bin libc-bin libgomp1 
  libstdc++-4.8-dev libstdc++6 
  libarchive13 cmake-data libacl1 libattr1 
  g++ cpp gcc make libboost-thread1.55.0 
  libboost-thread-dev libgd2-xpm-dev 
  pkg-config libboost-system1.55-dev libboost-context1.55-dev 
  libboost-program-options1.55-dev libboost-filesystem1.55-dev libboost-regex1.55-dev 
  libmagickwand-dev libiberty-dev libevent-dev libxslt-dev libgoogle-glog-dev 
  automake libldap2-dev libkrb5-dev libyaml-dev gperf ocaml-native-compilers 
  libgmp-dev libgmp3-dev
ln -s /usr/include/x86_64-linux-gnu/gmp.h /usr/include/gmp.h

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

mkdir /tmp/php7 && cd /tmp/php7
wget https://downloads.php.net/~ab/php-7.0.0RC2.tar.gz
tar -xzf php-7.0.0RC2.tar.gz
mv php-7.0.0RC2 php-src

Минимальный набор компонентов PHP 7, необходимый для работы WordPress:

cd php-src
./buildconf --force
CONFIGURE_STRING="--prefix=/usr/local/php7 
--enable-fpm 
--enable-mysqlnd 
--enable-mbstring 
--enable-sockets 
--disable-ipv6 
--with-config-file-scan-dir=/usr/local/php7/etc/conf.d 
--with-curl 
--with-gd 
--with-fpm-user=www-data 
--with-fpm-group=www-data 
--with-mysql-sock=/var/run/mysqld/mysqld.sock 
--with-mysqli=mysqlnd 
--with-openssl 
--with-zlib 
--without-sqlite3 
--without-pdo-sqlite"

Компилируем PHP 7:

mkdir /usr/local/php7
./configure $CONFIGURE_STRING
make && make install

Создаем каталог для конфигурационных файлов PHP 7:

mkdir /usr/local/php7/etc/conf.d

Создаем символическую ссылку php-fpm для php7-fpm

ln -s /usr/local/php7/sbin/php-fpm /usr/local/php7/sbin/php7-fpm

Добавляем конфигурационные файлы:

cd /tmp/php7
cp php-src/php.ini-production /usr/local/php7/lib/php.ini
# nano /usr/local/php7/etc/php-fpm.d/www.conf

[www]

user = www-data
group = www-data

listen = /var/run/php7-fpm.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660

pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
# nano /usr/local/php7/etc/php-fpm.conf

[global]

pid = /var/run/php7-fpm.pid
error_log = /var/log/php7-fpm.log

include=/usr/local/php7/etc/php-fpm.d/*.conf
# mkdir /usr/local/php7/etc/conf.d/
# nano /usr/local/php7/etc/conf.d/modules.ini

# Zend OPcache
zend_extension=opcache.so

Добавляем PHP-FPM в автозагрузку:

# nano /etc/init.d/php7-fpm

#!/bin/sh
### BEGIN INIT INFO
# Provides:          php7-fpm
# Required-Start:    $remote_fs $network
# Required-Stop:     $remote_fs $network
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: starts php7-fpm
# Description:       Starts The PHP FastCGI Process Manager Daemon
### END INIT INFO

# Author: Ondrej Sury <ondrej@debian.org>
# Adjusted for PHP7 by Kaspars Dambis <hi@kaspars.net>

PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/php7/sbin
DESC="PHP7 FastCGI Process Manager"
NAME=php7-fpm
DAEMON=/usr/local/php7/sbin/$NAME
CONFFILE=/usr/local/php7/etc/php-fpm.conf
DAEMON_ARGS="--daemonize --fpm-config $CONFFILE"
CONF_PIDFILE=$(sed -n 's/^pid[ =]*//p' $CONFFILE)
PIDFILE=${CONF_PIDFILE:-/var/run/php7-fpm.pid}
TIMEOUT=30
SCRIPTNAME=/etc/init.d/$NAME

# Exit if the package is not installed
[ -x "$DAEMON" ] || exit 0

# Read configuration variable file if it is present
[ -r /etc/default/$NAME ] && . /etc/default/$NAME

# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh

# Define LSB log_* functions.
# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
. /lib/lsb/init-functions

# Don't run if we are running upstart
if init_is_upstart; then
    exit 1
fi

#
# Function to check the correctness of the config file
#
do_check()
{
    # Run php-fpm with -t option to check the configuration file syntax
    errors=$($DAEMON --fpm-config $CONFFILE -t 2>&1 | grep "[ERROR]" || true);
    if [ -n "$errors" ]; then
        echo "Please fix your configuration file..."
        echo $errors
        return 1
    fi
    return 0
}

#
# Function that starts the daemon/service
#
do_start()
{
	# Return
	#   0 if daemon has been started
	#   1 if daemon was already running
	#   2 if daemon could not be started
	start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null 
		|| return 1
	start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- 
		$DAEMON_ARGS 2>/dev/null 
		|| return 2
	# Add code here, if necessary, that waits for the process to be ready
	# to handle requests from services started subsequently which depend
	# on this one.  As a last resort, sleep for some time.
}

#
# Function that stops the daemon/service
#
do_stop()
{
	# Return
	#   0 if daemon has been stopped
	#   1 if daemon was already stopped
	#   2 if daemon could not be stopped
	#   other if a failure occurred
	start-stop-daemon --stop --quiet --retry=QUIT/$TIMEOUT/TERM/5/KILL/5 --pidfile $PIDFILE --name $NAME
	RETVAL="$?"
	[ "$RETVAL" = 2 ] && return 2
	# Wait for children to finish too if this is a daemon that forks
	# and if the daemon is only ever run from this initscript.
	# If the above conditions are not satisfied then add some other code
	# that waits for the process to drop all resources that could be
	# needed by services started subsequently.  A last resort is to
	# sleep for some time.
	start-stop-daemon --stop --quiet --oknodo --retry=0/30/TERM/5/KILL/5 --exec $DAEMON
	[ "$?" = 2 ] && return 2
	# Many daemons don't delete their pidfiles when they exit.
	rm -f $PIDFILE
	return "$RETVAL"
}

#
# Function that sends a SIGHUP to the daemon/service
#
do_reload() {
	#
	# If the daemon can reload its configuration without
	# restarting (for example, when it is sent a SIGHUP),
	# then implement that here.
	#
	start-stop-daemon --stop --signal USR2 --quiet --pidfile $PIDFILE --name $NAME
	return 0
}

case "$1" in
    start)
	[ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
	do_check $VERBOSE
	case "$?" in
	    0)
		do_start
		case "$?" in
		    0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
		    2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
		esac
		;;
	    1) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
	esac
	;;
    stop)
	[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
	do_stop
	case "$?" in
		0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
		2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
	esac
	;;
    status)
        status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
        ;;
    check)
        do_check yes
	;;
    reload|force-reload)
	log_daemon_msg "Reloading $DESC" "$NAME"
	do_reload
	log_end_msg $?
	;;
    reopen-logs)
	log_daemon_msg "Reopening $DESC logs" $NAME
	if start-stop-daemon --stop --signal USR1 --oknodo --quiet 
	    --pidfile $PIDFILE --exec $DAEMON
	then
	    log_end_msg 0
	else
	    log_end_msg 1
	fi
	;;
    restart)
	log_daemon_msg "Restarting $DESC" "$NAME"
	do_stop
	case "$?" in
	  0|1)
		do_start
		case "$?" in
			0) log_end_msg 0 ;;
			1) log_end_msg 1 ;; # Old process is still running
			*) log_end_msg 1 ;; # Failed to start
		esac
		;;
	  *)
	  	# Failed to stop
		log_end_msg 1
		;;
	esac
	;;
    *)
	echo "Usage: $SCRIPTNAME {start|stop|status|restart|reload|force-reload}" >&2
	exit 1
    ;;
esac

:
chmod +x /etc/init.d/php7-fpm
update-rc.d php7-fpm defaults

Для работы PHP-FPM через сокет необходимо необходимо внести изменения в файл:

nano /usr/local/php7/etc/php-fpm.d/www.conf

Вместо настройки параметров порта, необходимо добавить следующие строки:

listen = /var/run/php7-fpm.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660

Для запуска PHP7-FPM необходимо выполнить следующую команду:

service php7-fpm start

Nginx: an upstream response is buffered to a temporary file

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

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

[warn] 3400#3400: *21 an upstream response is buffered to a temporary file /var/cache/nginx/fastcgi_temp/1/00/0000000001 while reading up

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

Исправить: an upstream response is buffered to a temporary file

Для устранения предупреждения, необходимо увеличить размер буфера в Nginx. Для этого в секцию location ~ .php$, необходимо добавить следующие параметры:

fastcgi_buffers 4 256k;
fastcgi_busy_buffers_size 256k;
fastcgi_temp_file_write_size 256k;

В итоге должно получится как в примере ниже:

location ~ .php$ {
    try_files $uri = 404;
    fastcgi_pass unix:/var/run/php-fpm.sock;
    fastcgi_index  index.php;
    fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
    fastcgi_buffers 4 256k;
    fastcgi_busy_buffers_size 256k;
    fastcgi_temp_file_write_size 256k;
    include fastcgi_params;
}

Подробнее о изменении размера буфера под конкретно ваши условия можно прочитать в этой статье.

Редирект 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, тИЦ и всей ссылочной массы сайта. В результате, позиции сайта после повторной индексации останутся на прежнем уровне.

Добавляем SWAP в Linux

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

При заказе виртуального сервера, часто для установки используется заранее подготовленные шаблоны, из-за чего в системе может отсутствовать SWAP-раздел. Что бы предотвратить ошибки вызванные переполнением RAM и обеспечит нормальное функционирование системы в будущем, необходимо добавить в систему дополнительное SWAP-пространство.

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

Ниже приведен пример скрипта для быстрой настройки SWAP:

if [ -f /swapfile ]; then
    echo "Swapfile already exists?"
    exit 1
fi

fallocate -l 4G /swapfile
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
sysctl vm.swappiness=10
sysctl vm.vfs_cache_pressure=50
echo "/swapfile   none    swap    sw    0   0" >> /etc/fstab
echo vm.swappiness=10 >> /etc/sysctl.conf
echo vm.vfs_cache_pressure=50 >> /etc/sysctl.conf

Параметр vm.swappiness указывает системе при каком минимальном проценте свободной памяти необходимо задействовать SWAP. Значение параметра может быть в пределах от 0 — 100. Но для улучшения производительности лучше установит значение данного параметра равным 10.

В случае использования SSD, необходимо уменьшит размер дискового кэша, для этого рекомендуется установить значение параметра vm.vfs_cache_pressure равным 50.

Иногда может возникнуть необходимость очистить SWAP без перезагрузки системы, для этого используем следующую команду:

swapoff -a && swapon -a

Для принудительной очистки системных кэшей используем команду:

sync

# Чистим pagecache:
echo 1 > /proc/sys/vm/drop_caches

# Чистим dentrie и inode кэши:
echo 2 > /proc/sys/vm/drop_caches

# Чистим pagecache, dentrie и inode кэши:
echo 3 > /proc/sys/vm/drop_caches

Как правило, я старюсь перегружать сервер только при крайней необходимости. Одна из причин, по которой я люблю Linux — если не течет память, то система абсолютно не нуждается в перезагрузке. Исключительно в целях профилактики чтобы очистить кеши и SWAP, на всех своих серверах в cron добавляю следующую команду:

0 0 * * * swapoff -a && swapon -a && sync && echo 3 > /proc/sys/vm/drop_caches

Настройка 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;