#!/usr/bin/env bash set -euo pipefail LOG_FILE=/var/log/core_setup.log exec > >(tee -a "$LOG_FILE") 2>&1 log() { echo "[$(date +'%Y-%m-%d %H:%M:%S')] $*" } SUMMARY=() run() { local desc="$1" shift log "$desc" if "$@"; then log "OK: $desc" SUMMARY+=("$desc: OK") else local rc=$? log "ERROR: $desc (code $rc)" SUMMARY+=("$desc: ERROR") exit $rc fi } print_summary() { echo "\n==== Итоговая сводка ====" for item in "${SUMMARY[@]}"; do echo "$item" done } cleanup() { local rc=$? if [[ $rc -ne 0 ]]; then log "Скрипт завершился с ошибкой (код $rc)" else log "Скрипт завершился успешно" fi print_summary } trap 'log "Ошибка (код $?) на строке $LINENO"' ERR trap cleanup EXIT usage() { cat <&2 exit 1 fi install_packages() { run "Updating package index" apt-get update -y run "Installing base packages" apt-get install -y sudo curl wget git ufw logrotate unattended-upgrades ca-certificates gnupg lsb-release apt-transport-https } setup_timezone() { run "Setting timezone to Europe/Moscow" timedatectl set-timezone Europe/Moscow } setup_unattended_upgrades() { run "Configuring unattended upgrades" bash -c "cat >/etc/apt/apt.conf.d/20auto-upgrades <<'EOF' APT::Periodic::Update-Package-Lists \"1\"; APT::Periodic::Download-Upgradeable-Packages \"1\"; APT::Periodic::AutocleanInterval \"7\"; APT::Periodic::Unattended-Upgrade \"1\"; EOF" run "Enabling unattended upgrades" systemctl enable --now unattended-upgrades.service } create_user() { run "Creating user $USERNAME" bash -c "id '$USERNAME' >/dev/null 2>&1 || adduser --disabled-password --gecos '' '$USERNAME'" run "Granting sudo privileges to $USERNAME" bash -c "usermod -aG sudo '$USERNAME' && printf '%s ALL=(ALL) NOPASSWD:ALL\\n' '$USERNAME' >/etc/sudoers.d/90-$USERNAME" } configure_ssh() { run "Configuring SSH access" bash -c "install -d -m 700 /home/$USERNAME/.ssh && cat >/home/$USERNAME/.ssh/authorized_keys <<'KEY' $SSH_KEY KEY chmod 600 /home/$USERNAME/.ssh/authorized_keys && chown -R '$USERNAME':'$USERNAME' /home/$USERNAME/.ssh && sed -i 's/^#\\?PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config && sed -i 's/^#\\?PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config && systemctl restart sshd" run "Checking SSH configuration" bash -c "sshd -T | grep -q '^passwordauthentication no' && sshd -T | grep -q '^permitrootlogin no'" } configure_ufw() { run "Resetting UFW" ufw --force reset run "Setting UFW defaults" bash -c "ufw default deny incoming && ufw default allow outgoing" run "Allow HTTPS" ufw allow 443/tcp comment 'HTTPS' if [[ -n "$SSH_ALLOWED_IP" ]]; then run "Allow SSH from $SSH_ALLOWED_IP" ufw allow from "$SSH_ALLOWED_IP" to any port 22 proto tcp comment 'SSH' else run "Allow SSH from anywhere" ufw allow 22/tcp comment 'SSH' fi if [[ -n "$MONITOR_IP" ]]; then run "Allow Beszel from $MONITOR_IP" ufw allow from "$MONITOR_IP" to any port 45876 proto tcp comment 'Beszel monitoring' fi if [[ -n "$NETBIRD_KEY" && -n "$NETBIRD_IP" && -n "$NETBIRD_PORT" ]]; then run "Allow Netbird central from $NETBIRD_IP:$NETBIRD_PORT" ufw allow from "$NETBIRD_IP" to any port "$NETBIRD_PORT" proto tcp comment 'Netbird central' fi run "Enable UFW" ufw --force enable run "Checking UFW active" bash -c "ufw status | grep -q 'Status: active'" run "Checking UFW SSH rule" bash -c "ufw status | grep -q '22/tcp'" run "Checking UFW HTTPS rule" bash -c "ufw status | grep -q '443/tcp'" if [[ -n "$MONITOR_IP" ]]; then run "Checking UFW Beszel rule" bash -c "ufw status | grep -q '45876/tcp'" fi if [[ -n "$NETBIRD_KEY" && -n "$NETBIRD_IP" && -n "$NETBIRD_PORT" ]]; then run "Checking UFW Netbird rule" bash -c "ufw status | grep -q '$NETBIRD_PORT/tcp'" fi } install_docker() { if ! command -v docker >/dev/null 2>&1; then run "Installing Docker" bash -c "install -m 0755 -d /etc/apt/keyrings && curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg && echo 'deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable' | tee /etc/apt/sources.list.d/docker.list >/dev/null && apt-get update -y && apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin" fi run "Adding $USERNAME to docker group" usermod -aG docker "$USERNAME" run "Checking Docker service" systemctl is-active --quiet docker run "Checking Docker CLI" docker --version run "Checking docker compose" docker compose version run "Checking docker ps" docker ps >/dev/null } configure_fail2ban() { run "Installing fail2ban" apt-get install -y fail2ban run "Configuring fail2ban" bash -c "cat >/etc/fail2ban/jail.local <<'EOF' [sshd] enabled = true bantime = 10m findtime = 10m maxretry = 3 EOF" run "Enabling fail2ban" systemctl enable --now fail2ban } configure_logrotate() { run "Configuring logrotate for Docker logs" bash -c "cat >/etc/logrotate.d/docker <<'EOF' /var/lib/docker/containers/*/*.log { rotate 7 daily compress missingok delaycompress copytruncate } EOF" } install_netbird() { [[ -z "$NETBIRD_KEY" ]] && return run "Installing Netbird" bash -c "curl -fsSL https://pkgs.netbird.io/install.sh | sh" run "Starting Netbird" netbird up --setup-key "$NETBIRD_KEY" run "Checking Netbird service" systemctl is-active --quiet netbird run "Checking Netbird connection" bash -c "netbird status | grep -qi 'connected'" } setup_vector() { [[ -z "$VECTOR_ENDPOINT" ]] && return if ! command -v vector >/dev/null 2>&1; then run "Installing Vector" bash -c "curl -1sLf 'https://repositories.timber.io/public/vector/cfg/setup/bash.deb.sh' | bash && apt-get install -y vector" fi run "Configuring Vector" bash -c "cat >/etc/vector/vector.toml <<'EOF' [sources.syslog] type = 'file' include = ['/var/log/*.log'] [sources.docker] type = 'docker_logs' [sinks.out] type = 'http' inputs = ['syslog', 'docker'] uri = '$VECTOR_ENDPOINT' encoding.codec = 'json' EOF" run "Enabling Vector" systemctl enable --now vector run "Checking Vector service" systemctl is-active --quiet vector } setup_compose() { [[ -z "$COMPOSE_URL" ]] && return run "Creating directory $COMPOSE_DIR" mkdir -p "$COMPOSE_DIR" run "Downloading compose file" curl -fsSL "$COMPOSE_URL" -o "$COMPOSE_DIR/docker-compose.yml" run "Setting ownership for compose dir" chown -R "$USERNAME:$USERNAME" "$COMPOSE_DIR" run "Starting docker compose" bash -c "cd '$COMPOSE_DIR' && docker compose up -d" } main() { install_packages setup_timezone setup_unattended_upgrades create_user configure_ssh configure_ufw install_docker configure_fail2ban configure_logrotate install_netbird setup_vector setup_compose } main