commit ba4b395a4a5e129b1a33473ba3f23142aa034e5d Author: Эльнар Date: Sat Mar 21 16:07:57 2026 +0400 Add server setup scripts (manual + cloud-init) Two deployment options for recreating the kirgysia server: - manual-setup/: bash script for manual server provisioning - cloud-init/: cloud-init config + data upload script for automated VPS setup Co-Authored-By: Claude Opus 4.6 (1M context) diff --git a/server-setup/.gitignore b/server-setup/.gitignore new file mode 100644 index 0000000..8fce603 --- /dev/null +++ b/server-setup/.gitignore @@ -0,0 +1 @@ +data/ diff --git a/server-setup/cloud-init/README.md b/server-setup/cloud-init/README.md new file mode 100644 index 0000000..2d1e45b --- /dev/null +++ b/server-setup/cloud-init/README.md @@ -0,0 +1,56 @@ +# Cloud-init настройка сервера + +Автоматическая настройка VPS через cloud-init. Два шага: создать сервер с конфигом, затем загрузить данные. + +## Шаг 1: Создание сервера + +При создании VPS у хостера (Hetzner, Vultr, DigitalOcean и т.д.) вставьте содержимое `cloud-init.yml` в поле **User Data** / **Cloud-Init**. + +- Выберите Ubuntu 22.04 LTS +- Вставьте содержимое `cloud-init.yml` +- Создайте сервер + +Cloud-init автоматически: +- Обновит систему и поставит пакеты +- Создаст пользователя `eberkheev` с sudo и SSH-ключом +- Настроит SSH на порт 10001 (только ключи, root запрещён) +- Подготовит Docker и скачает образ 3x-ui +- Создаст docker-compose.yml и update.sh + +Подождите 3-5 минут после создания сервера, пока cloud-init завершится. + +## Шаг 2: Загрузка данных + +После того как сервер создался, запустите с локальной машины: + +```bash +bash upload-data.sh IP_СЕРВЕРА +``` + +Скрипт загрузит на сервер: +- базу данных `x-ui.db` из `../data/` +- SSL-сертификаты из `../data/` + +И запустит контейнер 3x-ui. + +## После установки + +Подключение: +```bash +ssh -p 10001 eberkheev@IP_СЕРВЕРА +``` + +Панель 3x-ui: +``` +https://IP_СЕРВЕРА:10002 +``` + +Проверка контейнера: +```bash +docker ps +``` + +Обновление: +```bash +bash ~/update.sh +``` diff --git a/server-setup/cloud-init/cloud-init.yml b/server-setup/cloud-init/cloud-init.yml new file mode 100644 index 0000000..ba2e5e3 --- /dev/null +++ b/server-setup/cloud-init/cloud-init.yml @@ -0,0 +1,169 @@ +#cloud-config +# +# Cloud-init конфиг для воссоздания сервера kirgysia +# Ubuntu 22.04 LTS +# +# Использование: +# Вставить содержимое этого файла в поле "User Data" / "Cloud-Init" +# при создании VPS у хостера (Hetzner, Vultr, DO и т.д.) +# +# После создания сервера запустить upload-data.sh для загрузки базы и сертификатов +# + +# --- Пользователь --- +users: + - name: eberkheev + groups: sudo, docker + shell: /bin/bash + sudo: ALL=(ALL) NOPASSWD:ALL + ssh_authorized_keys: + - ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDqMBaED9uVMQkKqwIZ6PeQp+3tNGBozQHpi4uNVjdcV admin@DESKTOP-4NGS6DA + +# --- Пакеты --- +package_update: true +package_upgrade: true +packages: + - curl + - wget + - git + - htop + - mc + - nmap + - net-tools + - unzip + - fail2ban + - certbot + - docker.io + - docker-compose + - ufw + +# --- SSH --- +write_files: + - path: /etc/ssh/sshd_config + content: | + Include /etc/ssh/sshd_config.d/*.conf + Port 10001 + PermitRootLogin no + PasswordAuthentication no + PermitEmptyPasswords no + KbdInteractiveAuthentication no + UsePAM yes + X11Forwarding yes + PrintMotd no + AcceptEnv LANG LC_* + Subsystem sftp /usr/lib/openssh/sftp-server + + # --- docker-compose.yml для 3x-ui --- + - path: /home/eberkheev/3x-ui/docker-compose.yml + owner: eberkheev:eberkheev + permissions: "0644" + content: | + services: + 3xui: + image: ghcr.io/mhsanaei/3x-ui:latest + container_name: 3xui_app + volumes: + - ./db/:/etc/x-ui/ + - ./cert/:/root/cert/ + environment: + XRAY_VMESS_AEAD_FORCED: "false" + XUI_ENABLE_FAIL2BAN: "true" + tty: true + network_mode: host + restart: unless-stopped + + # --- Скрипт обновления --- + - path: /home/eberkheev/update.sh + owner: eberkheev:eberkheev + permissions: "0755" + content: | + #!/bin/bash + set -e + + BACKUP_PATH="/home/eberkheev/x-ui-backup.db" + XUI_PATH="/home/eberkheev/3x-ui" + DOCKER_IMAGE="ghcr.io/mhsanaei/3x-ui:latest" + + BUILD_MODE="pull" + if [ "$1" = "--build" ]; then + BUILD_MODE="build" + fi + + echo "=== Mode: $BUILD_MODE ===" + + echo "=== System update ===" + sudo apt update && sudo apt upgrade -y + + echo "=== Finding x-ui container ===" + CONTAINER=$(sudo docker ps --format "{{.Names}}" | grep -i "xui\|x-ui\|3xui" | head -n 1) + + if [ -z "$CONTAINER" ]; then + echo "WARNING: x-ui container not found, skipping backup..." + if [ ! -f "$BACKUP_PATH" ]; then + echo "ERROR: No container and no backup found, aborting!" + exit 1 + fi + echo "Existing backup found at $BACKUP_PATH, continuing..." + else + echo "Found container: $CONTAINER" + echo "=== Backup x-ui database ===" + sudo docker cp $CONTAINER:/etc/x-ui/x-ui.db $BACKUP_PATH + echo "Backup saved to $BACKUP_PATH" + fi + + echo "=== Pulling latest from main ===" + cd $XUI_PATH + sudo git checkout main + sudo git pull origin main + + echo "=== Stopping old container ===" + sudo docker-compose down + + if [ "$BUILD_MODE" = "build" ]; then + echo "--- Building from source ---" + sudo docker-compose build --no-cache + sudo docker-compose up -d + else + echo "--- Pulling prebuilt image: $DOCKER_IMAGE ---" + sudo docker pull $DOCKER_IMAGE + sudo docker rm -f 3xui_app 2>/dev/null || true + sudo docker run -d \ + --name 3xui_app \ + --restart unless-stopped \ + --network host \ + --env XRAY_VMESS_AEAD_FORCED=false \ + --env XUI_ENABLE_FAIL2BAN=true \ + -v $XUI_PATH/db/:/etc/x-ui/ \ + -v $XUI_PATH/cert/:/root/cert/ \ + -t \ + $DOCKER_IMAGE + fi + + echo "=== Restoring database from backup ===" + NEW_CONTAINER=$(sudo docker ps --format "{{.Names}}" | grep -i "xui\|x-ui\|3xui" | head -n 1) + if [ -z "$NEW_CONTAINER" ]; then + echo "ERROR: Container not found after restart!" + exit 1 + fi + sudo docker cp $BACKUP_PATH $NEW_CONTAINER:/etc/x-ui/x-ui.db + echo "Database restored, restarting container..." + sudo docker restart $NEW_CONTAINER + + echo "=== Status ===" + sudo docker ps | grep -i "xui\|x-ui\|3xui" + sudo docker logs $NEW_CONTAINER --tail=30 + + echo "=== Done! ===" + +# --- Команды при первом запуске --- +runcmd: + - systemctl restart ssh + - systemctl enable docker + - systemctl start docker + - mkdir -p /home/eberkheev/3x-ui/db + - mkdir -p /home/eberkheev/3x-ui/cert + - mkdir -p /home/eberkheev/cert + - chown -R eberkheev:eberkheev /home/eberkheev/3x-ui + - chown -R eberkheev:eberkheev /home/eberkheev/cert + - chown eberkheev:eberkheev /home/eberkheev/update.sh + - docker pull ghcr.io/mhsanaei/3x-ui:latest diff --git a/server-setup/cloud-init/upload-data.sh b/server-setup/cloud-init/upload-data.sh new file mode 100755 index 0000000..7e3f87b --- /dev/null +++ b/server-setup/cloud-init/upload-data.sh @@ -0,0 +1,62 @@ +#!/bin/bash +# +# Загрузка данных на сервер после cloud-init +# Запускается с ЛОКАЛЬНОЙ машины +# +# Использование: bash upload-data.sh +# + +set -euo pipefail + +if [ $# -lt 1 ]; then + echo "Использование: bash $0 " + echo "Пример: bash $0 5.144.180.119" + exit 1 +fi + +SERVER_IP="$1" +SSH_PORT="10001" +SSH_USER="eberkheev" +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +DATA_DIR="$SCRIPT_DIR/../data" + +# Проверка наличия файлов +for f in x-ui.db fullchain.pem privkey.pem; do + if [ ! -f "$DATA_DIR/$f" ]; then + echo "ERROR: Файл $DATA_DIR/$f не найден" + exit 1 + fi +done + +SCP="scp -P $SSH_PORT" +SSH="ssh -p $SSH_PORT ${SSH_USER}@${SERVER_IP}" + +echo "=== Загрузка данных на $SERVER_IP ===" + +echo "[1/4] Загрузка базы данных x-ui..." +$SCP "$DATA_DIR/x-ui.db" "${SSH_USER}@${SERVER_IP}:~/3x-ui/db/x-ui.db" +$SCP "$DATA_DIR/x-ui.db" "${SSH_USER}@${SERVER_IP}:~/x-ui-backup.db" + +echo "[2/4] Загрузка сертификатов..." +$SCP "$DATA_DIR/fullchain.pem" "$DATA_DIR/privkey.pem" "${SSH_USER}@${SERVER_IP}:~/3x-ui/cert/" +$SCP "$DATA_DIR/fullchain.pem" "$DATA_DIR/privkey.pem" "${SSH_USER}@${SERVER_IP}:~/cert/" + +echo "[3/4] Запуск контейнера 3x-ui..." +$SSH "docker run -d \ + --name 3xui_app \ + --restart unless-stopped \ + --network host \ + --env XRAY_VMESS_AEAD_FORCED=false \ + --env XUI_ENABLE_FAIL2BAN=true \ + -v ~/3x-ui/db/:/etc/x-ui/ \ + -v ~/3x-ui/cert/:/root/cert/ \ + -t \ + ghcr.io/mhsanaei/3x-ui:latest" + +echo "[4/4] Проверка..." +$SSH "docker ps | grep 3xui" + +echo "" +echo "=== Готово! ===" +echo "Панель: https://$SERVER_IP:10002" +echo "SSH: ssh -p $SSH_PORT $SSH_USER@$SERVER_IP" diff --git a/server-setup/manual-setup/README.md b/server-setup/manual-setup/README.md new file mode 100644 index 0000000..2453b47 --- /dev/null +++ b/server-setup/manual-setup/README.md @@ -0,0 +1,95 @@ +# Настройка нового сервера (копия kirgysia) + +## Что внутри + +``` +server-setup/ +├── setup.sh # Скрипт автоматической настройки +├── README.md # Эта инструкция +└── data/ + ├── x-ui.db # База данных 3x-ui + ├── fullchain.pem # SSL-сертификат + ├── privkey.pem # SSL-ключ + └── authorized_keys # SSH-ключ для доступа +``` + +## Требования + +- Ubuntu 22.04 LTS +- Root-доступ + +## Быстрый старт + +### 1. Скопировать папку на новый сервер + +```bash +scp -r server-setup/ root@IP_НОВОГО_СЕРВЕРА:/root/ +``` + +### 2. Подключиться к серверу + +```bash +ssh root@IP_НОВОГО_СЕРВЕРА +``` + +### 3. Запустить скрипт + +```bash +cd /root/server-setup +sudo bash setup.sh +``` + +Всё. Скрипт сам установит пакеты, создаст пользователя, настроит SSH, поднимет 3x-ui в Docker. + +## Настройки (при необходимости) + +В начале `setup.sh` есть переменные — обычно менять их не нужно: + +| Переменная | По умолчанию | Описание | +|-------------|----------------|----------| +| `NEW_USER` | `eberkheev` | Имя пользователя | +| `SSH_PORT` | `10001` | Порт SSH | +| `TIMEZONE` | `UTC` | Часовой пояс | +| `STATIC_IP` | *(пусто)* | IP сервера, например `5.144.180.119/24`. Оставить пустым если сеть настраивается автоматически (DHCP) — так на большинстве VPS | +| `GATEWAY` | *(пусто)* | IP шлюза, например `5.144.180.1`. Нужен только если задан `STATIC_IP` | +| `DNS` | `8.8.8.8,8.8.4.4` | DNS-серверы | + +## Что настраивает скрипт + +1. Обновление системы +2. Установка пакетов: docker, git, htop, mc, nmap, fail2ban, certbot, curl, wget, unzip +3. Создание пользователя с sudo (без пароля) +4. SSH: порт 10001, вход только по ключу, root запрещён +5. Сеть (только если задан STATIC_IP) +6. 3x-ui в Docker (network_mode: host) с восстановлением базы и сертификатов +7. Скрипт обновления `~/update.sh` + +## После установки + +Подключение: +```bash +ssh -p 10001 eberkheev@IP_НОВОГО_СЕРВЕРА +``` + +Панель 3x-ui: +``` +https://IP_НОВОГО_СЕРВЕРА:10002 +``` +(порт панели зависит от настроек в x-ui.db) + +Проверка контейнера: +```bash +docker ps +``` + +Обновление 3x-ui: +```bash +bash ~/update.sh +``` + +## Обновление сертификатов + +Если нужен новый сертификат — положите `fullchain.pem` и `privkey.pem` в `~/3x-ui/cert/` и перезапустите контейнер: +```bash +docker restart 3xui_app +``` diff --git a/server-setup/manual-setup/setup.sh b/server-setup/manual-setup/setup.sh new file mode 100755 index 0000000..a6616a2 --- /dev/null +++ b/server-setup/manual-setup/setup.sh @@ -0,0 +1,296 @@ +#!/bin/bash +# +# Server Setup Script — воссоздание конфигурации сервера kirgysia +# OS: Ubuntu 22.04 LTS +# Запуск: sudo bash setup.sh +# +# Перед запуском: +# 1. Положите рядом файлы: +# - ../data/x-ui.db (база 3x-ui — скопировать с оригинала) +# - ../data/fullchain.pem (SSL-сертификат) +# - ../data/privkey.pem (SSL-ключ) +# - ../data/authorized_keys (SSH-ключи для доступа) +# 2. Отредактируйте переменные ниже под новый сервер +# + +set -euo pipefail + +# ============================================================ +# НАСТРОЙКИ — отредактируйте под новый сервер +# ============================================================ +NEW_USER="eberkheev" +SSH_PORT="10001" +TIMEZONE="UTC" +# Сетевой интерфейс (узнать: ip link show) +NET_IFACE="ens18" +# Статический IP (оставьте пустым для DHCP) +STATIC_IP="" # например: "5.144.180.119/24" +GATEWAY="" # например: "5.144.180.1" +DNS="8.8.8.8,8.8.4.4" + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +DATA_DIR="$SCRIPT_DIR/../data" + +# ============================================================ +# Проверки +# ============================================================ +if [ "$(id -u)" -ne 0 ]; then + echo "ERROR: Запустите с sudo: sudo bash $0" + exit 1 +fi + +if [ ! -d "$DATA_DIR" ]; then + echo "ERROR: Директория $DATA_DIR не найдена." + echo "Создайте её и положите туда: x-ui.db, fullchain.pem, privkey.pem, authorized_keys" + exit 1 +fi + +echo "=== [1/8] Обновление системы ===" +apt update && apt upgrade -y + +echo "=== [2/8] Установка пакетов ===" +apt install -y \ + curl \ + wget \ + git \ + htop \ + mc \ + nmap \ + net-tools \ + unzip \ + fail2ban \ + certbot \ + docker.io \ + docker-compose \ + ufw + +systemctl enable docker +systemctl start docker + +echo "=== [3/8] Настройка часового пояса ===" +timedatectl set-timezone "$TIMEZONE" + +echo "=== [4/8] Создание пользователя ===" +if ! id "$NEW_USER" &>/dev/null; then + adduser --disabled-password --gecos "" "$NEW_USER" + usermod -aG sudo "$NEW_USER" + # Разрешить sudo без пароля (опционально — удалите если не нужно) + echo "$NEW_USER ALL=(ALL) NOPASSWD:ALL" > "/etc/sudoers.d/$NEW_USER" + chmod 440 "/etc/sudoers.d/$NEW_USER" + echo "Пользователь $NEW_USER создан" +else + echo "Пользователь $NEW_USER уже существует" +fi + +usermod -aG docker "$NEW_USER" + +# SSH-ключи +USER_HOME="/home/$NEW_USER" +mkdir -p "$USER_HOME/.ssh" +if [ -f "$DATA_DIR/authorized_keys" ]; then + cp "$DATA_DIR/authorized_keys" "$USER_HOME/.ssh/authorized_keys" + chmod 600 "$USER_HOME/.ssh/authorized_keys" +fi +chown -R "$NEW_USER:$NEW_USER" "$USER_HOME/.ssh" + +echo "=== [5/8] Настройка SSH ===" +cat > /etc/ssh/sshd_config < /etc/netplan/01-netcfg.yaml < "$XUI_DIR/docker-compose.yml" <<'DCEOF' +services: + 3xui: + image: ghcr.io/mhsanaei/3x-ui:latest + container_name: 3xui_app + volumes: + - ./db/:/etc/x-ui/ + - ./cert/:/root/cert/ + environment: + XRAY_VMESS_AEAD_FORCED: "false" + XUI_ENABLE_FAIL2BAN: "true" + tty: true + network_mode: host + restart: unless-stopped +DCEOF + +chown -R "$NEW_USER:$NEW_USER" "$XUI_DIR" + +# Скрипт обновления +cat > "$USER_HOME/update.sh" <<'UPDATEEOF' +#!/bin/bash + +set -e + +BACKUP_PATH="/home/eberkheev/x-ui-backup.db" +XUI_PATH="/home/eberkheev/3x-ui" +DOCKER_IMAGE="ghcr.io/mhsanaei/3x-ui:latest" + +BUILD_MODE="pull" +if [ "$1" = "--build" ]; then + BUILD_MODE="build" +fi + +echo "=== Mode: $BUILD_MODE ===" + +echo "=== System update ===" +sudo apt update && sudo apt upgrade -y + +echo "=== Finding x-ui container ===" +CONTAINER=$(sudo docker ps --format "{{.Names}}" | grep -i "xui\|x-ui\|3xui" | head -n 1) + +if [ -z "$CONTAINER" ]; then + echo "WARNING: x-ui container not found, skipping backup..." + if [ ! -f "$BACKUP_PATH" ]; then + echo "ERROR: No container and no backup found, aborting!" + exit 1 + fi + echo "Existing backup found at $BACKUP_PATH, continuing..." +else + echo "Found container: $CONTAINER" + echo "=== Backup x-ui database ===" + sudo docker cp $CONTAINER:/etc/x-ui/x-ui.db $BACKUP_PATH + echo "Backup saved to $BACKUP_PATH" +fi + +echo "=== Pulling latest from main ===" +cd $XUI_PATH +sudo git checkout main +sudo git pull origin main + +echo "=== Stopping old container ===" +sudo docker-compose down + +if [ "$BUILD_MODE" = "build" ]; then + echo "--- Building from source ---" + sudo docker-compose build --no-cache + sudo docker-compose up -d +else + echo "--- Pulling prebuilt image: $DOCKER_IMAGE ---" + sudo docker pull $DOCKER_IMAGE + sudo docker rm -f 3xui_app 2>/dev/null || true + sudo docker run -d \ + --name 3xui_app \ + --restart unless-stopped \ + --network host \ + --env XRAY_VMESS_AEAD_FORCED=false \ + --env XUI_ENABLE_FAIL2BAN=true \ + -v $XUI_PATH/db/:/etc/x-ui/ \ + -v $XUI_PATH/cert/:/root/cert/ \ + -t \ + $DOCKER_IMAGE +fi + +echo "=== Restoring database from backup ===" +NEW_CONTAINER=$(sudo docker ps --format "{{.Names}}" | grep -i "xui\|x-ui\|3xui" | head -n 1) +if [ -z "$NEW_CONTAINER" ]; then + echo "ERROR: Container not found after restart!" + exit 1 +fi +sudo docker cp $BACKUP_PATH $NEW_CONTAINER:/etc/x-ui/x-ui.db +echo "Database restored, restarting container..." +sudo docker restart $NEW_CONTAINER + +echo "=== Status ===" +sudo docker ps | grep -i "xui\|x-ui\|3xui" +sudo docker logs $NEW_CONTAINER --tail=30 + +echo "=== Done! ===" +UPDATEEOF + +chown "$NEW_USER:$NEW_USER" "$USER_HOME/update.sh" + +echo "=== [8/8] Запуск 3x-ui ===" +cd "$XUI_DIR" +docker pull ghcr.io/mhsanaei/3x-ui:latest +docker run -d \ + --name 3xui_app \ + --restart unless-stopped \ + --network host \ + --env XRAY_VMESS_AEAD_FORCED=false \ + --env XUI_ENABLE_FAIL2BAN=true \ + -v "$XUI_DIR/db/:/etc/x-ui/" \ + -v "$XUI_DIR/cert/:/root/cert/" \ + -t \ + ghcr.io/mhsanaei/3x-ui:latest + +echo "" +echo "============================================" +echo " Сервер настроен!" +echo "============================================" +echo "" +echo " SSH: порт $SSH_PORT, пользователь $NEW_USER" +echo " 3x-ui: запущен в Docker (network_mode: host)" +echo " Панель: https://:10002 (или порт из x-ui.db)" +echo "" +echo " Для обновления: bash ~/update.sh" +echo " Для проверки: docker ps" +echo ""