← До всіх записів
ubuntusecuritybootstrap

Перший bootstrap сервера: від сирого VPS до базового production baseline

Великий конспект першого дня сервера: оновлення Ubuntu, timezone, базові утиліти, UFW, fail2ban, SSH-політика, nginx, MariaDB, PHP, Docker, reverse proxy і логіка того, чому на Linux hardening важливіший за класичний “антивірус”.

16 квітня 202612 хв читанняСирий VPS став керованою базою під сервіси

Перший bootstrap сервера: від сирого VPS до базового production baseline

Це той запис, якого мені самому дуже бракувало на старті. Не "ось список модних інструментів", а чесний і зрозумілий конспект того, як із сирого VPS зробити нормальну базу під реальні сервіси.

Вхідні дані були прості:

  • OVH VPS
  • Ubuntu 22.04 LTS
  • користувач ubuntu з sudo
  • домен bombaworkflows.com

Ціль теж була проста: не просто "щоб відкривався сайт", а щоб сервер одразу будувався як маленька, але вже доросла інфраструктура. Без зайвої магії, зате з логікою.

Крок 1. Оновити систему одразу, поки вона ще чиста

Перший крок після входу на сервер:

terminal
sudo apt update && sudo apt full-upgrade -y

Це банально, але саме тут закривається величезна частина стартових ризиків:

  • старі пакети
  • старі залежності
  • security fixes, які вже доступні

Я дуже люблю починати саме з цього, бо далі весь стек ставиться вже на актуальну систему, а не на застарілу базу.

Крок 2. Виставити правильний timezone

Час на сервері - це не дрібниця. Якщо він налаштований криво, потім криво виглядають:

  • логи
  • cron-завдання
  • часові мітки в моніторингу
  • сертифікати і scheduled jobs

У моєму випадку timezone був таким:

terminal
sudo timedatectl set-timezone Europe/Kyiv
timedatectl

Після цього всі логи, cron і ручні перевірки вже жили в звичному часовому просторі.

Крок 3. Доставити базовий набір утиліт

Щоб сервером було зручно користуватись, я одразу поставив мінімальний набір корисних інструментів:

terminal
sudo apt install -y curl wget git htop rsync unzip zip tree ncdu jq

Кожен із них швидко окупається:

  • curl для HTTP-перевірок
  • git для майбутніх деплоїв
  • htop для живої діагностики
  • rsync для копій і переносу даних
  • tree і ncdu для розуміння файлової структури
  • jq для роботи з JSON-відповідями

Крок 4. Закрити все зайве через UFW

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

Початковий набір відкритих портів був мінімальний:

terminal
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status verbose

У результаті зовні залишилися відкритими лише:

  • 22 для SSH
  • 80 для HTTP
  • 443 для HTTPS

Усе інше було закрито.

Це одна з найважливіших базових звичок: не відкривати порт "про всяк випадок". Якщо сервіс можна заховати за reverse proxy або повісити на 127.0.0.1, значить саме так і треба робити.

Крок 5. Те, що часто називають "антивірусом", на Linux виглядає інакше

На Windows логіка часто така: ставимо антивірус і ніби вже спокійні.

На серверному Linux базовий захист зазвичай починається не з класичного AV, а з таких шарів:

  • актуальні пакети
  • мінімум відкритих портів
  • fail2ban
  • адекватна SSH-політика
  • сервіси, прив'язані до localhost
  • reverse proxy як єдина публічна точка входу

Тобто замість класичного "антивірусу" на практиці я будував саме hardening baseline. Для Linux-сервера це набагато ближче до реальності.

Крок 6. Увімкнути fail2ban як анти-bruteforce шар

Щоб сервер не приймав безкінечні спроби логіну, я поставив fail2ban:

terminal
sudo apt install -y fail2ban
sudo systemctl enable --now fail2ban
sudo systemctl status fail2ban --no-pager

Його роль дуже практична: ловити повторні невдалі спроби входу і тимчасово банити джерело.

Тобто якщо спростити, то саме це і є той "бан-файл/бан-механізм", про який багато хто говорить на старті серверної безпеки.

Крок 7. Налаштувати SSH без зайвого героїзму

Я спеціально не поспішав повністю відключати парольний вхід, бо хотів залишити собі запасний спосіб зайти під час активного налаштування.

Поточна SSH-політика вийшла такою:

  • PubkeyAuthentication yes
  • PasswordAuthentication yes тимчасово
  • PermitRootLogin without-password

Це хороший компроміс для перших днів:

  • вже є ключі
  • root не входить звичайним паролем
  • пароль для ubuntu ще можна залишити як тимчасовий backup path

Пізніше це точно варто дотиснути до повного key-only доступу, але не обов'язково в першу ж годину життя сервера.

