All checks were successful
CI Trade-In / changes (pull_request) Successful in 8s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI / changes (pull_request) Successful in 10s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
Сервер Poincare (SPB-4, 188.246.224.93) поднят 22.08.2026. Два скрипта под переезд (#2989, #3027-#3032). selectel-audit.sh — только чтение. Отвечает на вопрос, который надо закрыть до установки чего бы то ни было: собраны ли диски в зеркало. Переставить ОС можно только пока сервер пустой. Результат первого прогона: RAID1 на всех трёх разделах ([2/2] [UU] на /boot, swap и /), память non-ECC подтверждена (Error Correction Type: None), 910G свободно из 924G. selectel-bootstrap.sh — идемпотентная настройка: пользователь с ключом, ufw, Docker версий текущего прода (29.4.1 / v5.1.3), лимит журналов контейнеров, sysctl, unattended-upgrades, fail2ban, ужесточение sshd. Порядок шагов выбран так, чтобы не потерять доступ: правило для SSH добавляется ДО включения файрвола, а sshd в конце намеренно НЕ перезапускается — сначала проверяется вход по ключу в отдельном окне. При выключенном PasswordAuthentication ошибка означала бы IP-KVM за 1320 руб. Два умолчания выставлены по факту, а не по привычке: - часовой пояс Europe/Moscow, а не UTC — оба хоста сейчас на MSK, и смена пояса сдвинула бы все шесть cron-задач (бэкапы, геокодинг) на три часа; - swap не создаётся, если он уже есть — установщик Selectel отдаёт раздел 4.7G в зеркале, добавлять файл поверх незачем при 62G памяти. .gitattributes: *.sh с LF — иначе скрипт, отредактированный под Windows, падает на удалённом хосте с `$'\r': command not found`.
84 lines
4.1 KiB
Bash
84 lines
4.1 KiB
Bash
#!/usr/bin/env bash
|
||
# Аудит нового выделенного сервера ДО того, как на него что-либо поставлено.
|
||
#
|
||
# Только чтение — ничего не меняет. Задача одна: собрать факты, по которым
|
||
# принимается решение «работаем на этой установке» или «переставляем ОС».
|
||
#
|
||
# Главный вопрос — RAID. На AR32-NVMe два диска по 1 ТБ. Если они отданы
|
||
# по отдельности или собраны в RAID0, смерть одного диска = потеря всего,
|
||
# а память на этой платформе non-ECC. Переставить ОС можно только пока
|
||
# сервер пустой, поэтому проверка идёт первой и до всего остального.
|
||
#
|
||
# Запуск: ssh <host> 'bash -s' < ops/selectel-audit.sh
|
||
|
||
set -uo pipefail
|
||
|
||
section() { printf '\n=== %s ===\n' "$1"; }
|
||
|
||
section "Идентификация"
|
||
. /etc/os-release 2>/dev/null && echo "OS: ${PRETTY_NAME:-unknown}"
|
||
echo "Kernel: $(uname -r)"
|
||
echo "Hostname: $(hostname)"
|
||
echo "Uptime: $(uptime -p 2>/dev/null || true)"
|
||
|
||
section "CPU / память"
|
||
lscpu 2>/dev/null | grep -E '^(Model name|CPU\(s\)|Thread|Core|Socket|CPU max MHz)' || nproc
|
||
free -h | head -2
|
||
echo "--- ECC (пусто = не-ECC либо недоступно из ОС) ---"
|
||
dmidecode -t memory 2>/dev/null | grep -iE 'error correction|^\s+Type:' | sort -u | head -5 \
|
||
|| echo "dmidecode недоступен (нужен root)"
|
||
|
||
section "ДИСКИ — ключевой вопрос"
|
||
lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINT,MODEL
|
||
echo "--- программный RAID ---"
|
||
if [ -f /proc/mdstat ]; then cat /proc/mdstat; else echo "/proc/mdstat отсутствует"; fi
|
||
echo "--- аппаратный RAID / NVMe ---"
|
||
lspci 2>/dev/null | grep -iE 'raid|nvme' || echo "контроллеров RAID не видно"
|
||
nvme list 2>/dev/null || echo "nvme-cli не установлен"
|
||
echo "--- LVM ---"
|
||
pvs 2>/dev/null; vgs 2>/dev/null; lvs 2>/dev/null
|
||
echo "--- монтирование ---"
|
||
df -hT -x tmpfs -x devtmpfs
|
||
|
||
echo
|
||
echo ">>> ВЕРДИКТ ПО ДИСКАМ читать так:"
|
||
echo ">>> raid1 / mirror в mdstat → зеркало есть, можно работать"
|
||
echo ">>> raid0 / linear / дисков нет → зеркала НЕТ, переставить ОС до установки чего-либо"
|
||
echo ">>> один диск в df, второй пуст → второй не используется, решить как задействовать"
|
||
|
||
section "Сеть"
|
||
ip -brief addr show | grep -v '^lo'
|
||
ip route | head -5
|
||
echo "--- DNS ---"
|
||
grep -E '^nameserver' /etc/resolv.conf 2>/dev/null | head -3
|
||
|
||
section "Что уже слушает"
|
||
ss -tulpn 2>/dev/null | grep LISTEN || netstat -tulpn 2>/dev/null | grep LISTEN
|
||
|
||
section "Безопасность — текущее состояние"
|
||
echo "--- sshd (значимые директивы) ---"
|
||
sshd -T 2>/dev/null | grep -E '^(permitrootlogin|passwordauthentication|pubkeyauthentication|port|permitemptypasswords)' \
|
||
|| grep -E '^\s*(PermitRootLogin|PasswordAuthentication|Port)' /etc/ssh/sshd_config /etc/ssh/sshd_config.d/* 2>/dev/null
|
||
echo "--- файрвол ---"
|
||
ufw status 2>/dev/null || echo "ufw не установлен"
|
||
nft list ruleset 2>/dev/null | head -20 || iptables -S 2>/dev/null | head -20
|
||
echo "--- пользователи с shell ---"
|
||
awk -F: '$7 !~ /(nologin|false)$/ {print $1" "$7}' /etc/passwd
|
||
|
||
section "Swap / sysctl"
|
||
swapon --show || echo "swap отсутствует"
|
||
sysctl vm.swappiness vm.overcommit_memory 2>/dev/null
|
||
|
||
section "Уже установленное ПО"
|
||
for b in docker containerd git curl ufw fail2ban-server unattended-upgrade; do
|
||
if command -v "$b" >/dev/null 2>&1; then
|
||
printf '%-22s %s\n' "$b" "$($b --version 2>/dev/null | head -1)"
|
||
else
|
||
printf '%-22s %s\n' "$b" "НЕ установлен"
|
||
fi
|
||
done
|
||
|
||
section "Время"
|
||
timedatectl 2>/dev/null | head -5 || date
|
||
|
||
printf '\n=== Аудит закончен ===\n'
|