78 KiB
Инструкция по развёртыванию на VDS-хостинге (виртуальная машина) на примере masterhost.ru
1: Создание пользователя
Изначально есть только root-доступ. Если мы залогированы под root, то следует создать пользователя от имени которого мы будем осуществлять все действия (позже root-доступ будет закрыт). Создадим пользователя <ssh_user>:
sudo useradd -c 'WEB-user' -m <ssh_user>
Присвоим ему пароль:
sudo passwd <ssh_user>
Дадим ему права работать от имени root. Для этого откроим на редактирование конфигурационный файл /etc/sudoers:
nano /etc/sudoers
и после строки root ALL=(ALL:ALL) ALL добавим в него строку:
<ssh_user> ALL=(ALL:ALL) ALL
Сохраняем конфигурационный файл Ctrl+O и Enter, а выходим из редактора Ctrl+X.
ВАЖНО: Если по какой-то причине файл /etc/sudoers пустой -- это означает, что служба sudoers не установлена.
Её нужно установить: apt-get install sudo.
Разлогируемся оз под root.
logout
Теперь можно залогироваться от имени пользователя <ssh_user>.
Установим командную оболочку bash для пользователя:
chsh -s /bin/bash
2: Настройка SSH и окружения клиента
Ограничиваем доступ root и повышение безопасности SSH
После завершения перезагрузки произведённой в конце предыдущего этапа мы можем заходить на наш сервер по SSH под новым, только что созданным, пользователем [user] и паролем [user_pwd]. Теперь следует сделать небольшие изменения в файле /etc/ssh/sshd_config -- конфигурации ssh-доступа:
sudo nano /etc/ssh/sshd_config
Полное описание настроек sshd_config находится на сайте Ubuntu. Там содержатся
вполне разумные рекомендации по увеличению безопасности. Откроем на редактирование конфигурационный файл /etc/ssh/sshd_config:
sudo nano /etc/ssh/sshd_config
И изменим порт на котором будет отвечать SSH:
Port 2002
Так же дописываем в конце следующие две строки в которых и запрещаем ssh-вход пользователя root и разрешаем доступ нашему пользователю <ssh_user>:
DenyUsers root
AllowUsers <ssh_user>
Сохраняем конфигурационный файл Ctrl+O и Enter, а выходим из редактора Ctrl+X.
Чтобы настройки подействовали нужно перезапустить ssh-сервис:
sudo service ssh restart
Проверим, что сервис корректно перезапустился:
sudo service sshd status
Увидим, что все работает:
● ssh.service - OpenBSD Secure Shell server
Loaded: loaded (/lib/systemd/system/ssh.service; enabled; vendor preset: enabled)
Active: active (running) since Wed 2022-05-25 01:01:24 MSK; 2 days ago
Docs: man:sshd(8)
man:sshd_config(5)
Main PID: 647 (sshd)
Tasks: 1 (limit: 1066)
Memory: 5.8M
CGroup: /system.slice/ssh.service
└─647 sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups
Разлогируемся -- logout. Входим ещё раз и можем проверяем, что теперь пользователя root больше в систему по SSH не пускают. Логируется вновь созданным пользователем [user].
Упрощение идентификации сервера при входе
В конфигурационном файле /etc/ssh/sshd_config есть специальный параметр Banner в котором указывается файл, который следует показать при входе (обычно /etc/ssh_banner). Его отображение упрощает идентификацию сервера при входе, его сложнее спутать с другими, особенно когда работа идёт одновременно с терминалами нескольких серверов. Но он этот баннер отображается только при входе через SSH. Существует более радикальное решение, отображающееся и при обычном входе. Оно упростит идентификацию даже если мы работаем с консоли (например, в случае нескольких виртуальных серверов на одном физическом).
Очистим файл /etc/motd, и поместим туда какой-нибудь красивый ASCII-арт текст из ASCII-генератора. :
sudo nano /etc/motd
Например, вот так:
███████╗░░░░░░██████╗███████╗██████╗░░██████╗░ MASTERHOST.RU HOSTED:
██╔════╝░░░░░██╔════╝██╔════╝██╔══██╗██╔════╝░
█████╗░░████╗╚█████╗░█████╗░░██████╔╝██║░░██╗░ cadpoint.ru
██╔══╝░░╚═══╝░╚═══██╗██╔══╝░░██╔══██╗██║░░╚██╗ oknardia.ru
███████╗░░░░░██████╔╝███████╗██║░░██║╚██████╔╝ cube2.ru
╚══════╝░░░░░╚═════╝░╚══════╝╚═╝░░╚═╝░╚═════╝░ venturebox.org
Сохраняем баннер Ctrl+O и Enter, а выходим из редактора Ctrl+X.
Раскрашиваем оболочку bash
Чтобы сделать красочно-разноцветным нашу командную строку, откроем на редактирование файл настроек оболочки bash пользователя .bashrc:
nano ~/.bashrc
находим там строку #force_color_prompt=yes раскомментируем её (и удаляем в ней #). И чтобы совсем отпад, находим блок:
if [ "$color_prompt" = yes ]; then
PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
else
PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '
fi
И меняем на блок
if [ "$color_prompt" = yes ]; then
PS1='${debian_chroot:+($debian_chroot)}\[\033[01;31m\]\u\[\033[01;34m\]@\[\033[01;31m\]\h\[\033[00m\]:\[\033[00;34m\]\w\[\033[00m\]\>
else
PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '
fi
Всё! Перелогиниваемся чтобы настройки подействовали.
logout
3. Настраиваем службу времени (необязательно)
Устанавливаем службу точного времени nlp:
apt-get install ntp
Откроем на редактирование конфигурационный файл /etc/ntp.conf:
sudo nano /etc/ntp.conf
Заменяем буржуйские адреса серверов точного времени на отечественные:
# Specify one or more NTP servers.
# Use servers from the NTP Pool Project. Approved by Ubuntu Technical Board
# on 2011-02-08 (LP: #104525). See http://www.pool.ntp.org/join.html for
# more information.
pool ntp.msk-ix.ru iburst prefer
pool 194.190.168.1 iburst
pool 2001:6d0:ffd4::1
# pool ntp.ix.ru
# pool 1.ubuntu.pool.ntp.org iburst
# pool 2.ubuntu.pool.ntp.org iburst
# pool 3.ubuntu.pool.ntp.org iburst
# Use Ubuntu's ntp server as a fallback.
pool ntp.msk-ix.ru
Сохраняем баннер Ctrl+O и Enter, а выходим из редактора Ctrl+X.
Чтобы настройки подействовали сервис точного времени нужно перезапустить:
sudo service ntp restart
Проверим, что сервис корректно перезапустился:
sudo service ntp status
Увидим, что все ок:
● ntp.service - Network Time Service
Loaded: loaded (/lib/systemd/system/ntp.service; enabled; vendor preset: enabled)
Active: active (running) since Wed 2022-05-25 01:01:24 MSK; 2 days ago
Docs: man:ntpd(8)
Main PID: 642 (ntpd)
Tasks: 2 (limit: 1066)
Memory: 1.5M
CGroup: /system.slice/ntp.service
└─642 /usr/sbin/ntpd -p /var/run/ntpd.pid -g -u 112:119
Проверить какой сервер точного времени ближе, задержки между серверами и т.п.:
ntpq -p
Увилим что-то типа:
remote refid st t when poll reach delay offset jitter
==============================================================================
ntp.msk-ix.ru .POOL. 16 p - 64 0 0.000 0.000 0.000
194.190.168.1 .POOL. 16 p - 64 0 0.000 0.000 0.000
2001:6d0:ffd4:: .POOL. 16 p - 64 0 0.000 0.000 0.000
ntp.ix.ru .POOL. 16 p - 64 0 0.000 0.000 0.000
*ntp.ix.ru .GPS. 1 u 450 1024 377 2.442 -0.254 0.117
4. Настраиваем бренмауэр для использования только с допустимыми внешними интерфейсами (защита портов)
Устанавливаем iptables для управления IP-соединения и iptables-persistent для сохранения конфигураций настроенных соединений и их автоматического подключения после перегрузке компьютера.
sudo -S apt-get install iptables
Далее создадим в домашней папке bash-скрипт prepare-iptable.sh:
nano ~/prepare-iptable.sh
...и вставим в него нижеследующий текст (исправьте если необходимо, следуя рекомендациям):
#!/bin/bash
# You have to set the rules of your firewall on your server only with the
# services used outside the VM.
# Вы должны установить правила брандмауэра на своем сервере только
# с сервисами, используемыми вне виртуальной машины.
echo "Сетевые настройки: разрешения трафика и портов";
echo "";
echo "ЭТОТ СКРИПТ НУЖНО ЗАПУСКАТЬ С ПРАВАМИ АДМИНИСТРАТОРА (ИЗ ПОД SUDO).";
echo "ОБАЗАТЕЛЬНО ИЗ KVM-КОНСОЛИ! ИЗ ПОД SSH МОЖЕТ СЛОМАТЬ ВАШУ ВИРТАЛКУ!";
echo "===================================================================";
echo "";
read -p "Хотите чтобы скрипт сделал это (возможно, и сломает)? (Y/N):" -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]
then
exit 1
fi
# Установим пакет iptables (если он уже установлен, попытка повторной установки "проскочит"
sudo -S apt-get install iptables
# ПРИСВАИВАЕМ ПЕРМЕННЫЕ:
# $IPT = "/usr/sbin/iptables"
# $WAN = текущий внешний сетевой интерфейс виртуалки
# $WAN_IP = текущий IP V4 назначенный на внешний сетевой интерфейс виртуалки
# $WAN_IP6 = текущий IP V6 назначенный на внешний сетевой интерфейс виртуалки
export IPT="$(sudo -S which iptables)"
export WAN="$(ip add | grep 'BROADCAST' | awk '{print $2}' | cut -d ':' -f 1)"
export WAN_IP="$(ip ad | grep 'inet ' | awk '(NR == 2)' | awk '{print $2}' | cut -d '/' -f 1)"
export WAN_IP6="$(ip ad | grep 'inet6 ' | awk '(NR == 2)' | awk '{print $2}' | cut -d '/' -f 1)"
echo "-------------------ТЕКУЩИЕ ПРАВИЛА--------------------";
$IPT -L -v -n
# СБРАСЫВАЕМ старые правила:
$IPT -F
$IPT -X
# БАЗОВЫЕ правила (политика по умолчанию) -- все обрубаем!
$IPT -P INPUT DROP
$IPT -P OUTPUT DROP
$IPT -P FORWARD DROP
# Разрешаем локальный траффик для loopback (для localhost)
$IPT -A INPUT -i lo -j ACCEPT
$IPT -A OUTPUT -o lo -j ACCEPT
# Разрешаем пинги
# $IPT -A INPUT -p icmp --icmp-type echo-reply -j ACCEPT
# $IPT -A INPUT -p icmp --icmp-type destination-unreachable -j ACCEPT
# $IPT -A INPUT -p icmp --icmp-type time-exceeded -j ACCEPT
# $IPT -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
# Разрешаем исходящие соединения с самого сервера
$IPT -A OUTPUT -o $WAN -j ACCEPT
# Состояние ESTABLISHED говорит о том, что это не первый пакет в соединении.
# Пропускать все уже инициированные соединения, а также дочерние от них.
# Так мы разрешим использование текущего порта на который настроен и
# открыт, в настощий момент, SSH а еще доступ к репозиториям для получения
# новых пакетов и их обновлений.
$IPT -A INPUT -p all -m state --state ESTABLISHED,RELATED -j ACCEPT
# Разрешить новые, а так же уже инициированные и их дочерние соединения
$IPT -A OUTPUT -p all -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
# Разрешить форвардинг для уже инициированных и их дочерних соединений
$IPT -A FORWARD -p all -m state --state ESTABLISHED,RELATED -j ACCEPT
# Включаем фрагментацию пакетов. Необходимо из-за разных значений MTU
$IPT -I FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
# Отбрасывать все пакеты, которые не могут быть идентифицированы
# и поэтому не могут иметь определенного статуса.
$IPT -A INPUT -m state --state INVALID -j DROP
$IPT -A FORWARD -m state --state INVALID -j DROP
# Приводит к связыванию системных ресурсов, так что реальный
# обмен данными становится не возможным, обрубаем
$IPT -A INPUT -p tcp ! --syn -m state --state NEW -j DROP
$IPT -A OUTPUT -p tcp ! --syn -m state --state NEW -j DROP
# Открываем только нужные порты на вход:
# !!! указать свой порт, который вы указали для SSH ранее !!!)
$IPT -A INPUT -i $WAN -p tcp --dport 2002 -j ACCEPT
# порт для web сервера (для http)
$IPT -A INPUT -i $WAN -p tcp --dport 80 -j ACCEPT
# порт для web сервера (для https)
$IPT -A INPUT -i $WAN -p tcp --dport 443 -j ACCEPT
## Логирование
## Все что не разрешено, но ломится отправим в цепочку undef
# $IPT -N undef_in
# $IPT -N undef_out
# $IPT -N undef_fw
# $IPT -A INPUT -j undef_in
# $IPT -A OUTPUT -j undef_out
# $IPT -A FORWARD -j undef_fw
# Логируем все из undef
# $IPT -A undef_in -j LOG --log-level info --log-prefix "-- IN -- DROP "
# $IPT -A undef_in -j DROP
# $IPT -A undef_out -j LOG --log-level info --log-prefix "-- OUT -- DROP "
# $IPT -A undef_out -j DROP
# $IPT -A undef_fw -j LOG --log-level info --log-prefix "-- FW -- DROP "
# $IPT -A undef_fw -j DROP
# Записываем правила
$IPT-save > $IPT.rules
# Выводим правила на экран:
echo "----------ПРАВИЛА ДЛЯ TCP-ПОРТОВ УСТАНОВЛЕНЫ----------";
cat $IPT.rules
echo "---------------------И ПРИМЕНЕНЫ----------------------";
$IPT -L -v -n
echo "------------------------------------------------------";
echo "";
echo "Правила сохранены в файле: $IPT.rules";
echo "";
echo "Для восстановления правил запустите скрипт повторно или";
echo "исполните команду:";
echo "";
echo "sudo $IPT-restore < $IPT.rules";
echo "";
echo "";
echo " _._ _,-'\"\"\`-._";
echo "(,-.\`._,'( |\\\`-/|";
echo " \`-.-' \\ )-\`( , o o)";
echo " \`- \\\`_\`\"'- Mi-mi-mi... Ok!";
echo "";
Сохраняем скрипт Ctrl+O и Enter, а выходим из редактора Ctrl+X.
Далее нужно зайти на вирталку через KVM-консоль и выполнить:
sudo bash ~/prepare-iptable.sh
После выполнения скрипта все внешние соединения с виртуалкой будут разорваны. После перелогирования через ssh можно будет увидеть, что новые настройки сетевой фильтрации вступили в силу:
sudo iptables -L -v -n
Увидим примерно следующее:
Chain INPUT (policy DROP 150 packets, 5768 bytes)
pkts bytes target prot opt in out source destination
28 2204 ACCEPT all -- lo * 0.0.0.0/0 0.0.0.0/0
81 7202 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
2 84 DROP all -- * * 0.0.0.0/0 0.0.0.0/0 state INVALID
8 608 DROP tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp flags:!0x17/0x02 state NEW
1 52 ACCEPT tcp -- eth0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:2002
0 0 ACCEPT tcp -- eth0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:80
0 0 ACCEPT tcp -- eth0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:443
Chain FORWARD (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
0 0 TCPMSS tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp flags:0x06/0x02 TCPMSS clamp to PMTU
0 0 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
0 0 DROP all -- * * 0.0.0.0/0 0.0.0.0/0 state INVALID
Chain OUTPUT (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
28 2204 ACCEPT all -- * lo 0.0.0.0/0 0.0.0.0/0
69 10113 ACCEPT all -- * eth0 0.0.0.0/0 0.0.0.0/0
0 0 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 state NEW,RELATED,ESTABLISHED
0 0 DROP tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp flags:!0x17/0x02 state NEW
Чтобы сохранить настройки и чтобы они автоматически вступали в силу в
случае перезагрузки установим пакет iptables-persistent:
sudo -S apt-get install iptables-persistent
Будет запрошено сохранить ли и восстанавливать настройки в случае
перезагрузки для IP-V4 и IP-V6 -- оба раза отвечаем Y.
В будущем, если будут меняться правила фильтрации, то сохранить sudo netfilter-persistent save, восстановить sudo netfilter-persistent start. Для детальных разъяснений см. по
ссылке.
5. Установиv защиту DoS (брутфорса) по ssh
DoS и DDoS-атака -- это агрессивное внешнее воздействие на сервер, проводимое с целью перегрузить его запросами, доведения его до отказа или брутфорс-взлома (brute force -- грубая сила, например, подбор паролей перебором и т.п.).
Если атака проводится с одиночного компьютера -- ее называют DoS (Denial of Service), если с нескольких, распределенных в сети, компьютеров — DDoS (Distributed Denial of Service).
Защиту от DoS (включая медленные атаки) может обеспечить пакет fail2ban.
Установим его (уже должен быть установлен):
sudo apt-get install fail2ban
Для его настройки перепишем конфигурационный файл /etc/fail2ban/jail.local:
sudo nano /etc/fail2ban/jail.local
И поместим туда следующее:
# == новый конфиг /etc/fail2ban/jail.local =====================
[DEFAULT]
#email, на который присылать уведомления
destemail = root
# подключить прафила бана из '/etc/fail2ban/action.d/iptables-multiport.conf'
banaction = iptables-multiport
# исключаем из потенциального бана ip машины с которых можем подключаться
ignoreip = <trusted_ip_1> <trusted_ip_2> <trusted_ip_3> <trusted_ip_4>
#### правила для SSH ####
[sshd]
enabled = true
port = ssh,2002
# filter — подключить правила фильтрации из '/etc/fail2ban/filter.d/sshd.conf'
filter = sshd
# logpath — какой лог наблюдаем (на тот случай, если он не по умолчанию)
logpath = /var/log/auth.log
# bantime — время (секунды) на которое баним. На неделю — 60*60*24*7=604800
bantime = 604800
# maxretry — число попыток (1) и получаешь бан!
maxretry = 1
# findtime — определяет длительность интервала в секундах, за которое
# событие должно повториться определённое количество раз, после чего санкции
# вступят в силу. Если специально не определить этот параметр, то будет
# установлено значение по умолчанию равное 600 (10 минут). Проблема в том,
# что ботнеты, участвующие в «медленном брутфорсе», умеют обманывать
# стандартное значение. Иначе говоря, при maxretry равным 6,
# атакующий может проверить 5 паролей, затем выждать 10 минут,
# проверить ещё 5 паролей, повторять это снова и снова, и его IP забанен
# не будет. В целом, это не угроза, но всё же лучше банить таких ботов
findtime = 7200
# СТАРЫЙ КОНФИГ ПО УМОЛЧАНИЮ
# [DEFAULT]
# bantime = 600
# findtime = 60
# maxretry = 6
# banaction = iptables-multiport
# [sshd]
# enabled = true
Сохраняем конфигурационный файл Ctrl+O и Enter, а выходим из редактора Ctrl+X.
Перезапустим fail2ban:
sudo service fail2ban restart
Проверим статус:
sudo service fail2ban status
Увидим, что все работает:
● fail2ban.service - Fail2Ban Service
Loaded: loaded (/lib/systemd/system/fail2ban.service; enabled; vendor preset: enabled)
Active: active (running) since Tue 2022-05-17 14:33:22 MSK; 1h 53min ago
Docs: man:fail2ban(1)
Process: 7635 ExecStartPre=/bin/mkdir -p /run/fail2ban (code=exited, status=0/SUCCESS)
Main PID: 7640 (f2b/server)
Tasks: 5 (limit: 1066)
Memory: 11.0M
CGroup: /system.slice/fail2ban.service
└─7640 /usr/bin/python3 /usr/bin/fail2ban-server -xf start
May 17 14:33:22 vm2203242538 systemd[1]: Starting Fail2Ban Service...
May 17 14:33:22 vm2203242538 systemd[1]: Started Fail2Ban Service.
May 17 14:33:22 vm2203242538 fail2ban-server[7640]: Server ready
Включаем автозапуск fail2ban при заугрузке системы:
sudo systemctl enable fail2ban.service
5. Установка и настройка СУБД (MariaDB), создание пользователей
Следуем инструкциям, и у нас получится примерно такой порядок действий:
Установка
Устанавливаем сервер MariaDB (полный аналог MySQL, но без патронажа Oracle) и пакет MariaDB-клиента для разработчиков (чтобы после корректно установился MySQL-коннектор для Python):
sudo apt install mariadb-server libmysqlclient-dev
Отредактируем конфигурационный файл, чтобы сменить кодовые таблицы в будущих базах с utf8mb4 (со всякими глупыми
эможи) на православную utf8:
sudo nano /etc/mysql/mariadb.conf.d/50-server.cnf
Найдём в конфигурационном файле строки:
character-set-server = utf8mb4
collation-server = utf8mb4_general_ci
и заменим на:
character-set-server = utf8
collation-server = utf8_general_ci
Сохраняем конфигурационный файл Ctrl+O и Enter, а выходим из редактора Ctrl+X.
Перезапустим систему управления базы данных:
sudo service mysql restart
Проверим статус:
sudo service mysql status
Если все сделали правильно, должны увидеть что-то типа:
● mariadb.service - MariaDB 10.6.7 database server
Loaded: loaded (/lib/systemd/system/mariadb.service; enabled; vendor preset: enabled)
Active: active (running) since Tue 2022-08-09 09:25:26 MSK; 3 days ago
Docs: man:mariadbd(8)
https://mariadb.com/kb/en/library/systemd/
Main PID: 1249 (mariadbd)
Status: "Taking your SQL requests now..."
Tasks: 9 (limit: 935)
Memory: 82.5M
CPU: 13min 42.376s
CGroup: /system.slice/mariadb.service
└─1249 /usr/sbin/mariadbd
Создание пользователей
Для этого запустим mysql с супер-правами root:
sudo mysql
Создаём пользователя <ssh_user>, зададим ему пароль и дадим привилегии на все:
CREATE USER '<ssh_user>'@'localhost' IDENTIFIED BY '*********************';
GRANT ALL PRIVILEGES ON *.* TO '<ssh_user>'@'localhost';
Создаем базу данных django_cadpoint для нашего сайта:
CREATE DATABASE django_cadpoint DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;
И создадим пользователя cadpint, пароль для него и дадим ему права работать только с базой сайта:
CREATE USER 'cadpint'@'localhost' IDENTIFIED BY '*******';
GRANT ALL PRIVILEGES ON django_cadpoint.* TO 'cadpint'@'localhost';
Проверим, что установлена правильная часовая зона времени:
SHOW VARIABLES LIKE '%time_zone%';
Типа, она должна быть MSK:
+------------------+--------+
| Variable_name | Value |
+------------------+--------+
| system_time_zone | MSK |
| time_zone | SYSTEM |
+------------------+--------+
2 rows in set (0.001 sec)
Выходим из MariaDB:
quit;
переносим базу
6. ПОДГОТОВКА WEB-СЕРВЕРА NGINX
Устанавливаем nginx
sudo apt-get install nginx
На всякий случай (как выяснилось позже), лучше поставить nginx plus. В нем есть динамические модули. И один их таких динамических модулей -- geoip -- может понадобиться для ограничения посещения сайта только пользователями России. Смотрим инструкцию по установке nginx plus.
Убедиться, что он запущен и работает корректно можно командой:
sudo service nginx status
Результат должен быть примерно таким:
● nginx.service - A high performance web server and a reverse proxy server
Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
Active: active (running) since Thu 2022-01-20 18:45:16 MSK; 56s ago
Docs: man:nginx(8)
Main PID: 2200 (nginx)
Tasks: 2 (limit: 1037)
Memory: 4.6M
CGroup: /system.slice/nginx.service
├─2200 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
└─2201 nginx: worker process
Зайдем по ip нашего сервера или через localhost:
curl -I http://localhost/
Получим ответ:
HTTP/1.1 200 OK
Server: nginx/1.18.0 (Ubuntu)
Date: Tue, 03 May 2022 18:16:46 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 03 May 2022 12:49:44 GMT
Connection: keep-alive
Vary: Accept-Encoding
ETag: "627124e8-264"
Accept-Ranges: bytes
Настройка GZIP
По умолчанию модуль GZIP установлен в NGINX. Он осуществляет сжатие данных «на лету», они отправляются nginx, и, после получения, распаковываются браузерами (само-собой теми, которые поддерживают такую возможность). При этом между веб-сервером и браузером передается меньшее данных, ускоряя тем самым . Сжатие использует ресурсы сервера, поэтому лучше всего сжимать только те файлы, которые хорощо «сжимаютсяу» (а еще лучще, есди еще и могут кэшироваться на стороне браузера). Текстовые файлы сжимаются хорошо, JPEG или PNG уже сжаты по своей природе и большого результата при сжатии GZIP можно не ожидать.
Настроим модуль GZIP в NGINX. Для этого открываем на редактирование
конфигурационный файл nginx /etc/nginx/nginx.conf:
sudo nano /etc/nginx/nginx.conf
Находим в нем кусочек касающийся GZIP:
##
# Gzip Settings
##
и пишем в нем следующее (там будет закомментированный блок, можно использовать его):
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_disable "msie6";
gzip_vary on;
gzip_min_length 512;
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript application/vnd.ms-fontobject application/x-font-ttf font/opentype image/svg+xml image/x-icon;
Если интересно, расшифруем что тут происходит:
- gzip_proxied any - сжимать данные ответов для proxy-серверов.
- gzip_comp_level 6 - устанавливаем, степень сжатия файлов. Чем выше число, тем выше уровень сжатия и использование ресурсов. уровень сжатия, 1
- минимальное, 9 - максимальное.
- gzip_buffers 16 8k - задаёт число и размер буферов, в которые будет сжиматься ответ. По умолчанию размер одного буфера равен размеру страницы. В зависимости от платформы это или 4K, или 8K.
- gzip_http_version 1.1 - директива используется для ограничения сжатия gzip для браузеров, поддерживающих протокол HTTP/1.1. Если браузер не поддерживает его, вероятно, что он не поддерживает и gzip.
- gzip_disable "msie6" - исключаем IE6 из браузеров, которые будут получать сжатые файлы (этот древний браузер не поддерживает GZIP).
- gzip_vary on - включает добавление в ответ заголовка "Vary: Accept-Encoding" (для IE4-6 это приведёт к не кешированию данных из-за бага).
- gzip_min_length 512 - сообщаем NGINX не сжимать файлы размером менее 512 байт.
- gzip_types - отображает все типы MIME, которые будут сжаты. В этом случае список включает страницы HTML, таблицы стилей CSS, файлы Javascript и JSON, файлы XML, иконки (BMP-изображения очень даже сжимаются), изображения SVG и веб-шрифты.
Ещё в этом же /etc/nginx/nginx.conf нужно заменить дерективу user www-data; на user root; (в самой первой
строчке... почему-то на Ubuntu 2022.04 по другому не работает uwsgi... похоже не может получить доступ к сокету...
странно...)
Сохраняем конфигурационый файл Ctrl+O и Enter, а выходим из редактора
Ctrl+X и перезагружаем nginx:
sudo service nginx restart
Проверка новой конфигурации
Выполним тестовый запрос:
curl -H "Accept-Encoding: gzip" -I http://localhost/
Мы получим ответ:
HTTP/1.1 200 OK
Server: nginx/1.18.0 (Ubuntu)
Date: Tue, 03 May 2022 18:16:53 GMT
Content-Type: text/html
Last-Modified: Tue, 03 May 2022 12:49:44 GMT
Connection: keep-alive
Vary: Accept-Encoding
ETag: W/"627124e8-264"
Content-Encoding: gzip
Как видим, сжатие включилось.
7. Развёртывание окружения проекта
Настройка виртуального окружения проекта
Установим python с набором для разработчиков (для сборки коннектора к сСУБД), пакетный менеджер и утилиту для создания виртуального окружения python:
sudo apt-get install python3-pip python3-virtualenv python3-dev
Проверим, что установлена нужная нам версия Python (нам нужно Python 3.8.10):
python3 -V
Теперь создадим папку для нашего сайта ~/cadpoint и развернём в ней
виртуальное окружение, указав, что в нем нужно использовать версию Python
3.7 /usr/bin/python3.7. Будет создан каталог, с файлами виртуального
окружение (версия Python, установщик пакетов pip, wheel, setuptools а, в
будущем, и все пакеты, батарейки, свистелки и хрюкалки нашего проекта).
cd $HOME
mkdir -p cadpoint
Чтобы для нашего проекта "заморозить" версию Python и все необходимые пакеты, и изьежать возможного кофликта при обновлении системного Python или с пакетвми установленными в других проектвх создадим виртуальное окружение в папке нашего сайта ($HOME/cadpoint):
virtualenv -p python3 $HOME/cadpoint/env
Активируем созданное виртуальное окружение:
source $HOME/cadpoint/env/bin/activate
Проверить, что теперь мы работаем в виртуальном окружении можно дав команды:
python -V
pip -V
Увидим
pip 20.0.2 from /home/<ssh_user>/cadpoint/env/lib/python3.8/site-packages/pip (python 3.8)
Можно обновить менеджер пакетов pip по последней версии (сперва получим его с помощью curl в папку tmp, а после запустим установщик через Python)
curl https://bootstrap.pypa.io/get-pip.py > ~/tmp/get-pip.py
python3 ~/tmp/get-pip.py
Попробуем снова
pip -V
Увидим
pip 22.0.4 from /home/<ssh_user>/cadpoint/env/lib/python3.8/site-packages/pip (python 3.8)
ФУУ!!
8. Установка пакетов необходимых проекту
Точный состав пакетов, обычно, находится в файле requarement_dev_prod_dreamhost.txt. Но на всякий случай приведем список пакетов здесь (он может отличаться от действительно актуального, в файле) т.к., на самом деле, большинство пакетов будут установлены автоматически как зависимости:
| Пакет | Версия | Назначение | Зависимости |
|---|---|---|---|
| django | 3.2.15 | Фреймворк Django | притащит с собой пакеты: asgiref, pytz и sqlparse |
| mysqlclient | 2.1.1 | Коннектор MySQL | нет |
| django-filer | 2.2.2 | Система управления медиа-файлами с фишками подготовки ресайз-картинок, превьюшек и прочими плюшками | притащит с собой пакеты: Unidecode, django-js-asset, django-mptt, django-polymorphic, easy-thumbnails и pillow |
| django-ckeditor | 6.4.2 | Wysiwyg-редактор (ckeditor) для админки | нет |
| django-taggit | 3.0.0 | Ситема управления тегами | нет |
| pytils-safe | 0.3.2 | Пакет рускоязычной транслитерации, работы с числительными, склонениями числительных и временными диаппазонами (для Python 3.x) | нет |
| urllib3 | 1.26.11 | пакет для работы с web-запросами (проекту этот пакет нужен для работы с API внешний HTML-типографов) | нет |
| django-ckeditor-filebrowser-filer | 0.3.0 | Плугин для дружбы Wysiwyg-редквтора (ckeditor) и django-filer | нет, все зависимости уже притащил django-filer |
Все эти пакеты устанавливаются в виртуальное окружение с помощью пакетного
менеджера pip в последовательности:
pip install Django==3.2.15
pip install mysqlclient==2.1.1
pip install django-filer==2.2.2
pip install django-ckeditor==6.4.2
pip install django-taggit==3.0.0
pip install django-ckeditor-filebrowser-filer
pip install pytils-safe==0.3.2
pip install urllib3==1.26.11
Разворачиваем и тестируем проект
Создаём папки для хранения сокета и логов:
mkdir -p $HOME/cadpoint/logs
mkdir -p $HOME/cadpoint/socket
Переносим проект... например на тест-деплоя z7 (или на на бочем проекте мастерхост) архивируем проект. Само-cобой это надо делать там, где проект находится, не на вирталке, а dev-серере (или или там находится наш проект). Например, так:
zip -9 -r cadpoint.zip public/ rsvo_new/ config/
Копируем архив по ssh на нашу виртуалку (masterhost или nic.ru)
scp -P 2002 cadpoint.zip <ssh_user>@<server_ip>:~/<project_root>
Возвращаемся на нашу виртуалку хостинга и разархивируем:
cd ~/cadpoint
unzip cadpoint.zip
Внимание, на разных серверах расположение папок проекта может отличаться. При архивации илм после распаковки, возможно, нам потребуется переместить некоторые папки. Мы должны получить следующую структуру проекта:
+---public
¦ +---media
¦ L---static
+---rsvo_new
¦ +---rsvo_new
¦ +---templates
¦ L---web
+---logs
+---config
+---env
L---socket
Папки logs, config, env и socket на данном этапе могут отсутствовать. Мы создадим их позже:
Еще важно, если у нас установилось Django 4 (а изначально проект создавался для Django 3.2.х) то нам надо сделать небольшие изменения в коде.
В файле проекта urls.py (он должен быть расположен тут: /home/<ssh_user>/cadpoint/rsvo_new/rsvo_new/urls.py)
из-за изменения расположения методов в библиотеках django следует закоменить строчку:
from django.conf.urls import url, include
И добавить после нее:
from django.conf.urls import include
from django.urls import re_path as url
должно получиться следующее:
# from django.conf.urls import url, include
from django.conf.urls import include
from django.urls import re_path as url
Подобные изменения следует сделать так же в файле urls.py батарейки ckeditor_filebrowser_filer
/home/<ssh_user>/cadpoint/env/lib/python3.8/site-packages/ckeditor_filebrowser_filer/urls.py. Вместо:
from django.conf.urls import url
Следует написать:
from django.urls import re_path as url
должно получиться:
# from django.conf.urls import url
from django.urls import re_path as url
Теперь можно произвести перенос статических файлов админки и батареек в папку для web-статики:
source ~/cadpoint/env/bin/activate
cd ~/cadpoint/rsvo_new
python manage.py collectstatic
Теперь произведем подготовку нашей базы под проект. Для этого произведем миграции:
python manage.py makemigrations
python manage.py migrate
Миграция создаст все необходимые таблицы и заполнит таблицу миграций django_cadpoint.django_migration.
Теперь можно произвести перенос базы с dev-проекта (или с другого рабочего сервера) в базу нашей виртуалки.
Следует учесть, что переносить таблицу django_cadpoint.django_migration не следует (мы произвели чистую миграцию, и
если мы перезапишем эту таблицу, то с высокой вероятностью сломаем наш проект).
Настало время проверить, что наше web-приложение Django работает.
Временно откроем порт 8080 через iptables:
sudo iptables -A INPUT -i eth0 -p tcp --dport 8080 -j ACCEPT
Запустим приложение с dev-режиме на нашем IP и этом порту:
python manage.py runserver <server_ip>:8080
Если мы обратимся из браузера по адресу http://<server_ip>:8080, то увидим как на нашей виртуалке "бежит лог". В браузере будет отображаться что-то похожее на наш проект (с тем отличием, что не будет работать статика... т.е. мы не увидим картинок, не будут подгружены стили, JavaScript и все такое).
Завершаем работу web-сервера разработчика, нажав Control+C.
8. Конфигурируем nginx под наш проект
Создаем и правим конфиг /cadpoint/config/cadpoint.conf:
nano /cadpoint/config/cadpoint.conf
Помещаем в него следующее:
# Разработка сайта CADPOINT.RU
# == Конфикурационный файл nginx cadpoint.conf
# Описываем апстрим-потоки которые должен подключить Nginx
# Для каждого сайта надо настроить свйо поток, со своим уникальным именем.
# Если будете настраивать несколько python (django) сайтов - измените название upstream
upstream cadpoint-django {
# расположение файла Unix-сокет для взаимодействие с uwsgi
server unix:///home/<ssh_user>/cadpoint/socket/cadpoint.sock;
# /home/<ssh_user>/cadpoint/socket/cadpoint.sock;
# также можно использовать веб-сокет (порт) для взаимодействие с uwsgi. Но это медленнее
# server 127.0.0.1:8001; # для взаимодействия с uwsgi через веб-порт
keepalive_requests 200;
}
# конфигурируем сервер
server {
# server_name <server_ip>; # доменное имя сайта
server_name cadpoint.ru; # доменное имя сайта
listen 80;
charset utf-8; # кодировка по умолчанию
access_log /home/<ssh_user>/cadpoint/logs/cadpoint-access.log; # логи с доступом
error_log /home/<ssh_user>/cadpoint/logs/cadpoint-error.log; # логи с ошибками
client_max_body_size 100M; # максимальный объем файла для загрузки на сайт (max upload size)
error_page 404 /404.html;
error_page 500 /500.html;
location /media { alias /home/<ssh_user>/cadpoint/public/media; } # Расположение media-файлов Django
location /static { alias /home/<ssh_user>/cadpoint/public/static; } # Расположение static-файлов Django
location /robots.txt { root /home/<ssh_user>/cadpoint/public; } # Расположение robots.txt
location /favicon.ico { root /home/<ssh_user>/cadpoint/public; } # Расположение favicon.ico
location /favicon.gif { root /home/<ssh_user>/cadpoint/public; } # Расположение favicon
location /favicon.png { root /home/<ssh_user>/cadpoint/public; } # Расположение favicon
location /favicon.svg { root /home/<ssh_user>/cadpoint/public; } # Расположение favicon
location /author.txt { root /home/<ssh_user>/cadpoint/public; } # Расположение author.txt
location = /404.html {
root /home/<ssh_user>/cadpoint/cadpoint/templates/404.html;
internal;
}
location = /500.html {
root /home/<ssh_user>/cadpoint/cadpoint/templates/500.html;
internal;
}
# location ~ \.(xml|html|htm)$
location ~ \.(html|htm|ico|svg|png|gif|jpg|jpeg)$ {
root /home/<ssh_user>/cadpoint/public; # Расположение статичных *.xml, *.html и *.txt
}
location / {
uwsgi_pass cadpoint-django; # upstream обрабатывающий обращений
include uwsgi_params; # конфигурационный файл uwsgi;
proxy_set_header Host $host;
# ограничение количества запросов c одного IP-адреса с помощью модуля Limit_Req_Module
# limit_req zone=one burst=20 nodelay;
# one — имя зоны настроеной в /etc/nginx/nginx.conf (для всех сайтов сервера) в блоке http {…}
# burst — максимальный всплеск активности, можно регулировать до какого значения запросов
# в секунду может быть всплеск запросов;
# nodelay — незамедлительно, при достижении лимита подключений, выдавать код 503
# (Service Unavailable) для этого IP
fastcgi_keep_conn on;
uwsgi_read_timeout 1800; # вдруг некоторые запросы очень долго обрабатываются?
uwsgi_send_timeout 200; # на всякий случай время записи в сокет побольше...
}
}
# переадресация с www на "без" www
server {
server_name www.cadpoint.ru;
listen 80;
return 301 http://cadpoint.ru$request_uri;
}
Делаем симлинк этого конфигурационного файла в папку конфигов сайтов nginx:
sudo ln -s ~/cadpoint/config/cadpoint.conf /etc/nginx/sites-enabled/
Протестируем конфигурацию:
sudo nginx -t
Если все ок, можем "мягко" перезапустить nginx:
sudo nginx -s reload
Или "по-жёсткому":
sudo service nginx restart
Теперь если мы из браузера обратимся по адресу http://cadpoint.ru/robots.txt, http://cadpoint.ru/favicon.ico, http://2cadpoint.ru/favicon.png или http://cadpointu/favicon.svg то увидим соответсвующий контент.
9. НАСТРОЙКА uWSGI
И uWSGI, и Python-плагин uWSGI уже должен быть установлен. Но если он не установлены, или для проверки, инсталляция производится из так:
sudo apt-get install uwsgi uwsgi-plugins-all
Проверим, что uWSGI работает:
sudo service uwsgi status
Увидим примерно следующее:
● uwsgi.service - LSB: Start/stop uWSGI server instance(s)
Loaded: loaded (/etc/init.d/uwsgi; generated)
Active: active (exited) since Thu 2022-01-20 20:36:20 MSK; 2min 57s ago
Docs: man:systemd-sysv-generator(8)
Tasks: 0 (limit: 1037)
Memory: 0B
CGroup: /system.slice/uwsgi.service
Создаём и правим ini-конфиг ~/cadpoint/config/cadpoint.ini для uWSGI:
nano ~/cadpoint/config/cadpoint.conf
Помещаем туда следующее:
# === Конфикурационный файл uwsgi cadpoint.ini
[uwsgi]
# НАСТРОЙКИ ДЛЯ DJANGO
# Корневая папка проекта (полный путь)
chdir = /home/<ssh_user>/cadpoint/cadpoint
# Django wsgi файл cadpoint/wsgi.py записываем так:
module = cadpoint.wsgi
# полный путь к виртуальному окружению
home = /home/<ssh_user>/cadpoint/env
# полный путь к файлу сокета
socket = /home/<ssh_user>/cadpoint/socket/cadpoint.sock
# Исходящие сообщения в лог
daemonize = /home/<ssh_user>/cadpoint/logs/cadpoint_uwsgi.log
# ЗАГАДОЧНЫЕ НАСТРОЙКИ, ПО ИДЕЕ ОНИ НУЖНЫ, НО И БЕЗ НИХ ВСЁ РАБОТАЕТ
# расположение wsgi.py
wsgi-file = /home/<ssh_user>/cadpoint/cadpoint/cadpoint/wsgi.py
# расположение виртуального окружения (как оно работает если этот параметр не указан, не ясно)
virtualenv = /home/<ssh_user>/cadpoint/env
# имя файла при изменении которого происходит авторестарт приложения
# (когда этого параметра нет, то гичего не авторестартится, но с ним все рестартится.
# Cтоит изменить любой Python-исходник проекта, как изменения сразу вступают в силу.
touch-reload = /home/<ssh_user>/cadpoint/logs/cadpoint_reload
py-autoreload = 5
# НАСТРОЙКИ ОБЩИЕ
# быть master-процессом
master = true
# максимальное количество процессов
processes = 1
# если uWSGI устнаовлен как сервис через apt-get то нужно установить еще плугин:
# sudo apt-get install uwsgi-plugin-python
# и добавить в этот конфиг: plugin = python
plugin = python3
# права доступа к файлу сокета. По умолчанию должно хватать 664. Но каких-то прав не хватает, поэтому 666.
chmod-socket = 666
# очищать окружение от служебных файлов uwsgi по завершению
vacuum = true
# количество секунд после которых подвисший процес будет перезапущен
# Так как некоторе скрипты требуют изрядно времени (особенно полная переиндексация) то ставим значение побольще
harakiri = 2600
# В общем случае, при некотых значениях harakiri логах uWSGI может вываливаться предупреждение:
# WARNING: you have enabled harakiri without post buffering. Slow upload could be rejected on post-unbuffered webservers
# можно оставить harakiri закоментированным, но нам нужно 900 и на него не ругается. Ругается на 30.
# разрешаем многопоточность
enable-threads = true
vacuum = true
thunder-lock = true
max-requests = 500
# пользователь и группа пользователей от имени которых запускать uWSGI
# указываем www-data: к этой группе относится nginz, и ранее мы включили в эту группу нашего [user]
uid = root
gid = root
print = ---------------- Запущен uWSGI для cadpoint ----------------
Делаем симлинк этого конфигурационного файла в папку конфигов uwsgi:
sudo ln -s ~/cadpoint/config/cadpoint.ini /etc/uwsgi/apps-enabled/
Не забываем перезапустить uwsgi:
sudo service uwsgi restart
Еще раз проверим, что uWSGI работает:
sudo service uwsgi status
Все. Сайт развёрнут. Далее можно проводить улучшайзинг и усиливать защиту:
10. Нагрузочное тестирование (нужен dockers)
Нагрузочное тестирование будем проводить при помощи Яндекс.Танк. Он будет "обстреливать" наш сайт запросами.
Для запускать Яндекс.Танк проще всего использовать Dockers. Т.о. Dockers должен быть установлен на машину, с которой будем "обстреливать" сайт (и это не виртуалка хостинга... "обстреливать" самих себя бессмысленно).
Создаем каталог yandex.tank (в моем случае M:/VM/yandex.tank) и в нем помещаем файл load.yaml следующего
содержания (не забываем корректировать URL, если необходимо):
overload:
enabled: true
package: yandextank.plugins.DataUploader
token_file: "token.txt"
phantom:
address: 2022.rsvo.ru:80
header_http: "1.1"
headers:
- "[Host: 2022.rsvo.ru]"
- "[Connection: close]"
uris:
- /
- /about/
- /about/management
- /about/news
- /about/news/184-fgup-rsvo-prinyalo-uchastie-v-ucheniyah-mchs?p=0&n=5
- /about/about/news/186-uchebnyij-tsentr-fgup-rsvo-prinyal-uchastie-v-mero?p=1&n=2
- /about/news/132-gromkij-maks-2017?p=30&n=1
- /about/news/128-fgup-rsvo-prinyalo-uchastie-v-dne-innovatsij-mchs?p=29&n=2
- /wired-radio-broadcasting/moskva-abonentam-yuridicheskim-litsam
- /upac
- /integrated-security/solutions-for-industrial
- /integrated-security/safe-cities-solutions
- /sound-technical-support/
- /about/contacts
- /about/smi
- /about/nagradyi-i-blagodarnosti
load_profile:
load_type: rps
# schedule: line(5, 5000, 3m)
# schedule: const(1,30s) line(1,1000,2m) const(10000,5m)
schedule: line(10,5000,2m) const(100,1m)
ssl: true
autostop:
autostop:
- http(5xx,10%,5s)
console:
enabled: true
telegraf:
enabled: false
Так же создаем пустой файл token.txt в той же папке. ВНИМАНИЕ файл должен быть в кодировке ANSI (хоть он и пустой,
но это важно).
Теперь можем запустить Яндекс.Танк:
docker run --rm -v M:/VM/yandex.tank:/var/loadtest -it direvius/yandex-tank
11. Установка SSL Let's Encrypt (переход с http на https)
Хорошую инструкцию по установке Let's Encript: https://www.digitalocean. com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-ubuntu-22-04
Let’s Encrypt — это удостоверяющий центр сертификации (ЦС), который предоставляет доступный способ получения и установки бесплатных сертификатов TLS/SSL , тем самым обеспечивая шифрование HTTPS на веб-серверах. Let’s Encrypt предоставляет программный клиент Certbot, который пытается автоматизировать большинство (если не все) необходимые шаги установки сертификатов, настройки web-севера nginx (и Apache тоже) и периодическое обновления сертификатов.
Установка Certbot
Если на сервере ранее была установлена более старая версия certbot, следует удалить ее:
sudo apt remove certbot
Certbot рекомендует использовать для установки пакет моментальных снимков (снапшотов). Пакеты Snap работают почти со всеми дистрибутивами Linux, но для управления пакетами Snap требуется, чтобы вы сначала установили snapd. Ubuntu 22. 04 поставляется с поддержкой снапшотов «из коробки», поэтому нужно начать с того, что убедитесь, что ядро snapd обновлено:
sudo snap install core; sudo snap refresh core
После этого можно установить certbot:
sudo snap install --classic certbot
Наконец, свяжем certbot с командой создания снапшотов. Это не обязательно, но по умолчанию снимки обычно менее навязчивы, поэтому создают случайных конфликтов с какими-либо другими системными пакетами:
sudo ln -s /snap/bin/certbot /usr/bin/certbot
Теперь, Certbot установлен. Можно запустить его и получить наш сертификат.
Получение сертификата и тюнинг конфигурации Nginx
Certbot должен иметь возможность найти правильный блок server в конфигурации Nginx. В частности, он ищет
директиву server_name, соответствующую домену, для которого вы запрашиваете сертификат. В нашем случае, это
домен cadpoint.ru. В предыдущем пункте мы создали этот конфигурационный файл в каталоге
~/cadpoint/config/cadpoint.conf и связали его через симлинк с каталогом настроек nginx
/etc/nginx/sites-enabled/. Плагин Certbot Nginx позаботится о перенастройке этого конфигурационного файла и
перезагрузке nginx
Получаем сертификаты
sudo certbot --nginx -d cadpoint.ru -d www.cadpoint.ru
При выполнени будет предложено ввести адрес электронной почты и согласиться с условиями обслуживания. После этого вы должны увидеть сообщение о том, что процесс прошел успешно и где хранятся ваши сертификаты:
IMPORTANT NOTES:
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/cadpoint.ru/fullchain.pem
Key is saved at: /etc/letsencrypt/live/cadpoint.ru/privkey.pem
This certificate expires on 2022-11-01.
These files will be updated when the certificate renews.
Certbot has set up a scheduled task to automatically renew this certificate in the background.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
If you like Certbot, please consider supporting our work by:
* Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
* Donating to EFF: https://eff.org/donate-le
Серификат загружен, конфигурация nginx изменена и, даже, настроен редирект c http на https... В принципе на этом можно
закончить. Но будет не лишним добавить немного тюнинга. Certbot в конфиг nginx для нашего сайта подключает файл
/etc/letsencrypt/options-ssl-nginx.conf (он единый для nginx подключается в конфиги всех сайтов работающих по ssl
с сертификатом Let's Encrypt). Нужно внести изменения в него:
sudo nano /etc/letsencrypt/options-ssl-nginx.conf
В частности нам нужно изменить дерективы ssl_protocols, ssl_ciphers, resolver, keepalive_requests и
ssl_session_cache. В результате наш файл должен выглядеть так:
# This file contains important security parameters. If you modify this file
# manually, Certbot will be unable to automatically provide future security
# updates. Instead, Certbot will print and log an error message with a path to
# the up-to-date file that you will need to refer to when manually updating
# this file. Contents are based on https://ssl-config.mozilla.org
# ssl_session_cache shared:le_nginx_SSL:10m;
ssl_session_cache builtin:1000 shared:le_nginx_SSL:25m;
ssl_session_timeout 1440m;
ssl_session_tickets off;
# ssl_protocols SSLv2 TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
ssl_protocols SSLv2 SSLv3 TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
# ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384";
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';
resolver 77.88.8.8;
keepalive_requests 200;
Сохраняем конфигурационый файл Ctrl+O и Enter, а выходим из редактора Ctrl+X. И еще надо добавить поддержку
cnfylfhnf http2 (много поточная загрузка web-страниц). Откроем конфигурационный файл nginx для нашего сайта:
nano ~/cadpoint/config/cadpoint.conf
И добавим изменим директиву:
listen 443 ssl; # managed by Certbot
на директиву:
listen 443 ssl http2; # managed by Certbot
Перезагружаем nginx чтобы применились изменения:
sudo service nginx restart
12. Блокируем и баним зловредов (бот-сканеры и http-досеров)
Ограничения числа запросов в nginx (не обязательно, но вдруг)
Настроим nginx на ограничения числа запросов c одного IP-адреса с помощью модуля Limit Req Module.
Открываем файл /etc/nginx/nginx.conf (конфиг для всех сайтов на сервере):
sudo nano /etc/nginx/nginx.conf
И в блок http {…} добавляем строку:
http {
...
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
...
}
где:
- $binary_remote_addr — переменная Nginx содержащая IP с которого пришёл запрос;
- zone=one — имя зоны. Если настройка делается в нескольких vhost файлах, имена должны быть разные;
- 10m — размер зоны. 1m может содержать 16000 состояний, т.е. 16000 уникальных IP-адресов;
- rate=1r/s — разрешено 1 запрос в секунду. Так же можно указать количество запросов в минуту (30r/m — 30 запросов в минуту)
Затем открываем на редактирование конфигурационный файл nginx для нашего сайта:
nano ~/cadpoint/config/cadpoint.conf
И в блок server {…}, добавим строку:
limit_req zone=one burst=20 nodelay;
где:
- one — имя зоны настроеной в /etc/nginx/nginx.conf (для всех сайтов сервера) в блоке
http {…}; - burst — максимальный всплеск активности, можно регулировать до какого значения запросов
- в секунду может быть всплеск запросов;
- nodelay — незамедлительно, при достижении лимита подключений, выдавать код 503
- (Service Unavailable) для этого IP.
Строку limit_req zone=one burst=5 nodelay; можно добавить как непосредственно в блок server {…}, и тогда будет ограничиваться число запросов ко всем файлам сайта, так и в расположенные в нем блоки location … {…}. Целесообразнее ограничить число запросов к uwsgi_pass, т.к. он отвечает только за странички сайта (без статики... статика может быть запрощена клиентом довольна, т.к. одна страничка может содержать внутри себя много встроенных картинок, стилей и скриптов).
Таким образом наш блок location … {…} будет выглядеть так:
location / {
uwsgi_pass cadpoint-django; # upstream обрабатывающий обращений
include uwsgi_params; # конфигурационный файл uwsgi;
proxy_set_header Host $host;
limit_req zone=one burst=5 nodelay;
fastcgi_keep_conn on;
uwsgi_read_timeout 1800;
uwsgi_send_timeout 200;
}
}
Баним ботов и подозрительную активность
Настроим fail2ban для выявления ботов, которые ищут скрипты, дампы баз, логи, ключи и тому подобное, анализируя error-лог. Создаем конфиг-файл фильтра /etc/fail2ban/filter.d/nginx-noscript.conf:
sudo nano /etc/fail2ban/filter.d/nginx-noscript.conf
Со следующим содержанием:
[Definition]
failregex = .*client: <HOST>.*GET.*(\.php|\.asp|\.aspx|\.exe|\.pl|\.cgi|\.scgi|\.log|\.sql|\.jsp|\.csv|\.sh|\.key|\.py|\.pyc|\.asmx|\.asax)
# failregex = ^<HOST> -.*GET.*(\.php|\.asp|\.aspx|\.exe|\.pl|\.cgi|\.scgi|\.log|\.sql|\.jsp|\.csv|\.sh|\.key|\.py|\.pyc|\.asmx|\.asax)
ignoreregex =
Проверим, что фильтр написан верно:
fail2ban-regex ~/cadpoint/logs/cadpoint-error.log /etc/fail2ban/filter.d/nginx-noscript.conf
Создаем еще одни фильтр для выявления подозрительной активности (ищут адинки популярных cms, log-и, ключи и тому подобное) анализируя access лог /etc/fail2ban/filter.d/nginx-manual.conf:
sudo nano /etc/fail2ban/filter.d/nginx-manual.conf
со следующим содержанием:
[Definition]
failregex = ^<HOST> -.*GET.*wp-content/
^<HOST> -.*GET.*wp-admin/.*
^<HOST> -.*GET.*wp-includes/.*
^<HOST> -.*GET.*administrator/
^<HOST> -.*GET.*user/register/
^<HOST> -.*GET.*bitrix/admin/
^<HOST> -.*GET.*minify/
^<HOST> -.*GET.*(?:a|A)dmin/
^<HOST> -.*GET.*netcat/
^<HOST> -.*GET.*koobooCMS/
^<HOST> -.*GET.*apanel/
^<HOST> -.*GET.*netcat/
^<HOST> -.*GET*/\.git/config
^<HOST> -.*GET*/\.well-known/
^<HOST> -.*GET.*(\.sql|\.php5|\.mdb|\.db|\.yml|\.cgi|\.scgi|\.log|\.sql|\.jsp|\.csv|\.sh|\.key|\.py|\.pyc|\.asmx|\.asax)
ignoreregex =
Снова проверим, что фильтр написан верно:
fail2ban-regex ~/cadpoint/logs/cadpoint-access.log /etc/fail2ban/filter.d/nginx-manual.conf
Далее, редактируем файл /etc/fail2ban/jail.local для настройки параметров подключения и работы фильтра:
sudo nano /etc/fail2ban/jail.local
Дописываем строки:
# ФИЛЬТР nginx-noscript
[nginx-noscript]
enabled = true
filter = nginx-noscript
port = http,https
action = iptables-multiport[name=NoAuthFailures, port="http,https"]
logpath = /var/log/nginx/*error*.log
/home/<ssh_user>/cadpoint/logs/*error*.log
bantime = 86400
maxretry = 6
findtime = 7200
# ФИЛЬТР manual
[nginx-manual]
enabled = true
filter = nginx-manual
port = http,https
action = iptables-multiport[name=NoAuthFailures, port="http,https"]
logpath = /var/log/nginx/*access*.log
/home/<ssh_user>/cadpoint/logs/*access*.log
bantime = 86400
maxretry = 6
findtime = 7200
Перезапустим fail2ban:
sudo service fail2ban restart
Чтобы посмотреть информацию по заблокированным ip по нашему фильтру используем команду:
sudo fail2ban-client status nginx-noscript
sudo fail2ban-client status nginx-manual
Чтобы разбанить IP (например 8.8.8.8) можно воспользоваться командой:
sudo fail2ban-client set nginx-noscript unbanip 8.8.8.8
13. Ротация логов
Обычно процесс ротации логов в системе уже установлен и работает. Но на всякий случай установить его можно так:
sudo apt-get install logrotate
Для настройки ротации логов нашего сайта нужно отредактировать конфигурационный файл ротации для nginx /etc/logrotate.d/nginx
sudo nano /etc/logrotate.d/nginx
И добавить в него (в конце) следующее:
/home/<ssh_user>/cadpoint/logs/*.log {
daily
missingok
rotate 14
compress
delaycompress
notifempty
create 0644 www-data adm
sharedscripts
prerotate
if [ -d /etc/logrotate.d/httpd-prerotate ]; then \
run-parts /etc/logrotate.d/httpd-prerotate; \
fi \
endscript
postrotate
invoke-rc.d nginx rotate >/dev/null 2>&1
endscript
}
После чего процесс ротации надо перезапустить:
sudo service logrotate restart
Убедимся, что ротация работает:
sudo service logrotate status
Увидим:
● logrotate.service - Rotate log files
Loaded: loaded (/lib/systemd/system/logrotate.service; static; vendor preset: enabled)
Active: inactive (dead) since Wed 2022-05-18 16:47:06 MSK; 4s ago
TriggeredBy: ● logrotate.timer
Docs: man:logrotate(8)
man:logrotate.conf(5)
Process: 20860 ExecStart=/usr/sbin/logrotate /etc/logrotate.conf (code=exited, status=0/SUCCESS)
Main PID: 20860 (code=exited, status=0/SUCCESS)
14. Геограничения
https://docs.nginx.com/nginx/admin-guide/installing-nginx/installing-nginx-plus/ https://docs.nginx.com/nginx/admin-guide/dynamic-modules/geoip2/
https://nginx.org/ru/docs/http/ngx_http_geoip_module.html https://dev.maxmind.com/?lang=en