Files
hestiacp/func_ruby/docs/BunkerWebApiDoc.md
2026-04-27 00:47:57 +03:00

15 KiB
Raw Blame History

HestiaBunkerWebApi - Ruby класс для работы с BunkerWeb API

Описание

Класс HestiaBunkerWebApi предоставляет простой интерфейс для управления сервисами BunkerWeb через REST API. Класс реализует:

  • Аутентификацию с получением токена
  • Управление сервисами (создание, обновление, удаление)
  • Управление SSL сертификатами
  • Управление instances (worker nodes)
  • Полное исключение ошибок при любых проблемах

Установка и импорт

# Ruby 3.3+ рекомендуется
ruby --version
# ruby 3.3.x or later

# Класс использует стандартные библиотеки Ruby:
# - json (для JSON парсинга)
# - net/http (для HTTP запросов)
# - uri (для URL парсинга)

Использование класса

Базовое использование

require_relative "HestiaBunkerWebApi.rb"

# Создаём экземпляр API с аутентификацией
api = HestiaBunkerWebApi.new(
  "http://127.0.0.1:8888",  # URL API (можно https://)
  "admin",                   # username
  "password"                 # password
)
# или
api = HestiaBunkerWebApi.new(
  "http://127.0.0.1:8888",  # URL API (можно https://)
)
# в этом случае пароль и логин читаются автоматически из файла /etc/bunkerweb/api.env


# При создании экземпляра автоматически происходит аутентификация
# Если ошибка - выбрасывается BunkerWebApiError с описанием проблемы

Обработка ошибок

Все ошибки наследуются от StandardError через класс BunkerWebApiError:

begin
  api.create_service("example.domain", options)
rescue BunkerWebApiError => e
  puts "[ERROR] Ошибка API: #{e.message}"
  
  # Примеры возможных ошибок:
  # - "Authentication failed: 401 - Unauthorized"
  # - "Service 'x' already exists"
  # - "Certificate and Key paths are required when USE_SSL is enabled"
  # - "Failed to create service: status=500, body={...}"
  
  exit 1
end

Методы класса

Конструктор

HestiaBunkerWebApi.new(api_url, username, password)

Параметры:

  • api_url - URL BunkerWeb API в формате http://ip:port или https://ip:port
  • username - имя администратора для аутентификации
  • password - пароль для аутентификации

Действие: При создании автоматически пытается аутентифицироваться через POST /auth и сохраняет токен.

Создание сервиса

api.create_service(service_name, options = {})

Параметры:

  • service_name - имя домена/сервиса (например, "example.my.domain")
  • options - хэш с конфигурацией:
Параметр Тип Описание Пример
ssl String "yes" для SSL, "no" для HTTP "no"
certificate_path String Путь к SSL сертификату (если ssl="yes") "/etc/ssl/certs/example.crt"
key_path String Путь к приватному ключу (если ssl="yes") "/etc/ssl/private/example.key"
use_template String Безопасность шаблона "high" (default)
reverse_proxy_host String Target reverse proxy "http://192.168.3.51:8078"
reverse_proxy_url String URL трансформация "~ ^/(.*)$"
real_ip_from String CIDR trusted network для RealIP "192.168.3.0/24"
use_modsecurity String WAF включение "yes" (default)
anti_bot String Bot protection "captcha" (default)
http_port Integer/nil HTTP порт "80" или null
https_port Integer HTTPS порт 443 или null

Пример - создание reverse proxy сервиса без SSL:

result = api.create_service("example.my.domain", {
  ssl: "no",
  reverse_proxy_host: "http://192.168.3.51:8078"
})

# Генерирует variables:
# - USE_TEMPLATE: "high"
# - USE_SSL: "no"
# - LISTEN_HTTPS_PORT: "null"
# - LISTEN_HTTP_PORT: "80"
# - USE_REVERSE_PROXY: "yes"
# - REVERSE_PROXY_HOST: "http://192.168.3.51:8078"

Пример - создание сервиса с SSL + reverse proxy:

result = api.create_service("example.my.domain", {
  ssl: "yes",                              # Включаем SSL
  
  certificate_path: "/etc/ssl/certs/example.crt",  # Путь к сертификату
  key_path: "/etc/ssl/private/example.key",        # Путь к ключу
  
  reverse_proxy_host: "http://192.168.3.51:8078",  # Reverse proxy target
  
  use_template: "high",
  anti_bot: "captcha"
})

