Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

86 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

UbuntuServer Fast Configuration

logo

Ubuntu 24.04 | 26.04 Debian 12 | 13 bash license MIT

🇷🇺 Русский · 🇬🇧 English

Каждый раз, когда поднимаешь новый VPS, повторяется одно и то же: поставить нормальный ls, накатить Docker, разобраться со свопом на маленьком сервере, включить SSH только по ключу и не забыть про UFW. Чтобы не повторять регулярно одно и то же — написал скрипт с меню на 14 пунктов, который делает это всё сам, спрашивая только там, где решение реально важно принять тебе, а не ему.

Работает на Ubuntu и Debian, умеет русский и английский интерфейс, а кроме меню имеет неинтерактивный режим для cloud-init и Ansible, сухой прогон, аудит сервера и снимки конфигов перед изменением.

Требования

Ubuntu 24.04/26.04 или Debian 12/13, root-доступ, исходящий интернет.

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

Содержание

Быстрый старт

curl -fsSL https://raw.githubusercontent.com/SkyDeaD/UbuntuServer-Fast-Configuration/main/install.sh | sudo bash && source ~/.bashrc

Ставится как команда usfc и сразу открывает меню — без ожидания: apt update больше не гоняется на старте, он подтягивается лениво и только перед реальной установкой. Функция usfc() (не alias) добавляется в .bashrc сама при первом запуске — дальше просто usfc, sudo руками писать не нужно, а когда меню закрывается, она сама подтягивает .bashrc в твою же сессию, так что новые алиасы/промпт видны сразу, без ручного source или переподключения (подробнее — в FAQ).

2026-07-15_23-02 2026-07-15_23-05 2026-07-15_23-07 2026-07-15_23-12 2026-07-15_23-15 2026-07-15_23-20

В меню — номер пункта (5, можно несколько сразу: 1 3 5 или 1,3,5), раздел целиком (C/B/S/P), всё сразу (A), можно сочетать (B,S). На пачку из нескольких пунктов все вопросы задаются заранее, одним блоком с пояснениями — что такое zram, нужен ли автозапуск nginx и Docker, нужен ли Cloudflare-плагин с токеном. Дальше пункты идут без остановок, а в конце показывается сводка: что встало, что упало, что пропущено. I (или ?, а также R) — справка и откат по пунктам: что делает каждый, какой у него сейчас статус, как выключить и как удалить совсем. H — справка по алиасам, U — снести сам usfc.

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

Запуск на голом сервере (только root)

Многие хостеры отдают VPS, где есть только root. Скрипт это замечает и первым делом предлагает завести обычного пользователя с sudo (по умолчанию — да):

[!] Скрипт запущен от имени root.
[i] РЕКОМЕНДУЮ создать обычного пользователя с sudo: работать из-под root
    небезопасно, SSH hardening без отдельного пользователя не работает вообще,
    а алиасы/fastfetch/tmux сейчас лягут в /root и пропадут после перелогина.

  Создать пользователя сейчас? [Y/n]:

Он спросит имя и пароль (скрытым вводом, с повтором), добавит в группу sudo и предложит скопировать ключи из /root/.ssh/authorized_keys — без этого новый пользователь просто не сможет зайти, если ты ходишь на сервер по ключу. Пароль короче 8 символов не принимается: сервер смотрит в интернет, и перебор по нему идёт круглосуточно. Пустой пароль допустим — тогда вход только по ключу.

Дальше скрипт переключается на нового пользователя прямо в работающей сессии, так что алиасы, fastfetch и tmux лягут уже ему, а не в /root. При выходе он напомнит перезайти под ним.

Если отказаться — ничего не сломается: пункт 1 «Пользователь + sudo» доступен в меню в любой момент. Как и SSH hardening с UFW, при выборе A («поставить всё») он пропускается: пароль и имя молча задефолтить нельзя.

Флаги

usfc --help        # справка
usfc --version     # версия
usfc --no-update   # не проверять обновления самого usfc
usfc --verbose     # сырой вывод команд вместо спиннера
usfc --lang en     # английский интерфейс на этот запуск
usfc --audit       # проверить состояние сервера, ничего не меняя
usfc --list        # профили и id пунктов
usfc --apply web   # применить набор пунктов без меню
usfc --dry-run     # показать, что было бы сделано
usfc --backups     # снимки конфигов
usfc --restore     # вернуть конфиги из снимка

Переменная USFC_APT_LOCK_TIMEOUT (по умолчанию 300 с) задаёт, сколько ждать освобождения блокировки dpkg. Ждать приходится потому, что на только что загруженном сервере apt-daily.timer запускает unattended-upgrades, и тот держит /var/lib/dpkg/lock-frontend минутами — без ожидания любая установка падала бы мгновенно с E: Could not get lock.