Крок 8. Поставити веб- і runtime-шар

Базовий LEMP-стек я зібрав так:

terminal
sudo apt install -y nginx mariadb-server php8.1-fpm php8.1-mysql

Далі логіка була така:

  • nginx як головний reverse proxy
  • MariaDB слухає тільки localhost
  • PHP-FPM підключений через socket

Це вже дає нормальну базу для класичних сайтів, WordPress або проміжного стейджингу.

Крок 9. Захистити MariaDB і не світити її назовні

Для бази даних ключове правило дуже просте: якщо до неї не треба ходити з інтернету, вона не повинна слухати інтернет.

Тут базові дії були такими:

terminal
sudo mysql_secure_installation
sudo ss -tulpn | grep 3306

Після цього MariaDB залишилась доступною лише локально, а не на публічному інтерфейсі.

Крок 10. Поставити Docker і compose plugin

Окремий пласт завдань я відразу хотів запускати в контейнерах, тому наступним шаром став Docker:

  • Docker Engine
  • Docker Compose plugin

І ще важливий практичний момент:

  • користувача ubuntu я додав у docker group

Щоб далі працювати із сервісами без постійного sudo.

Крок 11. Виносити сервіси на 127.0.0.1, а не в публічний інтернет

Один із найсильніших архітектурних принципів цього сервера звучить так:

усі сервіси через reverse proxy, мінімум відкритих портів

Саме тому інфраструктурні сервіси були прив'язані не до 0.0.0.0, а до localhost:

  • 127.0.0.1:3001 для Uptime Kuma
  • 127.0.0.1:9443 для Portainer

Зовні користувач бачить лише:

  • 80
  • 443
  • 22

А все інше ховається за nginx.

Крок 12. Побудувати reverse proxy під домени

Публічна схема з самого початку вийшла дуже чистою:

text
Internet
  -> Cloudflare
  -> Nginx
  -> dev / kuma / portainer
  -> локальні сервіси і web root

Окремі віртуальні хости були налаштовані для:

  • dev.bombaworkflows.com
  • kuma.bombaworkflows.com
  • portainer.bombaworkflows.com

Логіка по них така:

  • dev спочатку дивився в /var/www/testsite/public
  • kuma проксіювався на 127.0.0.1:3001
  • portainer проксіювався на https://127.0.0.1:9443

Крок 13. HTTPS одразу, а не "колись потім"

Сертифікати були випущені для:

  • dev.bombaworkflows.com
  • kuma.bombaworkflows.com
  • portainer.bombaworkflows.com

Ключова перевірка тут була двошарова:

terminal
sudo certbot renew --dry-run
systemctl status snap.certbot.renew.timer --no-pager

Це теж важливий DevOps-урок: мало один раз отримати сертифікат. Треба ще перевірити, що renewal дійсно працюватиме.

Який стан сервера вийшов після першого циклу

Після всіх цих кроків VPS перестав бути просто "Ubuntu у хмарі" і перетворився на вже цілком серйозну базу:

  • ОС оновлена
  • timezone виставлено
  • встановлені робочі утиліти
  • UFW обмежує трафік
  • fail2ban ловить brute-force
  • SSH уже частково захардений
  • nginx працює як єдиний вхідний шар
  • MariaDB не стирчить назовні
  • Docker готовий під інфраструктурні сервіси
  • домени живуть за reverse proxy
  • HTTPS вже автоматично поновлюється

Команди швидкої перевірки, які я б залишив собі як cheat sheet

Ось той набір, який дуже корисно мати під рукою після bootstrap:

terminal
sudo ufw status verbose
sudo systemctl status fail2ban --no-pager
sudo ss -tulpn
sudo nginx -t
systemctl status nginx --no-pager
docker ps
curl -I https://dev.bombaworkflows.com
curl -I https://kuma.bombaworkflows.com
curl -I https://portainer.bombaworkflows.com

Цієї добірки вже достатньо, щоб за хвилину зрозуміти, в якому стані firewall, reverse proxy, Docker і публічні сервіси.

Висновок

Найголовніше відкриття першого дня було не в тому, який саме пакет ставити першим. Найголовніше - зрозуміти правильний порядок мислення:

  1. онови систему
  2. закрий мережу
  3. нормалізуй доступ
  4. побудуй єдину точку входу
  5. ховай сервіси за reverse proxy
  6. автоматизуй те, що зламається без автоматизації

Саме цей порядок і перетворює сирий VPS на базовий production-ready фундамент. Не ідеальний, не завершений, але вже такий, на який можна спиратись і спокійно нарощувати наступні шари: бекапи, моніторинг, compose, git deploy і далі вже CI/CD та IaC.