Часто на первом проекте кажется, что самое сложное позади: приложение готово, осталось только показать его миру. Но что, если сервер под угрозой?
В этой статье — простая и проверенная инструкция по настройке безопасного сервера для вашего первого fullstack-приложения. От SSH до SSL и двухфакторной аутентификации — рассказываю, как я защитил свой SaaS-проект Transcribator.
Шаг 1: Подключение и создание нового пользователя
Для начала подключаемся к серверу через IP-адрес и пароль, предоставленные провайдером. Обычно эти данные указываются в личном кабинете сервиса. Пример подключения:
ssh root@ваш_IP_адрес
Система запросит пароль, который вы получили от провайдера. После успешного входа создаём нового пользователя:
-
Создаём пользователя:
sudo adduser admin
Система попросит ввести пароль для нового пользователя — выберите надёжный пароль и сохраните его.
-
Добавляем пользователя в группу sudo:
Что предоставляет ему административные права на сервере. Это необходимо для того, чтобы новый пользователь мог выполнять команды с повышенными привилегиями, такие как установка программного обеспечения или настройка системных параметров, не заходя под учетной записью
root
. Это улучшает безопасность, так как использованиеroot
-доступа напрямую считается рискованнымsudo usermod -aG sudo admin
-
Для проверки подключаемся в новом окне терминала от имени нового пользователя:
ssh admin@ваш_IP_адрес
Теперь можно продолжить настройку.
Шаг 2: Установка nano
Прежде чем редактировать конфигурационные файлы, установим текстовый редактор nano. Это удобный и понятный инструмент для работы с файлами.
sudo apt install nano -y
Основные команды nano:
Ctrl+O
– сохранить файл.Ctrl+X
– выйти из редактора.Ctrl+K
– вырезать строку.
Шаг 3: Настройка SSH
SSH (Secure Shell) позволяет безопасно управлять сервером удалённо, в отличие от обычных подключений, которые менее защищены. Если на вашем локальном компьютере ещё не настроены SSH-ключи, сгенерируйте их:
-
Генерация SSH-ключей на локальном компьютере (локально):
ssh-keygen -t rsa -b 4096
Система попросит указать путь для сохранения ключа (можно оставить по умолчанию) и установить пароль (опционально).
-
Копирование публичного ключа на сервер (локально):
Выполните следующую команду, чтобы добавить ваш публичный ключ на сервер:
ssh-copy-id admin@ваш_IP_адрес
Если команда не доступна, можно вручную скопировать содержимое файла
~/.ssh/id_rsa.pub
на локальном компьютере и добавить его в файл~/.ssh/authorized_keys
на сервере:cat ~/.ssh/id_rsa.pub | ssh admin@ваш_IP_адрес "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
-
Запретить подключение по root и паролю:
Открываем файл настройки SSH:
sudo nano /etc/ssh/sshd_config
Вносим изменения:
PermitRootLogin no PasswordAuthentication no
-
Перезапускаем SSH:
sudo systemctl restart ssh
В новом окне пробуем подключиться:
ssh -i ~/.ssh/id_rsa admin@<ваш IP>
Шаг 4: Установка и настройка брандмауэра
Брандмауэр (ufw) защищает сервер, разрешая подключение только на определённые порты.
-
Устанавливаем ufw:
sudo apt update sudo apt install ufw -y
-
Открываем только нужные порты:
Порт 22 — для SSH (удалённое управление).
Порт 80 — для HTTP (незащищённые соединения).
Порт 443 — для HTTPS (защищённые соединения).
sudo ufw allow 22 sudo ufw allow 80 sudo ufw allow 443
-
Включаем брандмауэр:
sudo ufw enable
-
Проверяем статус:
sudo ufw status
Убедитесь, что отображаются разрешённые порты (22, 80, 443).
Шаг 5: Установка Fail2ban
Fail2ban защищает сервер от атак брутфорс, блокируя IP-адреса после нескольких неудачных попыток подключения.
-
Установка:
sudo apt install fail2ban -y
-
Создаём конфигурацию:
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local sudo nano /etc/fail2ban/jail.local
-
Добавляем базовые правила:
bantime
— время блокировки IP-адреса (30 минут).findtime
— период, за который учитываются неудачные попытки.maxretry
— максимальное число попыток перед блокировкой.
[DEFAULT] bantime = 30m findtime = 10m maxretry = 5 [sshd] enabled = true
-
Перезапускаем Fail2ban:
sudo systemctl restart fail2ban
Fail2ban будет анализировать логи SSH и блокировать подозрительные попытки подключения.
Шаг 6: Установка SSL
SSL (Secure Sockets Layer) обеспечивает шифрование данных между клиентом и сервером, предотвращая перехват данных злоумышленниками. Без SSL браузеры предупреждают пользователей о небезопасном соединении, что негативно сказывается на пользовательском опыте.
Сертификаты выдаются на определённое время, поэтому важно настроить их автоматическое обновление.
-
Устанавливаем Certbot:
sudo apt install certbot python3-certbot-nginx -y
-
Получаем SSL-сертификат:
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
-
Автоматическое обновление сертификатов:
Открываем crontab:
sudo crontab -e
Добавляем строку:
0 0 * * * certbot renew --quiet
Теперь ваши данные защищены шифрованием, а сертификаты будут обновляться автоматически.
Шаг 7: Настройка двухфакторной аутентификации
Двухфакторная аутентификация добавляет дополнительный уровень защиты, требуя ввода одноразового кода из приложения Google Authenticator.
-
Устанавливаем Google Authenticator:
sudo apt install libpam-google-authenticator -y google-authenticator
Следуйте инструкциям и сохраните ключ для приложения аутентификации.
-
Включаем двухфакторную аутентификацию:
Открываем PAM:
sudo nano /etc/pam.d/sshd
Добавляем строку:
auth required pam_google_authenticator.so
-
Редактируем настройки SSH:
sudo nano /etc/ssh/sshd_config
Находим или добавляем такие значения для работы Google авторизации:
KbdInteractiveAuthentication yes ChallengeResponseAuthentication yes PasswordAuthentication no PubkeyAuthentication yes UsePAM yes Match Address <IP1>,<IP2>,<IP3> AuthenticationMethods publickey Match all AuthenticationMethods keyboard-interactive
Match Address - это разрешенные адреса по которым не будет запрашиваться пароль.
Match all - для всех остальных запрашивается пароль из google и потом для пользователя admin под которым мы входим.
IP - ваш текущий можно узнать на сайте Мой IP -
Перезапускаем SSH:
sudo systemctl restart ssh
Теперь при попытке входа сервер запросит код из приложения Google Authenticator.
Итог
Эти шаги обеспечивают базовую защиту сервера. Если у вас есть свои подходы к настройке безопасности или идеи как улучшить предложенные шаги, делитесь ими в комментариях!
P.S. Моё приложение развернуто через Docker Compose, где объединены Nginx, PostgreSQL, Redis, бэкенд, фронтенд и лендинг. Если вам интересно, как это было реализовано, напишите в комментариях — я подготовлю статью с подробным описанием.
Комментарии (20)
Lev3250
03.01.2025 08:24Если уж меняем рут на что-то другое, то есть смысл указать рандомное имя, а не админ. Остальное на удивление ёмко и по делу. Спасибо!
ToSHiC
03.01.2025 08:24Если у вас
mkdir -p ~/.ssh
таки выполнится - вы потом долго будете дебажить, почему вход по ключу не работает. Права на директорию и файл должны быть 0700 и 0600 соответственно.Двухфакторный вход при логине по ключу не имеет большого смысла, и будет очень сильно усложнять жизнь впоследствии. Хотите тут безопасности - используйте аппаратное хранилище ключей.
aborouhin
03.01.2025 08:24ufw с docker дружатся, мягко говоря, неочевидно. Да и в целом, у nftables на удивление простой и приятный синтаксис, так что лишний уровень абстракции в виде ufw не особо что упрощает, а когда захочется подкрутить что-то посложнее - наоборот, мешает.
Kenya-West
03.01.2025 08:24Эта проблема впоследствии решается Ansible. Например, у меня он сам после работы CI/CD ходит и выдирает из .env'ов и docker-compose.yml'ов значения, которые потом прописывает в
ufw allow
.Но сразу говорю, что мой совет из разряда "проблема воробьёв решается пушкой". Юзать Ansible на этапе, когда это твой первый сервер в жизни — это лютый оверкилл.
Я лично до использования Ansible дорос самостоятельно, просто потому что личных серверов уже за два десятка перевалило.
aborouhin
03.01.2025 08:24Ну про Ansible я не стал писать ровно по этой же причине, что для первого сервера пока рановато. Хотя, с другой стороны, это очень сильно дисциплинирует записывать (и тем самым документировать) все свои настройки. Ну и в случае переноса на новый сервер разворачивать всё там одной командой (ну почти одной, юзера-то создать и SSH настроить придётся руками - разговор про Cloud-Init и тем более Terraform у нас тоже впереди...)
Но с firewall'ом и тут, на мой взгляд, ufw только добавляет сложности. Хоть для него и есть community.general.ufw, но для чистого nftables куда удобнее сделать каталог /etc/nftables.conf.d/, куда Ansible'ом класть по шаблону файлик для каждого сервиса. А что-то более или менее сложное без ручной магии с /etc/ufw/before.rules всё равно не настроить, и вот тут уже начинаются чреватые ошибками костыли.
pae174
03.01.2025 08:24KbdInteractiveAuthentication yes
ChallengeResponseAuthentication yes
PasswordAuthentication noChallengeResponseAuthentication это на самом деле алиас для KbdInteractiveAuthentication. То есть эти две штуки это одно и то же, но ChallengeResponseAuthentication позже могут и выкинуть на фиг.
KbdInteractiveAuthentication=yes на самом деле делает возможным вход по паролю, так что последующая PasswordAuthentication=no становится бесполезной и дает вам только иллюзию безопасности.
Выданный вам начальный рутовый пароль вообще-то надо сразу поменять на свой. Просто потому что ломать пароль вам все равно будут из-за KbdInteractiveAuthentication=yes а изначальный пароль скорее всего а) простой и б) еще часто посылается клиенту по электронной почте и, таким образом, тихо-мирно ждет своего часа.
Про права доступа на файлы authorized_keys уже написали комментом выше.
Нет никакого упоминания о том, что надо на первом коннекте по ssh сверить слепок серверного ключа. А то вдруг у вас там с самого начала MitM, а вы и не в курсе.
kvazimoda24
03.01.2025 08:24Так и подмывает спросить, а когда будут советы по настройке сервера от уборщицы, которая полы мыла в машинном зале?
Фронтендер не должен заниматься настройкой сервера.
Ufw — какое-то очень странное поделие, которое генерит правила в стиле iptables, а затем скармливает их ему, притом что iptables уже довольно давно является устаревшим и по сути ещё раз преобразует правила уже в формат nftables. И я вот не помню, нужно ли в ufw отдельно разрешать исходящий трафик.
Есть сомнения в необходимости использования двухфакторной аутентификации при использовании SSH ключей.
Почему бы не использовать ключи на эллептических кривых? Как для SSH, так и для Web сервера.
Fail2ban для SSH сомнительное решение. Если отключили вход по паролю, то в целом подбор паролей ботами только логи засирает. Но эти боты прекрасно распознают настройки fail2ban, и долбятся с разных IP. И тут либо белые списки, либо knok-knok (или как там оно называется, когда чтобы порт тебе открыли, надо постучаться на какие-то другие порты в определённой последовательности).
История про работу из под root тоже уже порядком достала. Если ты один админишь машину, то проще сразу под рутом логиниться по ключу. Всё равно первой командой после логина будет sudo -i. Ну или будешь ко всем командам приписывать sudo в начале. А вся эта история с безопасностью — это когда пишут правила для sudo, кому какие команды можно выполнять и под какими пользователями. Но тут надо ооочень грамотно подходить к вопросу, т.к. методов подняться до рута в этом случае ну очень много.
По правам на каталог ~/.ssh уже сказали.
aborouhin
03.01.2025 08:24Фронтендер не должен заниматься настройкой сервера.
Вот меня всегда поражает этот корпоративный снобизм. Конечно, если фронтэндер решил запилить свой проект, он должен взять кредит на многомиллионов, нанять бэкэндера, архитектора, пару аналитиков, девопса, девсекопса, тестировщика, маркетолога, бухгалтера, финансиста, юриста, водителя и секретаршу, - чтобы не дай Бог не сделать чужую работу...
и поняв, что MVP не взлетел, подавать на личное банкротство:)kvazimoda24
03.01.2025 08:24Снобизм? Ну так советы от этого фронтендера такие себе. Работать, конечно, будет, но больше смахивает на то, что человек где-то что-то услышал, но толком не разобрался что это и для чего.
Ну и если это не страничка визитка, то подразумевается ещё и бекенд. Его тоже фронтендер писать будет? И тоже советы тут будет давать?
Ведь, одно дело пилить проект для себя, а другое дело советы раздавать. Я вот немножко программирую на Си, Питон, JS, Bash... Но как-то советы раздовать по этому поводу мне хватает компетенции не раздавать, т.к. я прекрасно понимаю, что программист из меня паршивый.
aborouhin
03.01.2025 08:24Насчёт того, что с написанием гайдов для Хабра автор поторопился, я полностью согласен, ему тут по делу накидали даже относительно того, что он описал (а это только самая база и верхушка айсберга) Но стремление познавать смежные области я только поддерживаю. Когда сам разберёшься - уже и делегировать другим будет проще осознанно, если до этого дойдёт.
IvanBodhidharma
03.01.2025 08:24Ну и если это не страничка визитка, то подразумевается ещё и бекенд. Его тоже фронтендер писать будет?
Почему бы и нет, что не так?
VenbergV
03.01.2025 08:24Перестаньте править sshd_config! Это файл системных настроек. Который может быть затерт при обновлении системы. Для пользовательских настроек есть каталог sshd_config.d.
Зачем RSA ключи для новых систем в 2025 году? Они скорее понадобятся для старых систем и старого оборудования. Для остального есть ed25519.
Зачем ufw в новом сервере в 2025 году? Debian12, Ubuntu 22.04-24.04 используют nftables.
ИМХО. Из-за отсутствия поддержки nftables в Docker, лучше перейти на Podman. Правда проскакивала информация, что новую версию Docker переведут на nftables. Но срок пока не определен.
aborouhin
03.01.2025 08:24Перестаньте править sshd_config! Это файл системных настроек. Который может быть затерт при обновлении системы. Для пользовательских настроек есть каталог sshd_config.d.
Все дистрибутивы, с которыми я сталкивался, в случае, если конфиг изменён пользователем, при обновлении в интерактивном режиме спрашивали, перезаписать ли его (по умолчанию предлагая оставить), в unattended режиме - молча оставляли пользовательскую версию. А вот если конфиг не менять - его правда молча перезапишет, и не факт, что очередное обновление не добавит каких-то новых дефолтных настроек, которые надо бы переопределить.
Из-за отсутствия поддержки nftables в Docker, лучше перейти на Podman.
Ну на самом деле docker с nftables работает, он вызывает iptables-nft, который транслирует правила в формат nftables. Беда в том, что если потом хочется добавить свои правила и перезапустить nftables - всё это автомагическое творчество docker'а сбрасывается. С podman ровно та же история, не заметил практической разницы. В общем, если есть автоматическая настройка правил nftables, например через Ansible, и что-то не вполне тривиальное, - то проще docker'у в настройках запретить создавать правила, вручную определять его сети и задавать правила для них.
mr-andry
03.01.2025 08:24Спасибо за статью!
Дополнительно можно обратить внимание на автоматические обновления безопасности для дистрибутива (например, с помощью unattended-upgrades в Ubuntu), чтобы своевременно получать патчи уязвимостей. Также не лишним будет настроить мониторинг (например, Netdata или Prometheus + Grafana) — так можно быстро реагировать на рост нагрузки или подозрительную активность. В остальном, для первого развёртывания fullstack-проекта этого гида более чем достаточно!
Balintrue
03.01.2025 08:24Ctrl+O
– сохранить файл.
Мне кажется, в nano для сохранения используется Ctrl+S
melkorus
03.01.2025 08:24Базовая настройка, под определенные нужды. Нет ничего плохого или хорошего в этом, просто гайд для людей которые чего то недопонимают. (Люди которые понимают, им он в принципе не нужен, те люди которые не понимают, не набив шишек не поймут). К сожалению, не нашел тут тип OS, на сколько понял что то Дебиан подобное (Вероятнее всего убунту). Так же видел комментарий по поводу Windows server, вообще проект и на IIS можно запилить, а вот стоит ли, это уже другой вопрос. Считаю , то что статья должна быть продолжением чего то изначального, если был посыл показать, как проще настроить свой сервер (локальный само собой).
abcdsash
а почему автор считает, что сервер по умолчанию будет на чем то отличном от венды?
а вдруг на вендовсе сервере каком нить?
Lainhard
Потому что это действительно "по умолчанию"
HyperWin
Сервер на винде это сюр. Если только такими пользуетесь - ищите свой гайд.