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
+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"