Полный лог всех выполненных команд всегда пишется в /var/log/usfc.log — даже когда на экране только спиннер.

Цвет отключается переменной NO_COLOR (значение неважно, важно наличие), а также сам собой при TERM=dumb и когда вывод идёт не в терминал — например usfc > log.txt.

Не доверяешь curl | sudo bash и хочешь применить то же самое руками, пункт за пунктом? — держи ручную инструкцию.

Что менялось от версии к версии — в CHANGELOG.md.

Что делает каждый пункт

База, сервисы, защита — по порядку

Пользователь + sudo — создаёт обычного пользователя с sudo, копирует ему SSH-ключи из /root и переключает на него всю дальнейшую настройку. Нужен, когда сервер выдали с одним лишь root. Подробности — выше.

Базовые пакетыmicro, curl, wget, git, nano, unzip, htop, jq, rsync и ещё несколько вещей, которые обычно ставишь в первую же минуту на любом сервере. После установки выводится список: что приехало сейчас, что уже стояло, и коротко — зачем каждый пакет нужен — в том числе software-properties-common, без которого не заработает add-apt-repository, нужный дальше для PPA fastfetch. certbot отсюда переехал в свой пункт (см. ниже).

CLI-утилиты + starship — современные замены классических утилит (eza вместо ls с иконками, bat/batcat вместо cat с подсветкой, fd/fdfind вместо find, ripgrep, zoxide — «умный» cd, ncdu для разбора места на диске) и starship-промпт — всё вместе, потому что это один и тот же слой "как выглядит и ощущается терминал". Алиасы в .bashrc (ls/ll/la/lt/cat/catp/scat/fd) и eval-строки для zoxide/starship пишутся сразу тем же пунктом, а не отдельным шагом позже.

fastfetch — показывает информацию о сервере (ОС, ядро, память, диск, IP) при каждом заходе по SSH. Версия не ниже 2.64.0 (более старые не умеют выравнивание в format-строках, которое использует прилагаемый config.jsonc). Конфиг и автозапуск пишутся в .bashrc сразу тем же пунктом.

tmux — мультиплексор терминала: держит сессию живой при обрыве связи (просто переподключаешься по SSH — и всё, что запускал, на месте, включая несколько окон/панелей). Ставится с минимальным конфигом (мышь, история на 10000 строк).

Docker + Compose — CE + Compose plugin из официального репозитория Docker (не пакет docker.io из репов Ubuntu — он старый).

nginx-full — веб-сервер/реверс-прокси.

Про автозапуск nginx и Docker. Оба пакета по умолчанию поднимают сервис сами, из postinst. Скрипт спрашивает об этом до установки, и по умолчанию отвечает нет — сервер не всегда нужно поднимать прямо сейчас. Чтобы «не запускать» означало именно это, а не «поднять и тут же погасить» (nginx успел бы занять :80), установка оборачивается в policy-rc.d. Выключенный сервис меню считает законченным состоянием, а не недоделкой, и повторно не пристаёт.

Передумать можно в любой момент. На установленной системе оба пункта работают выключателями: показывают текущее состояние и предлагают обратное — остановить работающий сервис или поднять остановленный вместе с автозапуском. У Docker при этом снимаются оба юнита, docker.service и docker.socket: без второго демон возвращается сам при первом же обращении к сокету, и «автозапуск выключен» оказывается неправдой.

Certbot + плагины — сам certbot плюс, по выбору, плагин nginx (HTTP-01, обычные сертификаты) и плагин dns-cloudflare (DNS-01, без которого не выпустить wildcard). Для Cloudflare тут же предлагается создать /root/.secrets/certbot/cloudflare.ini с API-токеном (скрытый ввод, права 600, нужны права токена Zone:DNS:Edit). Откажешься — пункт так и будет светиться в меню как ! токен CF не задан, потому что без файла плагин нерабочий.

Про WARNING от python-cloudflare 2.20. Плагин объявляет Depends: python3-cloudflare (<< 3.0), а в архиве Ubuntu 26.04 лежит ровно одна подходящая версия — 2.20.0, и Ubuntu баннер из неё не вырезала. Проверено на живой системе: баннер срабатывает в конструкторе клиента, то есть при реальном выпуске сертификата, а не при установке — apt install, certbot --version и certbot plugins молчат. Отключить его нельзя: warn_warning_2_20() сам зовёт warnings.simplefilter('always', ...), перебивая и PYTHONWARNINGS, и python3 -W ignore. На выпуск сертификатов он не влияет — версия закреплена зависимостью пакета, а не выехала сама из pip. Скрипт предупреждает о нём заранее, чтобы баннер не выглядел поломкой.