# Генерирует variables:
# - USE_TEMPLATE: "high"
# - USE_SSL: "yes"
# - SSL_CERTIFICATE_FILE_PATH: "/etc/ssl/certs/example.crt"
# - SSL_KEY_FILE_PATH: "/etc/ssl/private/example.key"
# - LISTEN_HTTPS_PORT: "443"
# - LISTEN_HTTP_PORT: "80"

Обновление SSL сертификата для существующего сервиса

api.update_service_ssl(service_name, certificate_path, key_path, https_port = nil)

Параметры:

  • service_name - имя уже созданного сервиса
  • certificate_path - новый путь к SSL сертификату
  • key_path - новый путь к приватному ключу
  • https_port (optional) - HTTPS порт (default: 443)

Пример:

api.update_service_ssl(
  "example.my.domain",
  "/etc/ssl/certs/example.crt",
  "/etc/ssl/private/example.key"
)

# Обновляет существующий сервис, сохраняя reverse proxy настройки

Удаление сервиса

api.delete_service(service_name)

Параметры:

  • service_name - имя сервиса для удаления

Пример:

api.delete_service("example.my.domain")
# Удаляет сервис и конфигурацию

Получение списка всех сервисов

api.list_services(drafts = false)

Параметры:

  • drafts (optional) - включать draft сервисы (default: false)

Возвращает: Array of service objects

Пример:

services = api.list_services()
services.each { |s| puts "- #{s['server_name']}" }

Получение деталей конкретного сервиса

api.get_service(service_name)

Параметры:

  • service_name - имя сервиса для получения деталей

Возвращает: Hash with service configuration (variables, settings, etc.)

Пример:

config = api.get_service("example.my.domain")
puts config.inspect

Перезагрузка конфигурации на instance

api.reload_instance(instance_hostname = nil)

Параметры:

  • instance_hostname (optional) - hostname instance для перезагрузки (если nil, reloads all instances)

Пример:

# Reload все instances
api.reload_instance()

# Reload конкретный instance
api.reload_instance("192.168.3.50")

Получение списка всех instances

api.list_instances()

Возвращает: Array of instance objects (hostname, name, port, etc.)

Создание/регистрация BunkerWeb instance (worker node)

api.create_instance(hostname, name = nil, port = 8888, https_port = nil)

Параметры:

  • hostname - IP address или hostname worker node
  • name (optional) - Human-readable имя instance
  • port - API port на worker node (default: 8888)
  • https_port (optional) - HTTPS port если есть

Пример:

api.create_instance(
  "192.168.3.50",          # IP worker node
  "BunkerWeb Worker Node", # Optional name
  8888                      # API port
)

# Возвращает: { status: 201/409, body: {...} }
# Если статус 201 - instance создан
# Если статус 409 - instance уже существует (это OK)

Удаление BunkerWeb instance

api.delete_instance(hostname)

Параметры:

  • hostname - hostname instance для удаления

Примеры полного использования

Пример 1: Создание и управление сервисом

require_relative "HestiaBunkerWebApi.rb"

begin
  # 1. Подключаемся к API
  api = HestiaBunkerWebApi.new(
    "http://127.0.0.1:8888",
    "admin",
    "your_password"
  )
  
  # 2. Создаём reverse proxy сервис без SSL
  result = api.create_service("u4.my.brp", {
    ssl: "no",
    reverse_proxy_host: "http://192.168.3.51:8078"
  })
  
  puts "[INFO] Service created: #{result.inspect}"
  
  # 3. Добавляем SSL сертификат позже (если нужно)
  api.update_service_ssl(
    "u4.my.brp",
    "/etc/ssl/certs/u4.crt",
    "/etc/ssl/private/u4.key"
  )
  
  # 4. Проверяем список сервисов
  services = api.list_services()
  puts "[INFO] All services:"
  services.each { |s| puts "- #{s['server_name']}" }
  
  # 5. Удаление сервиса (при необходимости)
  api.delete_service("u4.my.brp")
  
rescue BunkerWebApiError => e
  puts "[ERROR] Ошибка API: #{e.message}"
  exit 1
end

Пример 2: Управление несколькими сервисами

require_relative "HestiaBunkerWebApi.rb"

api = HestiaBunkerWebApi.new("http://127.0.0.1:8888", "admin", "password")

# Создаём несколько сервисов с разными конфигурациями
services_to_create = [
  { name: "service1.domain", ssl: "no", reverse_proxy_host: "http://192.168.3.50:80" },
  { name: "service2.domain", ssl: "yes", certificate_path: "/certs/service2.crt", key_path: "/keys/service2.key", reverse_proxy_host: "http://192.168.3.51:8078" }
]

services_to_create.each do |opts|
  begin
    api.create_service(opts[:name], opts)
  rescue BunkerWebApiError => e
    puts "[ERROR] #{e.message}" if e.message.include?("already exists")
  end
end

# Reload конфигурации на instance
api.reload_instance("192.168.3.50")

Пример 3: Обработка ошибок и логирование

require_relative "HestiaBunkerWebApi.rb"

def safe_create_service(api_url, username, password, service_name, options)
  begin
    api = HestiaBunkerWebApi.new(api_url, username, password)
    
    result = api.create_service(service_name, options)
    return { success: true, data: result }
    
  rescue BunkerWebApiError => e
    if e.message.include?("Authentication")
      puts "[FATAL] Authentication failed: #{e.message}"
    elsif e.message.include?("already exists")
      begin
        existing = api.get_service(service_name)
        return { success: false, already_exists: true, service: existing }
      rescue => get_error
        return { success: false, error: "Can't retrieve service: #{get_error.message}" }
    else
      return { success: false, error: e.message }
    end
  end
  
  { success: false, error: "Unknown error" }
end

# Использование
result = safe_create_service("http://127.0.0.1:8888", "admin", "password", "example.domain", { ssl: "yes" })

if result[:success]
  puts "[SUCCESS] Service created"
elsif result[:already_exists]
  puts "[INFO] Service exists:"
  puts JSON.generate(result[:service])
else
  puts "[FAILED] #{result[:error]}"
end

Ошибки и их обработка

Типичные ошибки:

Код ответа Описание Пример сообщения
401 Authentication failed "Authentication failed: 401 - Unauthorized"
200 (no token) Auth passed but no token "Authentication succeeded but no token received"
Connection error API недоступен "Authentication error: Connection refused"
409 Conflict Service already exists "Service 'x' already exists"
422 Unprocessable Entity Invalid data (например, LISTEN_HTTPS_PORT = nil) "Failed to create service: status=422..."
429 Too Many Requests Rate limit exceeded "Rate limit exceeded: 10 per 1 minute"

Решение проблем с rate limiting

Если получаете ошибку 429 (rate limit), нужно отключить или увеличить лимит в /etc/bunkerweb/api.env:

# Откройте конфиг и найдите секцию Rate limiting
nano /etc/bunkerweb/api.env

# Добавьте/измените:
API_RATE_LIMIT_ENABLED=no          # Отключение rate limiting
# или
API_RATE_LIMIT=1000/minute         # Увеличение лимита до 1000/m

Затем перезагрузите API service:

systemctl reload bunkerweb-api.service

Особенности реализации

1. SSL сертификатные пути

Когда ssl: "no" - API ожидает "LISTEN_HTTPS_PORT" => "null" (строка), а не JSON null (nil):

# ❌ Ошибка:
variables["LISTEN_HTTPS_PORT"] = nil  # → 422 error

# ✅ Правильно:
variables["LISTEN_HTTPS_PORT"] = "null"  # → 200 OK

2. Статусы ответа для создания сервиса

BunkerWeb API возвращает 200 OK вместо стандартного 201 Created:

# Класс принимает оба статуса как успех:
if [201, 200].include?(response[:status])
  puts "[INFO] Service created successfully"
end

3. Поддержка HTTP методов

Класс поддерживает все основные HTTP методы для API операций:

  • GET - получение данных (services, instances)
  • POST - создание (services, instances, auth)
  • PATCH - обновление (services)
  • DELETE - удаление (services, instances)

Совместимость

  • Ruby: 3.0+
  • BunkerWeb API: 1.6.x и выше
  • ZooKeeper/Redis: не требуются для этого класса (работает через HTTP API напрямую)

Дополнительные ресурсы