Добавить скрипты первичной инициализации, очистки и автозапуска (BBox)

This commit is contained in:
NW
2026-08-07 14:58:14 +01:00
parent 79f6c425e5
commit 5606fb0563
5 changed files with 553 additions and 0 deletions

View File

@@ -2,6 +2,8 @@
Автоматический скрипт для настройки VPS с базовыми инструментами, Docker-окружением и расширенными возможностями.
> Часть экосистемы **BBox (bbox.wtf)** — «Свободные люди для свободного мира, во имя приватности и безопасности».
## Что устанавливается
- 🛠️ **Системные утилиты**:
@@ -15,6 +17,48 @@
- 🔗 **Клонирование репозитория** [opendoor-base-install](https://git.softuniq.eu/OpenDoor/opendoor-base-install)
- 📂 **Копирование файлов из папки `tmux`** в `/root/`
## Скрипты репозитория
| Скрипт | Назначение |
|--------|-----------|
| `setup_vps.sh` | Основная настройка VPS: утилиты, Docker, dry, btop, tmux |
| `init_system.sh` | Первичная инициализация устройства (однократно после развёртывания): обновление, базовые утилиты, Docker, hostname, баннер BBox, сброс идентификаторов |
| `cleanup_system.sh` | Очистка и оптимизация: apt-кэш, логи, tmp, orphaned-пакеты, Docker-мусор; `--full` дополнительно удаляет Matrix/nginx и сбрасывает идентификаторы |
| `install_scripts.sh` | Установка скриптов в `/usr/local/bin` + сервис автозапуска `bbox-firstboot.service` |
### Первичная инициализация (`init_system.sh`)
Выполняется один раз на новом устройстве:
```bash
sudo ./init_system.sh
```
Что делает:
1. Обновляет систему и устанавливает базовые утилиты (tmux, mc, git, net-tools, curl, wget, build-essential, btop)
2. Устанавливает Docker + Docker Compose
3. Настраивает hostname (по умолчанию `bbox-node`)
4. Обновляет баннер входа: **BBox v1.2 (bbox.wtf)** с подписью «Created by free people for a free world»
5. Сбрасывает machine-id и SSH host keys (для уникальности клонированных образов)
6. Вызывает `install_scripts.sh` для установки автозапуска
### Очистка системы (`cleanup_system.sh`)
```bash
sudo ./cleanup_system.sh # стандартная очистка
sudo ./cleanup_system.sh --dry-run # показать, что будет очищено
sudo ./cleanup_system.sh --full # + удаление Matrix/nginx, сброс идентификаторов
```
### Автозапуск (firstboot)
`install_scripts.sh` создаёт systemd-сервис `bbox-firstboot.service`, который при **первой** загрузке устройства автоматически выполняет инициализацию. Повторный запуск блокируется маркером `/var/lib/bbox-firstboot-done`.
```bash
sudo ./install_scripts.sh # установить скрипты + автозапуск
systemctl status bbox-firstboot.service # статус автозапуска
```
## Особенности
- 🔧 **Гибкая установка tmux**:

194
cleanup_system.sh Executable file
View File

@@ -0,0 +1,194 @@
#!/bin/bash
# ============================================================================
# cleanup_system.sh — очистка и оптимизация системы (BBox / OpenDoor base)
# ----------------------------------------------------------------------------
# Безопасная очистка от мусора и подготовка устройства к клонированию образа:
# * apt-кэш и списки пакетов
# * логи (journald, /var/log, /var/log.hdd)
# * tmp-директории и кэши пользователей
# * orphaned-пакеты (autoremove)
# * тестовые Docker-образы/контейнеры
# * удаление следов Matrix/coturn/nginx (если были установлены)
# * освобождение места в /boot
# ============================================================================
set -uo pipefail
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
DRY_RUN=0
LOG_FILE="/var/log/bbox-cleanup.log"
log() { echo -e "${GREEN}[cleanup]${NC} $*" | tee -a "$LOG_FILE"; }
warn() { echo -e "${YELLOW}[cleanup][warn]${NC} $*" | tee -a "$LOG_FILE"; }
fail() { echo -e "${RED}[cleanup][error]${NC} $*" | tee -a "$LOG_FILE"; exit 1; }
usage() {
cat <<EOF
Использование: $0 [--dry-run] [--full]
--dry-run только показать, что будет очищено (ничего не удалять)
--full полная очистка (включая удаление Matrix/nginx, сброс идентификаторов)
-h, --help показать справку
EOF
}
# ---------------------------------------------------------------------------
# Сбор данных о занимаемом месте
# ---------------------------------------------------------------------------
size_of() {
du -sh "$1" 2>/dev/null | awk '{print $1}' || echo "0"
}
report() {
echo
echo "=== Текущее состояние ==="
echo " Диск: $(df -h / | tail -1 | awk '{print $3" занято из "$2", свободно "$4}')"
echo " apt-кэш: $(size_of /var/cache/apt)"
echo " apt-lists: $(size_of /var/lib/apt/lists)"
echo " /var/log: $(size_of /var/log)"
echo " journald: $(journalctl --disk-usage 2>/dev/null | tail -1)"
echo " /tmp: $(size_of /tmp)"
}
# ---------------------------------------------------------------------------
# 1. Apt-кэш и списки
# ---------------------------------------------------------------------------
clean_apt() {
log "Очистка apt-кэша..."
[ $DRY_RUN -eq 1 ] && { warn "dry-run: apt-get clean/autoclean"; return; }
apt-get clean
apt-get autoclean -y
log "Удаление кэшей индексов apt (пересоздадутся автоматически)..."
rm -f /var/cache/apt/pkgcache.bin /var/cache/apt/srcpkgcache.bin
rm -rf /var/lib/apt/lists/*
}
# ---------------------------------------------------------------------------
# 2. Логи
# ---------------------------------------------------------------------------
clean_logs() {
log "Очистка journald (ограничение до 20M)..."
[ $DRY_RUN -eq 1 ] && { warn "dry-run: journalctl --vacuum-size"; return; }
journalctl --vacuum-size=20M 2>/dev/null || warn "journalctl недоступен"
log "Удаление старых ротированных логов..."
[ $DRY_RUN -eq 1 ] && { warn "dry-run: удаление *.gz/*.old/*.1 в /var/log"; return; }
find /var/log -type f \( -name "*.gz" -o -name "*.1" -o -name "*.old" \) -delete 2>/dev/null
find /var/log.hdd -type f \( -name "*.gz" -o -name "*.1" -o -name "*.old" \) -delete 2>/dev/null
# Логи sysstat (если пакет удалён — остаются файлы)
rm -rf /var/log/sysstat /var/log.hdd/sysstat
}
# ---------------------------------------------------------------------------
# 3. TMP и кэши
# ---------------------------------------------------------------------------
clean_tmp() {
log "Очистка временных директорий и кэшей..."
[ $DRY_RUN -eq 1 ] && { warn "dry-run: очистка /tmp, /var/tmp, /root/.cache"; return; }
rm -rf /tmp/* /var/tmp/* 2>/dev/null
find /root/.cache /root/.npm /root/.cargo /root/.local/share/Trash -mindepth 1 -delete 2>/dev/null
find /home -maxdepth 3 -type d -name ".cache" -exec rm -rf {} + 2>/dev/null
}
# ---------------------------------------------------------------------------
# 4. Orphaned-пакеты
# ---------------------------------------------------------------------------
clean_autoremove() {
log "Удаление неиспользуемых (orphaned) пакетов..."
[ $DRY_RUN -eq 1 ] && { warn "dry-run: apt-get autoremove"; return; }
apt-get autoremove -y --purge 2>/dev/null || warn "autoremove завершился с ошибкой"
}
# ---------------------------------------------------------------------------
# 5. Docker-мусор (образы/контейнеры/тома, не используемые)
# ---------------------------------------------------------------------------
clean_docker() {
if ! command -v docker &> /dev/null; then
log "Docker не установлен, пропуск."
return
fi
log "Очистка Docker (dangling-образы, остановленные контейнеры, неиспользуемые сети)..."
[ $DRY_RUN -eq 1 ] && { warn "dry-run: docker system prune -f"; return; }
docker system prune -f 2>/dev/null || warn "docker prune завершился с ошибкой"
}
# ---------------------------------------------------------------------------
# 6. Удаление следов Matrix/coturn/nginx (для чистого образа)
# ---------------------------------------------------------------------------
clean_matrix() {
local pkgs=()
for p in coturn nginx nginx-core nginx-common certbot; do
if dpkg -l "$p" &>/dev/null; then pkgs+=("$p"); fi
done
if [ ${#pkgs[@]} -eq 0 ]; then
log "Следов Matrix/coturn/nginx нет, пропуск."
return
fi
log "Удаление пакетов Matrix/nginx: ${pkgs[*]}..."
[ $DRY_RUN -eq 1 ] && { warn "dry-run: удаление ${pkgs[*]} и их конфигов"; return; }
DEBIAN_FRONTEND=noninteractive apt-get purge -y "${pkgs[@]}"
rm -rf /etc/nginx /etc/letsencrypt /etc/turnserver.conf /etc/coturn /var/www 2>/dev/null
rm -f /etc/cron.d/certbot 2>/dev/null
log "Следы Matrix/nginx удалены."
}
# ---------------------------------------------------------------------------
# 7. Сброс уникальных идентификаторов (перед клонированием)
# ---------------------------------------------------------------------------
reset_ids() {
log "Сброс machine-id и SSH host keys..."
[ $DRY_RUN -eq 1 ] && { warn "dry-run: сброс machine-id/ssh keys"; return; }
rm -f /etc/machine-id /var/lib/dbus/machine-id
systemd-machine-id-setup 2>/dev/null || warn "machine-id не пересоздан"
rm -f /etc/ssh/ssh_host_*
# Примечание: после этого нужно перезапустить ssh или перезагрузиться,
# чтобы sshd сгенерировал новые ключи.
}
# ---------------------------------------------------------------------------
# MAIN
# ---------------------------------------------------------------------------
main() {
while [ $# -gt 0 ]; do
case "$1" in
--dry-run) DRY_RUN=1 ;;
--full) FULL=1 ;;
-h|--help) usage; exit 0 ;;
*) fail "Неизвестный аргумент: $1" ;;
esac
shift
done
if [ "$(id -u)" -ne 0 ]; then
fail "Запустите скрипт от root: sudo ./cleanup_system.sh"
fi
touch "$LOG_FILE"
log "=== Очистка системы начата $(date) ==="
report
clean_apt
clean_logs
clean_tmp
clean_autoremove
clean_docker
if [ "${FULL:-0}" -eq 1 ]; then
clean_matrix
reset_ids
fi
echo
report
log "Очистка завершена. Журнал: $LOG_FILE"
if [ $DRY_RUN -eq 1 ]; then
warn "Это был dry-run — ничего не удалено. Запустите без --dry-run для применения."
fi
}
main "$@"

226
init_system.sh Executable file
View File

@@ -0,0 +1,226 @@
#!/bin/bash
# ============================================================================
# init_system.sh — первичная инициализация системы (BBox / OpenDoor base)
# ----------------------------------------------------------------------------
# Выполняется ОДИН раз после развёртывания образа на новом устройстве:
# * обновление пакетов
# * установка базовых утилит (tmux, mc, git, net-tools, curl, wget, btop)
# * установка Docker + Docker Compose
# * настройка hostname и баннера BBox (bbox.wtf)
# * сброс уникальных идентификаторов (machine-id, SSH host keys)
# * установка вспомогательных скриптов и автозапуска
#
# Безопасно повторять: повторный запуск пропускает уже выполненные шаги.
# ============================================================================
set -euo pipefail
# Цвета
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
BBOX_VERSION="1.2"
BBOX_URL="bbox.wtf"
HOSTNAME_DEFAULT="bbox-node"
log() { echo -e "${GREEN}[init]${NC} $*"; }
warn() { echo -e "${YELLOW}[init][warn]${NC} $*"; }
fail() { echo -e "${RED}[init][error]${NC} $*"; exit 1; }
# ---------------------------------------------------------------------------
# 1. Определение дистрибутива и архитектуры
# ---------------------------------------------------------------------------
detect_distro() {
if [ -f /etc/os-release ]; then
. /etc/os-release
DISTRO=$ID
VERSION_CODENAME=$VERSION_CODENAME
else
fail "Не удалось определить дистрибутив."
fi
ARCH=$(uname -m)
log "Дистрибутив: $DISTRO ($VERSION_CODENAME), архитектура: $ARCH"
}
check_install() {
if command -v "$1" &> /dev/null; then
log "$1 уже установлен."
else
log "Установка $1..."
if ! apt-get install -y "$1" &> /dev/null; then
fail "Ошибка при установке $1."
fi
log "$1 установлен."
fi
}
# ---------------------------------------------------------------------------
# 2. Обновление системы
# ---------------------------------------------------------------------------
update_system() {
log "Обновление списков пакетов..."
apt-get update || fail "Ошибка apt-get update"
apt-get upgrade -y || warn "apt-get upgrade завершился с предупреждениями"
}
# ---------------------------------------------------------------------------
# 3. Установка базовых утилит
# ---------------------------------------------------------------------------
install_base_utils() {
log "Установка базовых утилит..."
check_install tmux
check_install mc
check_install git
check_install net-tools
check_install curl
check_install wget
check_install build-essential
check_install btop
}
# ---------------------------------------------------------------------------
# 4. Установка Docker
# ---------------------------------------------------------------------------
install_docker() {
if command -v docker &> /dev/null; then
log "Docker уже установлен."
return
fi
log "Установка Docker для $DISTRO..."
apt-get install -y apt-transport-https ca-certificates curl gnupg
mkdir -p /etc/apt/keyrings
curl -fsSL "https://download.docker.com/linux/$DISTRO/gpg" | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
chmod a+r /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/$DISTRO $VERSION_CODENAME stable" \
> /etc/apt/sources.list.d/docker.list
apt-get update
if ! apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin; then
warn "Официальный репозиторий не подошёл, пробуем docker.io..."
apt-get install -y docker.io docker-compose-plugin || fail "Не удалось установить Docker."
fi
systemctl enable --now docker
log "Docker установлен: $(docker --version)"
}
# ---------------------------------------------------------------------------
# 5. Настройка hostname
# ---------------------------------------------------------------------------
setup_hostname() {
local NEW_HOSTNAME="${HOSTNAME:-$HOSTNAME_DEFAULT}"
local CUR_HOSTNAME
CUR_HOSTNAME=$(hostname)
if [ "$CUR_HOSTNAME" != "$NEW_HOSTNAME" ]; then
log "Смена hostname: $CUR_HOSTNAME -> $NEW_HOSTNAME"
hostnamectl set-hostname "$NEW_HOSTNAME" || warn "Не удалось сменить hostname"
echo "$NEW_HOSTNAME" > /etc/hostname
else
log "Hostname уже установлен: $CUR_HOSTNAME"
fi
}
# ---------------------------------------------------------------------------
# 6. Баннер BBox (MOTD)
# ---------------------------------------------------------------------------
setup_motd() {
local HEADER="/etc/update-motd.d/10-armbian-header"
if [ -f "$HEADER" ] && ! grep -q "BBox" "$HEADER"; then
log "Обновление баннера входа: BBox v${BBOX_VERSION} ($BBOX_URL)"
cp "$HEADER" "${HEADER}.bak"
# ASCII-баннер
sed -i 's|figlet -f small " $VENDOR"|figlet -f small " BBox"|' "$HEADER"
# Строка версии + подпись
sed -i 's|running Armbian Linux \\e\[0;92m\${KERNELID\^}\\x1B\[0m|running \\e[0;92m${KERNELID^}\\x1B[0m, built on Armbian Linux|' "$HEADER"
# Вставка строки версии/подписи после строки баннера figlet
if ! grep -q "bbox.wtf v" "$HEADER"; then
sed -i "/figlet -f small \" BBox\"/a echo -e \" \\\\e[0;92mv${BBOX_VERSION}\\\\x1B[0m ${BBOX_URL} on \$BOARD_NAME\"\necho -e \" \\\\e[0;36mCreated by free people for a free world, in the name of privacy and security.\\\\x1B[0m\"" "$HEADER"
fi
log "Баннер обновлён."
else
log "Баннер BBox уже установлен или скрипт не найден."
fi
}
# ---------------------------------------------------------------------------
# 7. Сброс уникальных идентификаторов (для клонированных образов)
# ---------------------------------------------------------------------------
reset_unique_ids() {
log "Сброс machine-id..."
rm -f /etc/machine-id /var/lib/dbus/machine-id
systemd-machine-id-setup || warn "Не удалось пересоздать machine-id"
log "Сброс SSH host keys (будут пересозданы при старте sshd)..."
rm -f /etc/ssh/ssh_host_*
systemctl restart ssh || systemctl restart sshd || warn "SSH будет перезапущен при перезагрузке"
}
# ---------------------------------------------------------------------------
# 8. Установка вспомогательных скриптов и автозапуска
# ---------------------------------------------------------------------------
install_helper_scripts() {
local SRC_DIR
SRC_DIR=$(dirname "$(readlink -f "$0")")
if [ -x "$SRC_DIR/install_scripts.sh" ]; then
log "Установка вспомогательных скриптов..."
"$SRC_DIR/install_scripts.sh" || warn "install_scripts.sh завершился с ошибкой"
else
warn "install_scripts.sh не найден рядом ($SRC_DIR), пропуск."
fi
}
# ---------------------------------------------------------------------------
# MAIN
# ---------------------------------------------------------------------------
FIRSTBOOT=0
FIRSTBOOT_MARKER="/var/lib/bbox-firstboot-done"
main() {
if [ "$(id -u)" -ne 0 ]; then
fail "Запустите скрипт от root: sudo ./init_system.sh"
fi
# --firstboot: режим автозапуска (из bbox-firstboot.service)
if [ "${1:-}" = "--firstboot" ]; then
FIRSTBOOT=1
log "Режим firstboot (автозапуск при первой загрузке)"
if [ -f "$FIRSTBOOT_MARKER" ]; then
log "Инициализация уже выполнялась, пропуск."
exit 0
fi
fi
log "=== BBox (bbox.wtf) v${BBOX_VERSION} — первичная инициализация ==="
detect_distro
update_system
install_base_utils
install_docker
setup_hostname
setup_motd
if [ $FIRSTBOOT -eq 1 ]; then
# При автозапуске не трогаем ssh/machine-id до перезагрузки
warn "Режим firstboot: сброс идентификаторов выполняется при следующем запуске"
touch "$FIRSTBOOT_MARKER"
else
reset_unique_ids
fi
install_helper_scripts
log "Инициализация завершена."
if [ $FIRSTBOOT -eq 1 ]; then
log "Сервис автозапуска завершён. Перезагрузка не требуется."
else
echo
echo "Рекомендуется перезагрузить устройство: reboot"
fi
}
main "$@"

89
install_scripts.sh Executable file
View File

@@ -0,0 +1,89 @@
#!/bin/bash
# ============================================================================
# install_scripts.sh — установка первичных скриптов в систему
# ----------------------------------------------------------------------------
# Копирует скрипты этого репозитория в /usr/local/bin и настраивает
# автозапуск:
# * /usr/local/bin/init-system -> первичная инициализация (ручной запуск)
# * /usr/local/bin/cleanup-system -> очистка системы (ручной запуск)
# * /etc/systemd/system/bbox-firstboot.service -> автозапуск при первой загрузке
# * /root/firstboot.log -> журнал автозапуска
# ============================================================================
set -euo pipefail
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
BIN_DIR="/usr/local/bin"
SERVICE_DIR="/etc/systemd/system"
MARKER="/var/lib/bbox-firstboot-done"
log() { echo -e "${GREEN}[install-scripts]${NC} $*"; }
warn() { echo -e "${YELLOW}[install-scripts][warn]${NC} $*"; }
fail() { echo -e "${RED}[install-scripts][error]${NC} $*"; exit 1; }
SCRIPT_SRC_DIR="$(cd "$(dirname "$(readlink -f "$0")")" && pwd)"
install_script() {
local src="$1" dst="$2"
if [ ! -f "$src" ]; then
warn "Не найден: $src"
return 1
fi
install -m 0755 "$src" "$dst"
log "Установлен: $dst"
}
install_firstboot_service() {
local unit="$SERVICE_DIR/bbox-firstboot.service"
cat > "$unit" <<EOF
[Unit]
Description=BBox first boot initialization (bbox.wtf)
After=network-online.target docker.service
Wants=network-online.target
ConditionPathExists=!/var/lib/bbox-firstboot-done
[Service]
Type=oneshot
ExecStart=/usr/local/bin/init-system --firstboot
RemainAfterExit=no
StandardOutput=journal+console
StandardError=journal+console
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable bbox-firstboot.service
log "Сервис автозапуска включён: $unit"
}
main() {
if [ "$(id -u)" -ne 0 ]; then
fail "Запустите скрипт от root: sudo ./install_scripts.sh"
fi
log "Установка скриптов из: $SCRIPT_SRC_DIR"
install_script "$SCRIPT_SRC_DIR/init_system.sh" "$BIN_DIR/init-system" || true
install_script "$SCRIPT_SRC_DIR/cleanup_system.sh" "$BIN_DIR/cleanup-system" || true
install_script "$SCRIPT_SRC_DIR/install_scripts.sh" "$BIN_DIR/install-bbox-scripts" || true
# tmux-конфиг
if [ -f "$SCRIPT_SRC_DIR/tmux/.tmux.conf" ]; then
install -m 0644 "$SCRIPT_SRC_DIR/tmux/.tmux.conf" /root/.tmux.conf
log "tmux-конфиг установлен в /root/.tmux.conf"
fi
install_firstboot_service
log "Готово. Запуск вручную:"
log " init-system — первичная инициализация"
log " cleanup-system — очистка системы"
log " systemctl start bbox-firstboot.service — запустить автозапуск сейчас"
}
main "$@"

0
setup_vps.sh Normal file → Executable file
View File