Отдельно предлагается положить в /etc/letsencrypt/ заготовки ssl-dhparams.pem и options-ssl-nginx.conf. Их создаёт только nginx-installer certbot'а, а при выпуске wildcard через certbot certonly они не появляются — и типовой конфиг nginx, который на них ссылается, роняет сервер при старте. Оба файла берутся из самого пакета certbot, ничего не генерируется и не качается.

Docker log rotation — ограничивает логи контейнеров (лимит 10 МБ на файл): без этого логи Docker по умолчанию ничем не ограничены и со временем могут забить всё место на диске.

fail2ban — банит IP после нескольких неудачных попыток входа по SSH (защита от перебора паролей). Настраивается на реальный SSH-порт сервера, не хардкожен 22.

unattended-upgrades — сам ставит security-обновления системы, без твоего участия.

ZRAM + swap + earlyoom — zram (сжатая память прямо в оперативке; сколько % RAM под неё отдать — теперь спрашивается при установке, по умолчанию 75%) плюс резервный swap-файл на диске с более низким приоритетом, чтобы использовался только если не хватило zram. Размер спрашивается, а по умолчанию считается как min(RAM, свободно/4), зажатое в 512–4096 МБ: своп здесь — резерв под zram, поэтому пляшет от объёма памяти, а деление на 4 не даёт ему съесть тесный диск. Если swap-файл уже есть, скрипт покажет его текущий размер рядом с рекомендуемым и предложит пересоздать — но только когда они расходятся больше чем на 10%, и только для файлов: размер разделов и LVM он не трогает. Плюс vm.swappiness=80/vm.vfs_cache_pressure=50 и опционально earlyoom — защита от полного зависания сервера при нехватке памяти.

SSH hardening — переводит вход только на ключ, выключает вход по паролю и вход под root. Самый рискованный пункт меню, поэтому единственный с самопроверкой перед применением: перед тем как выключить пароль, скрипт заводит одноразовый ключ и реально проверяет вход по нему — если проверка не прошла, автоматически откатывает конфиг и оставляет пароль включённым.

UFW — файрвол: закрывает все порты, кроме нужных (SSH-порт и то, что сервер уже реально слушает на момент включения).

Раздел «защита» идёт последним осознанно: UFW при включении сканирует реально слушающие порты, и если Docker/nginx уже подняты, фаервол сразу увидит их порты, а не только 22-й.

Аудит сервера

Скрипт умеет не только настраивать, но и отвечать на вопрос «что с сервером прямо сейчас». Клавиша D в меню или usfc --audit:

Сеть
! Порты наружу: 22
    Файрвол выключен — доступны все. Пункт 14

Доступ
! Вход по паролю разрешён
    Перебор по SSH идёт круглосуточно. Пункт 13
✓ Root-логин: prohibit-password
! fail2ban не работает
    Пункт 10

Итог:  в норме: 9   замечаний: 3   важных: 0

Проверяются место на диске и inode (кончаются раньше места и выглядят как «нет места» при свободных гигабайтах), память и подкачка, упавшие systemd-юниты, порты наружу против правил UFW, вход по паролю и root-логин, неустановленные security-обновления, необходимость перезагрузки, срок жизни сертификатов.

Аудит только читает. Это не обещание, а проверяемое свойство: в CI есть тест, который сверяет слепок /etc, dpkg, passwd/group и свопа до и после прогона.

Неинтерактивный режим

Всё то же самое, но без меню — для cloud-init, Ansible и скриптов развёртывания:

usfc --apply web                  # готовый профиль
usfc --apply docker,nginx,ufw     # свои пункты
usfc --apply all --dry-run        # показать, что было бы сделано
usfc --config /etc/usfc.conf      # ответы на вопросы из файла
usfc --list                       # какие есть профили и id

Профили: minimal, web, dockerhost, secure. Коды возврата пригодны для CI: 0 — применилось, 1 — часть пунктов упала, 2 — не разобрали, что применять.

Конфиг разбирается построчно, а не через source: --config из непроверенного места не должен уметь запускать команды.

ITEMS=web
NGINX_AUTOSTART=Y
DOCKER_AUTOSTART=N
ZRAM_PERCENT=75
SWAP_MB=2048

SSH hardening в неинтерактивном режиме пропускается — с явным сообщением. Закрыть себе доступ к серверу по чужому конфигу не та цена, которую стоит платить за автоматизацию. Настраивается отдельно, из меню.

Повторный запуск — честный no-op. Уже применённые пункты пропускаются. Это не оптимизация, а вопрос смысла: в меню повторный выбор -пункта означает «переключить», и без этой проверки --apply из cloud-init выключал бы то, что просили включить.

Сухой прогон

