2026-05-01 18:11:49 +03:00
|
|
|
|
#!/opt/brepo/ruby33/bin/ruby
|
|
|
|
|
|
# info: action with bunkerweb API
|
|
|
|
|
|
# options: [SSL_CERT_PATH SSL_KEY_PATH]
|
|
|
|
|
|
#
|
|
|
|
|
|
# example: v-bunkerweb-module-install
|
|
|
|
|
|
#
|
|
|
|
|
|
# This function enables and disables additional modules
|
|
|
|
|
|
#
|
2026-05-02 17:50:56 +03:00
|
|
|
|
#------------------------------------------#
|
2026-05-01 18:11:49 +03:00
|
|
|
|
# Variables & Functions #
|
2026-05-02 17:50:56 +03:00
|
|
|
|
#------------------------------------------#
|
2026-05-01 18:11:49 +03:00
|
|
|
|
|
|
|
|
|
|
# Argument definition
|
|
|
|
|
|
|
|
|
|
|
|
require "/usr/local/hestia/func_ruby/global_options"
|
|
|
|
|
|
|
|
|
|
|
|
load_ruby_options_defaults
|
|
|
|
|
|
$HESTIA = load_hestia_default_path_from_env
|
|
|
|
|
|
|
|
|
|
|
|
require "main"
|
|
|
|
|
|
require "modules"
|
|
|
|
|
|
require "HestiaBunkerWebApi"
|
|
|
|
|
|
require "securerandom"
|
|
|
|
|
|
require "socket"
|
|
|
|
|
|
require 'json' unless defined?(JSON)
|
2026-05-02 17:50:56 +03:00
|
|
|
|
require 'etc'
|
2026-05-01 18:11:49 +03:00
|
|
|
|
|
|
|
|
|
|
hestia_check_privileged_user
|
|
|
|
|
|
|
|
|
|
|
|
load_global_bash_variables "/etc/hestiacp/hestia.conf"
|
|
|
|
|
|
if $HESTIA.nil?
|
|
|
|
|
|
hestia_print_error_message_to_cli "Can't find HESTIA base path"
|
|
|
|
|
|
exit 1
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
load_global_bash_variables "#{$HESTIA}/conf/hestia.conf"
|
|
|
|
|
|
|
|
|
|
|
|
# Perform verification if read-only mode is enabled
|
|
|
|
|
|
check_hestia_demo_mode
|
|
|
|
|
|
|
2026-05-02 17:50:56 +03:00
|
|
|
|
#------------------------------------------#
|
2026-05-01 18:11:49 +03:00
|
|
|
|
# Action #
|
2026-05-02 17:50:56 +03:00
|
|
|
|
#------------------------------------------#
|
2026-05-01 18:11:49 +03:00
|
|
|
|
|
2026-05-02 17:50:56 +03:00
|
|
|
|
puts "========================================================"
|
2026-05-01 18:11:49 +03:00
|
|
|
|
puts "=== AUTOMATED BUNKERWEB SETUP SCRIPT ==="
|
2026-05-02 17:50:56 +03:00
|
|
|
|
puts "========================================================"
|
2026-05-01 18:11:49 +03:00
|
|
|
|
puts ""
|
|
|
|
|
|
|
|
|
|
|
|
# Parse command line arguments for SSL cert and key paths
|
|
|
|
|
|
SSL_CERT_PATH = ARGV[0] || nil # First argument: SSL certificate path
|
|
|
|
|
|
SSL_KEY_PATH = ARGV[1] || nil # Second argument: SSL key path
|
|
|
|
|
|
|
|
|
|
|
|
# Generate secure passwords (meeting BunkerWeb password policy requirements)
|
2026-05-11 23:28:47 +03:00
|
|
|
|
api_env_file = "/etc/bunkerweb/api.env"
|
|
|
|
|
|
api_password = nil
|
|
|
|
|
|
if File.exist?(api_env_file)
|
|
|
|
|
|
File.foreach(api_env_file) do |line|
|
|
|
|
|
|
if line =~ /^\s*API_PASSWORD=(.*)/
|
|
|
|
|
|
val = $1.strip
|
|
|
|
|
|
api_password = val unless val.empty?
|
|
|
|
|
|
break
|
|
|
|
|
|
end
|
|
|
|
|
|
end
|
|
|
|
|
|
end
|
|
|
|
|
|
specials = '!@#$%^&*()-_=+[]{}|;:,.<>?'
|
|
|
|
|
|
API_PASSWORD = api_password || (SecureRandom.alphanumeric(24) + specials.chars.sample(3).join).chars.shuffle.join
|
|
|
|
|
|
|
|
|
|
|
|
ui_env_file = "/etc/bunkerweb/ui.env"
|
|
|
|
|
|
admin_password = nil
|
|
|
|
|
|
if File.exist?(ui_env_file)
|
|
|
|
|
|
File.foreach(ui_env_file) do |line|
|
|
|
|
|
|
if line =~ /^\s*ADMIN_PASSWORD=(.*)/
|
|
|
|
|
|
val = $1.strip
|
|
|
|
|
|
admin_password = val unless val.empty?
|
|
|
|
|
|
break
|
|
|
|
|
|
end
|
|
|
|
|
|
end
|
|
|
|
|
|
end
|
|
|
|
|
|
ADMIN_PASSWORD = admin_password || (SecureRandom.alphanumeric(24) + specials.chars.sample(3).join).chars.shuffle.join
|
2026-05-01 18:11:49 +03:00
|
|
|
|
|
|
|
|
|
|
puts "[INFO] Get server IP address"
|
|
|
|
|
|
|
|
|
|
|
|
server_ip_addr = "127.0.0.1" # default fallback
|
|
|
|
|
|
# Attempt to retrieve server IP via Hestia utility
|
|
|
|
|
|
begin
|
|
|
|
|
|
cmd = "/usr/local/hestia/bin/v-list-sys-ips json"
|
|
|
|
|
|
ips_output = `#{cmd}`.strip
|
|
|
|
|
|
unless ips_output.empty?
|
|
|
|
|
|
parsed_ips = JSON.parse(ips_output)
|
|
|
|
|
|
parsed_ips.each do |ip, details|
|
|
|
|
|
|
if details["OWNER"] == "admin"
|
|
|
|
|
|
server_ip_addr = ip
|
|
|
|
|
|
break
|
|
|
|
|
|
end
|
|
|
|
|
|
end
|
|
|
|
|
|
end
|
|
|
|
|
|
rescue JSON::ParserError, Errno::ENOENT
|
|
|
|
|
|
# If the command fails or output is invalid, keep default fallback
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
puts ""
|
|
|
|
|
|
|
2026-05-02 17:50:56 +03:00
|
|
|
|
# Compute nginx group ID once
|
|
|
|
|
|
nginx_gid = Etc.getgrnam('nginx').gid
|
|
|
|
|
|
|
2026-05-01 18:11:49 +03:00
|
|
|
|
# Step 1: Create /etc/bunkerweb/api.env configuration file
|
|
|
|
|
|
puts "[INFO] Creating API configuration at /etc/bunkerweb/api.env..."
|
|
|
|
|
|
api_env_content = <<~APIENV
|
|
|
|
|
|
# ==============================
|
|
|
|
|
|
# BunkerWeb API Configuration
|
|
|
|
|
|
# This file lists all supported API environment variables with their defaults.
|
|
|
|
|
|
# Uncomment and adjust as needed. Lines starting with # are ignored.
|
|
|
|
|
|
# ==============================
|
|
|
|
|
|
|
|
|
|
|
|
# --- Network & Proxy ---
|
|
|
|
|
|
# Listen address/port for the API
|
|
|
|
|
|
LISTEN_ADDR=127.0.0.1
|
|
|
|
|
|
LISTEN_PORT=8888
|
|
|
|
|
|
# Trusted proxy IPs for X-Forwarded-* headers (comma-separated).
|
|
|
|
|
|
# Default is restricted to loopback for security.
|
|
|
|
|
|
FORWARDED_ALLOW_IPS=127.0.0.1,::1
|
|
|
|
|
|
# Trusted proxy IPs for PROXY protocol (comma-separated).
|
|
|
|
|
|
# Defaults to FORWARDED_ALLOW_IPS when unset.
|
|
|
|
|
|
PROXY_ALLOW_IPS=127.0.0.1,::1
|
|
|
|
|
|
|
|
|
|
|
|
# --- Logging & Runtime ---
|
|
|
|
|
|
# LOG_LEVEL affects most components; CUSTOM_LOG_LEVEL overrides when provided.
|
|
|
|
|
|
# LOG_LEVEL=info
|
|
|
|
|
|
LOG_TYPES=file
|
|
|
|
|
|
LOG_FILE_PATH=/var/log/bunkerweb/api.log
|
|
|
|
|
|
# Number of workers/threads (auto if unset).
|
|
|
|
|
|
# MAX_WORKERS=<auto>
|
|
|
|
|
|
# MAX_THREADS=<auto>
|
|
|
|
|
|
|
|
|
|
|
|
# --- Authentication & Authorization ---
|
|
|
|
|
|
# Optional admin Bearer token (grants full access when provided).
|
|
|
|
|
|
# API_TOKEN=#{API_PASSWORD}
|
|
|
|
|
|
# Bootstrap admin user (created/validated on startup if provided).
|
|
|
|
|
|
API_USERNAME=admin
|
|
|
|
|
|
API_PASSWORD=#{API_PASSWORD}
|
|
|
|
|
|
# Force re-applying bootstrap admin credentials on startup (use with care).
|
|
|
|
|
|
# OVERRIDE_API_CREDS=no
|
|
|
|
|
|
# Fine-grained ACLs can be enabled/disabled here.
|
|
|
|
|
|
# API_ACL_BOOTSTRAP_FILE=
|
|
|
|
|
|
|
|
|
|
|
|
# --- IP allowlist ---
|
|
|
|
|
|
# Enable and shape inbound IP allowlist for the API.
|
|
|
|
|
|
API_WHITELIST_ENABLED=yes
|
|
|
|
|
|
WHITELIST_IPS=127.0.0.1
|
|
|
|
|
|
|
|
|
|
|
|
# --- FastAPI surface ---
|
|
|
|
|
|
# Customize or disable documentation endpoints. Use 'disabled' to turn off.
|
|
|
|
|
|
# API_TITLE=BunkerWeb API
|
|
|
|
|
|
# API_DOCS_URL=/docs
|
|
|
|
|
|
# API_REDOC_URL=/redoc
|
|
|
|
|
|
# API_OPENAPI_URL=/openapi.json
|
|
|
|
|
|
# Mount the API under a subpath (useful behind reverse proxies).
|
|
|
|
|
|
# API_ROOT_PATH=
|
|
|
|
|
|
|
|
|
|
|
|
# --- TLS/SSL ---
|
|
|
|
|
|
# Enable TLS for the API listener (requires cert and key).
|
|
|
|
|
|
# API_SSL_ENABLED=no
|
|
|
|
|
|
# Path to PEM-encoded certificate and private key.
|
|
|
|
|
|
# API_SSL_CERTFILE=/etc/ssl/certs/bunkerweb-api.crt
|
|
|
|
|
|
# API_SSL_KEYFILE=/etc/ssl/private/bunkerweb-api.key
|
|
|
|
|
|
# Optional chain/CA bundle and cipher suite.
|
|
|
|
|
|
# API_SSL_CA_CERTS=
|
|
|
|
|
|
# API_SSL_CIPHERS_CUSTOM=
|
|
|
|
|
|
# API_SSL_CIPHERS_LEVEL=modern # choices: modern|intermediate
|
|
|
|
|
|
|
|
|
|
|
|
# --- Biscuit keys & policy ---
|
|
|
|
|
|
# Bind token to client IP (except private ranges).
|
|
|
|
|
|
# CHECK_PRIVATE_IP=yes
|
|
|
|
|
|
# Biscuit token lifetime in seconds (0 disables expiry).
|
|
|
|
|
|
# API_BISCUIT_TTL_SECONDS=3600
|
|
|
|
|
|
# Provide Biscuit keys via env (hex) instead of files.
|
|
|
|
|
|
# BISCUIT_PUBLIC_KEY=
|
|
|
|
|
|
# BISCUIT_PRIVATE_KEY=
|
|
|
|
|
|
|
|
|
|
|
|
# --- Rate limiting ---
|
|
|
|
|
|
# Enable/disable and shape rate limiting.
|
|
|
|
|
|
API_RATE_LIMIT_ENABLED=no
|
|
|
|
|
|
API_RATE_LIMIT_HEADERS_ENABLED=no
|
|
|
|
|
|
# Global default limit (times per seconds).
|
|
|
|
|
|
# API_RATE_LIMIT_TIMES=100
|
|
|
|
|
|
# API_RATE_LIMIT_SECONDS=60
|
|
|
|
|
|
# Authentication endpoint limit.
|
|
|
|
|
|
# API_RATE_LIMIT_AUTH_TIMES=10
|
|
|
|
|
|
# API_RATE_LIMIT_AUTH_SECONDS=60
|
|
|
|
|
|
# Advanced limits and rules (CSV/JSON/YAML).
|
|
|
|
|
|
# API_RATE_LIMIT_DEFAULTS="200/minute"
|
|
|
|
|
|
# API_RATE_LIMIT_APPLICATION_LIMITS=
|
|
|
|
|
|
# API_RATE_LIMIT_RULES=
|
|
|
|
|
|
# Strategy: fixed-window | moving-window | sliding-window-counter
|
|
|
|
|
|
# API_RATE_LIMIT_STRATEGY=fixed-window
|
|
|
|
|
|
# Key selector: ip | user | path | method | header:<Name>
|
|
|
|
|
|
# API_RATE_LIMIT_KEY=ip
|
|
|
|
|
|
# Exempt IPs (space or comma-separated CIDRs).
|
|
|
|
|
|
# API_RATE_LIMIT_EXEMPT_IPS=
|
|
|
|
|
|
# Storage options in JSON (merged with Redis settings if USE_REDIS=yes).
|
|
|
|
|
|
# API_RATE_LIMIT_STORAGE_OPTIONS=
|
|
|
|
|
|
|
|
|
|
|
|
# --- Redis (optional, for rate limiting storage) ---
|
|
|
|
|
|
# USE_REDIS=no
|
|
|
|
|
|
# REDIS_HOST=
|
|
|
|
|
|
# REDIS_PORT=6379
|
|
|
|
|
|
# REDIS_DATABASE=0
|
|
|
|
|
|
# REDIS_USERNAME=
|
|
|
|
|
|
# REDIS_PASSWORD=
|
|
|
|
|
|
# REDIS_SSL=no
|
|
|
|
|
|
# REDIS_SSL_VERIFY=yes
|
|
|
|
|
|
# REDIS_TIMEOUT=1000
|
|
|
|
|
|
# REDIS_KEEPALIVE_POOL=10
|
|
|
|
|
|
# REDIS_SENTINEL_HOSTS=sentinel1:26379 sentinel2:26379
|
|
|
|
|
|
# REDIS_SENTINEL_MASTER=mymaster
|
|
|
|
|
|
# REDIS_SENTINEL_USERNAME=
|
|
|
|
|
|
# REDIS_SENTINEL_PASSWORD=
|
|
|
|
|
|
APIENV
|
|
|
|
|
|
|
|
|
|
|
|
File.write("/etc/bunkerweb/api.env", api_env_content)
|
2026-05-02 17:50:56 +03:00
|
|
|
|
File.chmod(0o660, "/etc/bunkerweb/api.env")
|
|
|
|
|
|
File.chown(0, nginx_gid, "/etc/bunkerweb/api.env")
|
2026-05-01 18:11:49 +03:00
|
|
|
|
puts "[SUCCESS] API configuration file created at /etc/bunkerweb/api.env"
|
|
|
|
|
|
puts ""
|
|
|
|
|
|
|
|
|
|
|
|
variables_env_content = <<~VENV
|
|
|
|
|
|
DNS_RESOLVERS=9.9.9.9 149.112.112.112 8.8.8.8 8.8.4.4
|
|
|
|
|
|
HTTP_PORT=80
|
|
|
|
|
|
HTTPS_PORT=443
|
|
|
|
|
|
API_LISTEN_IP=127.0.0.1
|
|
|
|
|
|
MULTISITE=yes
|
|
|
|
|
|
UI_HOST=http://127.0.0.1:7000
|
|
|
|
|
|
SERVER_NAME=
|
|
|
|
|
|
|
|
|
|
|
|
API_WHITELIST_IP=127.0.0.0/8
|
|
|
|
|
|
USE_SERVE_FILES=no
|
|
|
|
|
|
VENV
|
|
|
|
|
|
|
|
|
|
|
|
File.write("/etc/bunkerweb/variables.env", variables_env_content)
|
2026-05-02 17:50:56 +03:00
|
|
|
|
File.chmod(0o660, "/etc/bunkerweb/variables.env")
|
|
|
|
|
|
File.chown(0, nginx_gid, "/etc/bunkerweb/variables.env")
|
2026-05-01 18:11:49 +03:00
|
|
|
|
puts "[SUCCESS] Variables configuration file created at /etc/bunkerweb/variables.env"
|
|
|
|
|
|
puts ""
|
|
|
|
|
|
|
|
|
|
|
|
# Step 2: Enable and start bunkerweb-api service, wait for it to be running
|
|
|
|
|
|
puts "[INFO] Enabling bunkerweb-api service..."
|
|
|
|
|
|
system("systemctl enable bunkerweb-api")
|
|
|
|
|
|
puts "[INFO] Starting bunkerweb-api service..."
|
|
|
|
|
|
system("systemctl start bunkerweb-api")
|
|
|
|
|
|
|
2026-05-11 23:28:47 +03:00
|
|
|
|
sleep(30)
|
|
|
|
|
|
|
2026-05-01 18:11:49 +03:00
|
|
|
|
# Wait for the service to be ready (max 30 seconds)
|
|
|
|
|
|
puts "[INFO] Waiting for bunkerweb-api service to be running..."
|
|
|
|
|
|
max_attempts = 60 # Wait up to 30 seconds (check every half second)
|
|
|
|
|
|
attempt = 0
|
|
|
|
|
|
|
|
|
|
|
|
while attempt < max_attempts
|
|
|
|
|
|
status_output = `systemctl is-active bunkerweb-api 2>&1`
|
|
|
|
|
|
status = status_output.strip
|
|
|
|
|
|
|
|
|
|
|
|
if status == "active" || status == "running"
|
|
|
|
|
|
puts "[SUCCESS] bunkerweb-api service is running!"
|
|
|
|
|
|
break
|
|
|
|
|
|
elsif status == "failed"
|
|
|
|
|
|
puts "[ERROR] bunkerweb-api service failed to start!"
|
|
|
|
|
|
exit 1
|
|
|
|
|
|
else
|
|
|
|
|
|
print "."
|
|
|
|
|
|
sleep(0.5)
|
|
|
|
|
|
attempt += 1
|
|
|
|
|
|
end
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
if attempt >= max_attempts
|
|
|
|
|
|
puts ""
|
|
|
|
|
|
puts "[ERROR] bunkerweb-api service did not become active within timeout"
|
|
|
|
|
|
puts "[INFO] Current status: #{status_output.strip}"
|
|
|
|
|
|
log_event E_INVALID, $ARGUMENTS
|
|
|
|
|
|
exit 1
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
puts ""
|
|
|
|
|
|
|
|
|
|
|
|
# Step 3: Configure UI settings based on documentation at https://docs.bunkerweb.io/latest/web-ui/
|
|
|
|
|
|
puts "[INFO] Configuring Web UI..."
|
|
|
|
|
|
|
|
|
|
|
|
# Determine SSL settings for UI
|
|
|
|
|
|
ui_ssl_enabled = "no"
|
|
|
|
|
|
if SSL_CERT_PATH && SSL_KEY_PATH && File.exist?(SSL_CERT_PATH) && File.exist?(SSL_KEY_PATH)
|
|
|
|
|
|
ui_ssl_enabled = "yes"
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
ui_env_content = <<~UIENV
|
|
|
|
|
|
# ==============================
|
|
|
|
|
|
# BunkerWeb UI Configuration
|
|
|
|
|
|
# This file configures the Web UI settings.
|
|
|
|
|
|
# ==============================
|
|
|
|
|
|
|
|
|
|
|
|
# --- Listener & TLS ---
|
|
|
|
|
|
# Bind address for the UI (use server IP for external access)
|
|
|
|
|
|
UI_LISTEN_ADDR=127.0.0.1
|
|
|
|
|
|
# Bind port for the UI
|
|
|
|
|
|
UI_LISTEN_PORT=7000
|
|
|
|
|
|
# Enable TLS in the UI container
|
|
|
|
|
|
UI_SSL_ENABLED=#{ui_ssl_enabled}
|
|
|
|
|
|
UIENV
|
|
|
|
|
|
|
|
|
|
|
|
# Add SSL cert/key paths if provided
|
|
|
|
|
|
if ui_ssl_enabled == "yes"
|
|
|
|
|
|
ui_env_content += <<~SSLCONF
|
|
|
|
|
|
|
|
|
|
|
|
# SSL Certificate and Key paths
|
|
|
|
|
|
UI_SSL_CERTFILE=#{SSL_CERT_PATH}
|
|
|
|
|
|
UI_SSL_KEYFILE=#{SSL_KEY_PATH}
|
|
|
|
|
|
SSLCONF
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
ui_env_content += <<~UIENV2
|
|
|
|
|
|
|
|
|
|
|
|
# --- Admin Authentication ---
|
|
|
|
|
|
# Seed admin account
|
|
|
|
|
|
ADMIN_USERNAME=admin
|
|
|
|
|
|
ADMIN_PASSWORD=#{ADMIN_PASSWORD}
|
|
|
|
|
|
|
|
|
|
|
|
# --- Proxy settings ---
|
|
|
|
|
|
# Trusted proxy IPs for X-Forwarded-* headers
|
|
|
|
|
|
# UI_FORWARDED_ALLOW_IPS=127.0.0.1,::1
|
|
|
|
|
|
|
|
|
|
|
|
UIENV2
|
|
|
|
|
|
|
|
|
|
|
|
File.write("/etc/bunkerweb/ui.env", ui_env_content)
|
2026-05-02 17:50:56 +03:00
|
|
|
|
File.chmod(0o660, "/etc/bunkerweb/ui.env")
|
|
|
|
|
|
File.chown(0, nginx_gid, "/etc/bunkerweb/ui.env")
|
2026-05-01 18:11:49 +03:00
|
|
|
|
puts "[SUCCESS] UI configuration file created at /etc/bunkerweb/ui.env"
|
|
|
|
|
|
puts ""
|
|
|
|
|
|
|
|
|
|
|
|
# Step 4: Reload the bunkerweb-ui service to apply new configuration
|
|
|
|
|
|
puts "[INFO] Reloading bunkerweb-ui service..."
|
|
|
|
|
|
system("systemctl restart bunkerweb-ui")
|
|
|
|
|
|
|
|
|
|
|
|
# Wait for UI to be ready (max 10 seconds)
|
|
|
|
|
|
sleep(2)
|
|
|
|
|
|
|
|
|
|
|
|
if system("systemctl is-active bunkerweb-ui >/dev/null 2>&1")
|
|
|
|
|
|
puts "[SUCCESS] bunkerweb-ui service is running!"
|
|
|
|
|
|
else
|
|
|
|
|
|
puts "[WARN] bunkerweb-ui service status could not be verified"
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
puts ""
|
|
|
|
|
|
|
|
|
|
|
|
# Step 5: Now proceed with the original service creation logic
|
|
|
|
|
|
puts "[INFO] Connecting to BunkerWeb API..."
|
|
|
|
|
|
|
|
|
|
|
|
API_URL = "http://127.0.0.1:8888"
|
|
|
|
|
|
|
|
|
|
|
|
USERNAME = "admin"
|
|
|
|
|
|
PASSWORD = API_PASSWORD
|
|
|
|
|
|
|
|
|
|
|
|
# Default services to create after setup
|
|
|
|
|
|
DEFAULT_SERVICES = [
|
|
|
|
|
|
{
|
|
|
|
|
|
name: "#{server_ip_addr}",
|
|
|
|
|
|
options: {
|
|
|
|
|
|
ssl: "no",
|
|
|
|
|
|
reverse_proxy_host: "http://127.0.0.1:7000",
|
|
|
|
|
|
use_template: "ui",
|
2026-05-11 23:28:47 +03:00
|
|
|
|
reverse_proxy_url: "/kormilo",
|
2026-05-01 18:11:49 +03:00
|
|
|
|
use_reverse_proxy: "yes"
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
# Add more services here if needed:
|
|
|
|
|
|
# {
|
|
|
|
|
|
# name: "secure.example.com",
|
|
|
|
|
|
# options: {
|
|
|
|
|
|
# ssl: "yes",
|
|
|
|
|
|
# certificate_path: "/etc/ssl/certs/example.crt",
|
|
|
|
|
|
# key_path: "/etc/ssl/private/example.key"
|
|
|
|
|
|
# }
|
|
|
|
|
|
# }
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
begin
|
|
|
|
|
|
api = HestiaBunkerWebApi.new(API_URL, USERNAME, PASSWORD)
|
|
|
|
|
|
|
|
|
|
|
|
puts ""
|
|
|
|
|
|
puts "[SUCCESS] API connected successfully!"
|
|
|
|
|
|
puts ""
|
|
|
|
|
|
|
|
|
|
|
|
# List existing services
|
|
|
|
|
|
services = api.list_services()
|
|
|
|
|
|
services = api.list_services()
|
|
|
|
|
|
if services && services.is_a?(Hash) && services.key?('services')
|
|
|
|
|
|
services = services['services']
|
|
|
|
|
|
services = nil if services.is_a?(Array) && services.empty?
|
|
|
|
|
|
else
|
|
|
|
|
|
services = nil
|
|
|
|
|
|
end
|
|
|
|
|
|
if services.nil?
|
|
|
|
|
|
puts "[INFO] No services found - creating default configuration..."
|
|
|
|
|
|
|
|
|
|
|
|
DEFAULT_SERVICES.each do |service_config|
|
|
|
|
|
|
begin
|
|
|
|
|
|
puts "[INFO] Creating service: #{service_config[:name]}"
|
|
|
|
|
|
result = api.create_service(service_config[:name], service_config[:options])
|
|
|
|
|
|
puts " ✓ Service '#{service_config[:name]}' created"
|
|
|
|
|
|
rescue BunkerWebApiError => e
|
|
|
|
|
|
if e.message.include?("already exists")
|
|
|
|
|
|
puts " ℹ Service '#{service_config[:name]}' already exists, skipping..."
|
|
|
|
|
|
else
|
|
|
|
|
|
raise
|
|
|
|
|
|
end
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
puts "[SUCCESS] Default services created!"
|
|
|
|
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
puts "[INFO] Existing services:"
|
|
|
|
|
|
services.each { |s| puts " - #{s['server_name']}" }
|
|
|
|
|
|
puts ""
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
# Reload configuration on all instances
|
|
|
|
|
|
puts "[INFO] Reloading configuration..."
|
|
|
|
|
|
api.reload_instance()
|
|
|
|
|
|
|
|
|
|
|
|
puts "[INFO] Restarting bunkerweb service..."
|
|
|
|
|
|
system("systemctl restart bunkerweb")
|
|
|
|
|
|
puts "[INFO] Restarting bunkerweb-scheduler service..."
|
|
|
|
|
|
system("systemctl restart bunkerweb-scheduler")
|
|
|
|
|
|
|
|
|
|
|
|
puts ""
|
2026-05-02 17:50:56 +03:00
|
|
|
|
puts "======================================================"
|
2026-05-01 18:11:49 +03:00
|
|
|
|
puts "=== SETUP COMPLETED SUCCESSFULLY ==="
|
2026-05-02 17:50:56 +03:00
|
|
|
|
puts "======================================================"
|
2026-05-01 18:11:49 +03:00
|
|
|
|
puts ""
|
|
|
|
|
|
puts "Web UI is now accessible at:"
|
|
|
|
|
|
if ui_ssl_enabled == "yes"
|
2026-05-11 23:28:47 +03:00
|
|
|
|
puts " https://#{server_ip_addr}/kormilo"
|
2026-05-01 18:11:49 +03:00
|
|
|
|
else
|
2026-05-11 23:28:47 +03:00
|
|
|
|
puts " http://#{server_ip_addr}/kormilo"
|
2026-05-01 18:11:49 +03:00
|
|
|
|
end
|
|
|
|
|
|
puts ""
|
|
|
|
|
|
puts "API URL: #{API_URL}"
|
|
|
|
|
|
puts ""
|
|
|
|
|
|
puts "API Credentials:"
|
|
|
|
|
|
puts " Username: admin"
|
|
|
|
|
|
puts " Password: #{PASSWORD}"
|
|
|
|
|
|
puts ""
|
|
|
|
|
|
|
|
|
|
|
|
puts "UI Credentials:"
|
|
|
|
|
|
puts " Username: admin"
|
|
|
|
|
|
puts " Password: #{ADMIN_PASSWORD}"
|
|
|
|
|
|
puts ""
|
|
|
|
|
|
|
|
|
|
|
|
rescue BunkerWebApiError => e
|
|
|
|
|
|
|
|
|
|
|
|
if e.message.include?("Authentication") || e.message.include?("Connection refused")
|
|
|
|
|
|
puts "[ERROR] Could not connect to BunkerWeb API"
|
|
|
|
|
|
puts "[INFO] This means the setup has NOT been completed correctly"
|
|
|
|
|
|
puts ""
|
|
|
|
|
|
puts "Please verify that:"
|
|
|
|
|
|
puts " 1. bunkerweb-api service is running: systemctl status bunkerweb-api"
|
|
|
|
|
|
puts " 2. API configuration file exists at /etc/bunkerweb/api.env"
|
|
|
|
|
|
puts " 3. Check logs: journalctl -u bunkerweb-api -f"
|
|
|
|
|
|
puts ""
|
|
|
|
|
|
log_event E_INVALID, $ARGUMENTS
|
|
|
|
|
|
exit 1
|
|
|
|
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
puts "[ERROR] #{e.message}"
|
|
|
|
|
|
log_event E_INVALID, $ARGUMENTS
|
|
|
|
|
|
exit 1
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
rescue => e
|
|
|
|
|
|
puts "[ERROR] Unexpected error: #{e.message}"
|
|
|
|
|
|
puts "Backtrace:"
|
|
|
|
|
|
puts e.backtrace.inspect
|
|
|
|
|
|
log_event E_INVALID, $ARGUMENTS
|
|
|
|
|
|
exit 1
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
exit 0
|