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) <noreply@anthropic.com>
This commit is contained in:
2026-03-21 16:07:57 +04:00
co-authored by Claude Opus 4.6
commit ba4b395a4a
6 changed files with 679 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
data/
+56
View File
@@ -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
```
+169
View File
@@ -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
+62
View File
@@ -0,0 +1,62 @@
#!/bin/bash
#
# Загрузка данных на сервер после cloud-init
# Запускается с ЛОКАЛЬНОЙ машины
#
# Использование: bash upload-data.sh <IP сервера>
#
set -euo pipefail
if [ $# -lt 1 ]; then
echo "Использование: bash $0 <IP сервера>"
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"
+95
View File
@@ -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
```
+296
View File
@@ -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 <<SSHEOF
Include /etc/ssh/sshd_config.d/*.conf
Port $SSH_PORT
PermitRootLogin no
PasswordAuthentication no
PermitEmptyPasswords no
KbdInteractiveAuthentication no
UsePAM yes
X11Forwarding yes
PrintMotd no
AcceptEnv LANG LC_*
Subsystem sftp /usr/lib/openssh/sftp-server
SSHEOF
systemctl restart ssh
echo "SSH настроен на порт $SSH_PORT"
echo "=== [6/8] Настройка сети ==="
if [ -n "$STATIC_IP" ]; then
cat > /etc/netplan/01-netcfg.yaml <<NETEOF
network:
version: 2
ethernets:
$NET_IFACE:
addresses:
- $STATIC_IP
gateway4: $GATEWAY
nameservers:
addresses:
- ${DNS//,/$'\n - '}
search: []
NETEOF
netplan apply
echo "Статический IP настроен: $STATIC_IP"
else
echo "Сеть: используется DHCP (не настраивалась)"
fi
echo "=== [7/8] Установка 3x-ui ==="
XUI_DIR="$USER_HOME/3x-ui"
if [ ! -d "$XUI_DIR" ]; then
sudo -u "$NEW_USER" git clone https://github.com/MHSanaei/3x-ui.git "$XUI_DIR"
else
echo "3x-ui уже склонирован"
fi
# Создаём директории для данных
mkdir -p "$XUI_DIR/db" "$XUI_DIR/cert" "$USER_HOME/cert"
# Копируем базу данных
if [ -f "$DATA_DIR/x-ui.db" ]; then
cp "$DATA_DIR/x-ui.db" "$XUI_DIR/db/x-ui.db"
cp "$DATA_DIR/x-ui.db" "$USER_HOME/x-ui-backup.db"
echo "База данных x-ui скопирована"
else
echo "WARNING: x-ui.db не найден в $DATA_DIR — пропущено"
fi
# Копируем сертификаты
if [ -f "$DATA_DIR/fullchain.pem" ] && [ -f "$DATA_DIR/privkey.pem" ]; then
cp "$DATA_DIR/fullchain.pem" "$XUI_DIR/cert/"
cp "$DATA_DIR/privkey.pem" "$XUI_DIR/cert/"
cp "$DATA_DIR/fullchain.pem" "$USER_HOME/cert/"
cp "$DATA_DIR/privkey.pem" "$USER_HOME/cert/"
echo "Сертификаты скопированы"
else
echo "WARNING: Сертификаты не найдены в $DATA_DIR — пропущено"
fi
# docker-compose.yml
cat > "$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://<IP>:10002 (или порт из x-ui.db)"
echo ""
echo " Для обновления: bash ~/update.sh"
echo " Для проверки: docker ps"
echo ""