--dry-run показывает, что было бы сделано, и не меняет систему. Перехват стоит не в отдельных функциях, а на уровне самих команд: usermod, install, chmod, systemctl, swapon и прочие подменяются на время прогона, а записи в системные файлы идут через одну общую точку. Читающие вызовы (systemctl is-active, sed без -i) пропускаются наружу — без них прогон врал бы уже про текущее состояние.

Полнота проверяется не глазами, а тестом: слепок системы до и после --apply all --dry-run обязан совпасть.

Снимки конфигов и откат

Перед тем как переписать любой системный файл, скрипт кладёт его копию в /var/backups/usfc/<метка>:

usfc --backups                    # что есть
usfc --restore 20260810-1021-4242 # вернуть как было

Снимок делается автоматически и только для файлов, которые правит сам скрипт: sshd_config.d/10-hardening.conf, fstab, daemon.json, 20auto-upgrades, 99-zram.conf, zramswap, .bashrc и остальные. Перед восстановлением снимается ещё один снимок — откат отката тоже должен быть возможен.

Язык интерфейса

При первом запуске скрипт спрашивает язык на двух сразу — на этом шаге ещё неизвестно, какой из них понятен:

Язык интерфейса  /  Interface language
  1) Русский
  2) English
Выбор / Choice [1]:

Выбор запоминается и переживает обновление. Сменить потом — клавиша L в меню. Флаг --lang en работает разово и ничего не сохраняет: одиночный запуск на другом языке не должен молча переучивать инструмент.

Кастомизация

src/config.jsonc для fastfetch — редактируешь и коммитишь, src/setup.sh тянет его по сырой ссылке при каждом запуске.

Свой форк — переменная окружения USFC_REPO_RAW_BASE подменяет источник обновлений и модулей, править код для этого не нужно. Версия проверяется через отдельный файл src/VERSION.

Как устроен код

С версии 4.0.0 это не один файл, а точка входа плюс модули:

src/setup.sh        загрузчик: bootstrap, самолечение, подключение модулей
src/MODULES         манифест — он же порядок загрузки и порядок пунктов меню
src/lib/*.sh        ядро по слоям: лог, разметка, apt, обновление, аудит…
src/lib/items/*.sh  по одному файлу на пункт меню

Добавить пункт — это один новый файл в src/lib/items/ и строка в MODULES. Пункт сам себя регистрирует, поэтому синхронизировать шесть параллельных массивов, как раньше, больше не нужно:

usfc_item docker сервисы "Docker + Compose" "Docker CE + Compose из официального репозитория" \
    "Docker + Compose" "Docker CE + Compose from the official repository"
usfc_item_toggle docker
usfc_item_full docker "полное описание" "full description"
usfc_item_rollback docker "команды удаления" "removal commands"

status_docker()  { ...; }
apply_docker()   { ...; }
disable_docker() { ...; }

Английский вариант необязателен: пока его нет, показывается русский.

FAQ

Иконки/шрифты в терминале выглядят как квадратики или кракозябры

Это шрифт твоего локального терминала (клиента), не сервера — Nerd Font для иконок eza/starship/fastfetch ставится и настраивается в приложении, через которое ты подключаешься по SSH, скрипт на это никак повлиять не может.

Docker не ставится, ошибка про кодовое имя дистрибутива

Официальный репозиторий Docker иногда отстаёт от свежих релизов Ubuntu — скрипт сам это ловит и переключается на совместимый noble. На Debian такого переключения нет намеренно: noble там чужая ветка репозитория, собранная под другие версии библиотек, и пункт честно останавливается вместо того, чтобы поставить заведомо неподходящие пакеты.

Что не работает на Debian

Почти всё работает. Отличия ровно два, и оба проверены на живых образах:

  • Debian 12 (bookworm) — в репозиториях нет eza и fastfetch. eza просто не попадает в набор CLI-утилит, а алиасы ls/ll/la/lt не пишутся в .bashrc (иначе они сломали бы ls). Пункт fastfetch объясняет, что пакета нет, и предлагает .deb с GitHub.
  • Debian 13 (trixie) — есть всё, кроме software-properties-common, который нужен только для PPA, то есть только на Ubuntu.
Хочу пересмотреть SSH hardening или UFW без пересоздания сервера

usfc ещё раз — на уже настроенных пунктах меню покажет текущее состояние и спросит, менять ли.

Contributing

Делался в первую очередь под свои сервера, так что часть решений — это то, что удобно мне. Баги и пожелания приветствуются — открывай issue.

Лицензия

MIT

About

Menu-driven Bash installer that turns a fresh Ubuntu 24.04/26.04 VPS into a configured server: CLI tools, Docker, nginx, zram/swap, fail2ban, SSH & UFW hardening.

Topics

Resources

Stars

9 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages