This commit is contained in:
Alexey Berezhok
2026-05-16 00:10:12 +03:00
parent af9e6bfb82
commit 6ff9d67909
2 changed files with 208 additions and 8 deletions

208
bin/v-bunkerweb-migrate Normal file → Executable file
View File

@@ -9,6 +9,7 @@
# Commands:
# migratenginx - move old nginx configs to the new port and path
# migratetobunkerweb - create items of sites in the bunkerweb database
#
#------------------------------------------#
# Variables & Functions #
@@ -53,7 +54,7 @@ def log_migrate_stage(stage)
log_file = '/usr/local/hestia/log/bunkerweb_migrate_stages.log'
# Check if the stage has already been recorded
if File.exist?(log_file) && File.readlines(log_file).any? { |line| line.strip == stage }
puts "Stage #{stage} already completed, skipping."
hestia_print_error_message_to_cli "Stage #{stage} already completed, skipping."
return
end
# Execute the stage block
@@ -61,7 +62,7 @@ def log_migrate_stage(stage)
yield
# Record the successful stage
File.open(log_file, 'a') { |f| f.puts stage }
puts "Stage #{stage} completed."
hestia_print_error_message_to_cli "Stage #{stage} completed."
rescue => e
hestia_print_error_message_to_cli "Stage #{stage} failed: #{e.message}"
exit 1
@@ -226,7 +227,7 @@ when :migratenginx
# Write changes back if modified
if modified
File.open(conf_file, 'w') { |f| f.write(new_content) }
puts " Updated: #{conf_file}"
hestia_print_info_message_to_cli " Updated: #{conf_file}"
end
end
@@ -254,7 +255,7 @@ when :migratenginx
# Write changes if modified
if modified
File.open(default_conf, 'w') { |f| f.write(new_content) }
puts " Updated: #{default_conf}"
hestia_print_info_message_to_cli " Updated: #{default_conf}"
end
end
end
@@ -296,7 +297,204 @@ when :migratenginx
system('systemctl start nginx-system')
end
when :migratetobunkerweb
#TODO настройка bunkerweb
log_migrate_stage('stage10') do
if system('/usr/local/hestia/bin/v-ext-modules enable bunkerweb_module')
output = IO.popen("/usr/local/hestia/bin/v-ext-modules state bunkerweb_module json").read
begin
parsed = JSON.parse(output)
if parsed.is_a?(Array) && parsed.first && parsed.first['STATE'] == 'enabled'
result = system('/usr/local/hestia/bin/v-ext-modules-run bunkerweb_module configure')
unless result
hestia_print_error_message_to_cli "bunkerweb_module configure command failed"
exit 1
end
else
hestia_print_error_message_to_cli "bunkerweb_module not enabled after enable command"
exit 1
end
rescue JSON::ParserError => e
hestia_print_error_message_to_cli "Failed to parse JSON from state command: #{e.message}"
exit 1
end
else
hestia_print_error_message_to_cli "Failed to enable bunkerweb_module"
exit 1
end
end
LIST_DOMAINS=[]
log_migrate_stage('stage11') do
hestia_print_info_message_to_cli "Stage 11: Migrating users and domains to BunkerWeb..."
# Get all users from HestiaCP in JSON format
user_list_output = IO.popen("/usr/local/hestia/bin/v-list-users json").read
begin
user_data = JSON.parse(user_list_output)
rescue JSON::ParserError => e
hestia_print_error_message_to_cli "Failed to parse users JSON: #{e.message}"
exit 1
end
# Iterate over each user
user_data.each do |username, user_info|
next unless user_info.is_a?(Hash)
web_domains_count = user_info['U_WEB_DOMAINS']
next unless web_domains_count && web_domains_count.to_i > 0
hestia_print_info_message_to_cli "Processing user: #{username} (#{web_domains_count} domains)"
# Get web domains for this user in JSON format
domain_list_output = IO.popen("/usr/local/hestia/bin/v-list-web-domains #{username} json").read
begin
domain_data = JSON.parse(domain_list_output)
rescue JSON::ParserError => e
hestia_print_error_message_to_cli "Failed to parse domains JSON for user #{username}: #{e.message}"
next
end
# Process each domain
domain_data.each do |domain_name, domain_info|
next unless domain_info.is_a?(Hash)
ssl_status = domain_info['SSL'] || 'no'
is_ssl = ssl_status == 'yes'
# Create alias list from domain info (ALIAS field contains comma-separated aliases)
raw_aliases = domain_info['ALIAS'] || ''
if raw_aliases && !raw_aliases.empty?
# Hestia uses comma-separated, pass as-is to v-bunkerweb-module (it handles conversion internally)
aliases_list = raw_aliases
else
aliases_list = domain_name # No aliases, use domain name only
end
hestia_print_info_message_to_cli "Processing domain: #{domain_name} (SSL: #{is_ssl}, Aliases: #{aliases_list})"
begin
# Add domain to BunkerWeb via module script (without SSL)
output = IO.popen("/usr/local/hestia/bin/v-bunkerweb-module add #{domain_name} #{$PROXY_HOST}")
hestia_print_info_message_to_cli " Added #{domain_name}: #{output.strip}"
rescue => e
hestia_print_error_message_to_cli "Failed to add domain #{domain_name} to BunkerWeb: #{e.message}"
next
end
# Add aliases to the domain via module script
begin
output = IO.popen("/usr/local/hestia/bin/v-bunkerweb-module alias #{domain_name} \"#{aliases_list}\"")
hestia_print_info_message_to_cli " Added aliases for #{domain_name}: #{output.strip}"
rescue => e
hestia_print_error_message_to_cli "Failed to set aliases for #{domain_name}: #{e.message}"
next
end
# Handle SSL configuration if enabled
if is_ssl
original_ssl_dir = "/home/#{username}/conf/#{domain_name}/web/ssl"
# Check if SSL directory and files exist
unless Dir.exist?(original_ssl_dir) || File.exist?("#{original_ssl_dir}/#{domain_name}.pem")
hestia_print_error_message_to_cli "Warning: SSL files not found for #{domain_name}"
LIST_DOMAINS << {
user: username,
domain: domain_name,
is_ssl: true,
path_to_ssl: nil
}
next
end
# Define bunkerweb directory for this domain's certificates
bunkerweb_ssl_dir = "/home/#{username}/conf/web/#{domain_name}/ssl/bunkerweb"
begin
# Create bunkerweb SSL directory if it doesn't exist
FileUtils.mkdir_p(bunkerweb_ssl_dir)
Dir.chmod(bunkerweb_ssl_dir, 0755)
# Define paths in bunkerweb directory
cert_path_bunkerweb = "#{bunkerweb_ssl_dir}/#{domain_name}.pem"
key_path_bunkerweb = "#{bunkerweb_ssl_dir}/#{domain_name}.key"
# Copy all SSL files if they exist (matching v-add-web-domain-ssl behavior)
original_crt = "#{original_ssl_dir}/#{domain_name}.crt"
original_pem = "#{original_ssl_dir}/#{domain_name}.pem"
original_key = "#{original_ssl_dir}/#{domain_name}.key"
original_ca = "#{original_ssl_dir}/#{domain_name}.ca"
# Copy .crt file if exists
if File.exist?(original_crt)
FileUtils.cp("-f", original_crt, cert_path_bunkerweb)
elsif File.exist?(original_pem)
# Only use .pem if .crt doesn't exist (fallback like the backup script)
FileUtils.cp("-f", original_pem, cert_path_bunkerweb)
end
# Copy .key file if exists
if File.exist?(original_key)
FileUtils.cp("-f", original_key, key_path_bunkerweb)
end
# Copy .pem file if exists (in addition to .crt for backup purposes)
if File.exist?(original_pem)
FileUtils.cp("-f", original_pem, cert_path_bunkerweb)
end
# Copy .ca file if exists
if File.exist?(original_ca)
FileUtils.cp("-f", original_ca, "#{bunkerweb_ssl_dir}/#{domain_name}.ca")
end
# Set ownership and permissions (nginx user can read, others cannot)
Dir.chown(bunkerweb_ssl_dir, 'root', 'nginx')
Dir.chmod(bunkerweb_ssl_dir, 0755)
File.chown(cert_path_bunkerweb, 'root', 'nginx') if File.exist?(cert_path_bunkerweb)
File.chmod(cert_path_bunkerweb, 0640) if File.exist?(cert_path_bunkerweb)
File.chown(key_path_bunkerweb, 'root', 'nginx') if File.exist?(key_path_bunkerweb)
File.chmod(key_path_bunkerweb, 0640) if File.exist?(key_path_bunkerweb)
# Add SSL configuration to BunkerWeb via module script
output = IO.popen("/usr/local/hestia/bin/v-bunkerweb-module addssl #{domain_name} #{cert_path_bunkerweb} #{key_path_bunkerweb}")
hestia_print_error_message_to_cli " Added SSL for #{domain_name}: #{output.strip}"
# Update path_to_ssl to point to bunkerweb directory
ssl_cert_path = cert_path_bunkerweb
rescue => e
hestia_print_error_message_to_cli "Failed to configure SSL for #{domain_name}: #{e.message}"
end
end
# Populate LIST_DOMAINS array with domain info
LIST_DOMAINS << {
user: username,
domain: domain_name,
is_ssl: is_ssl,
path_to_ssl: ssl_cert_path ? ssl_cert_path : nil
}
hestia_print_info_message_to_cli "Successfully migrated #{domain_name} for user #{username}"
end
end
# Output the populated LIST_DOMAINS array
if !LIST_DOMAINS.empty?
hestia_print_info_message_to_cli "\n=== Populated LIST_DOMAINS ==="
LIST_DOMAINS.each_with_index do |entry, idx|
hestia_print_info_message_to_cli "#{idx + 1}. user: #{entry[:user]}, domain: #{entry[:domain]}, is_ssl: #{entry[:is_ssl].to_s}, path_to_ssl: #{entry[:path_to_ssl]}"
end
# Output as JSON for potential use in downstream scripts
hestia_print_info_message_to_cli "\n=== LIST_DOMAINS (JSON) ==="
hestia_print_info_message_to_cli JSON.generate(LIST_DOMAINS, { indent: 2 })
else
hestia_print_error_message_to_cli "No domains were migrated to BunkerWeb"
end
hestia_print_info_message_to_cli "Stage 11 completed."
end
else
hestia_print_error_message_to_cli "unknown command"
log_event E_ARGS, $ARGUMENTS

View File

@@ -77,6 +77,10 @@ class File
end
end
def hestia_print_info_message_to_cli(error_message)
puts "Info: #{error_message}"
end
def hestia_print_error_message_to_cli(error_message)
puts "Error: #{error_message}"
end
@@ -323,7 +327,7 @@ def hestia_change_sys_config_value(key, value)
config_file = "/usr/local/hestia/conf/hestia.conf"
if File.exist?(config_file)
File.open(config_file, File::RDWR | File::LOCK_SH) do |f|
File.open(config_file, File::RDWR) do |f|
# Check if key exists in the configuration file
existing_line_index = -1
@@ -343,7 +347,6 @@ def hestia_change_sys_config_value(key, value)
if existing_line_index.nil? || existing_line_index == -1
# Key doesn't exist - append new line to file
File.open(config_file, "a") do |append_f|
append_f.flock(File::LOCK_EX)
append_f.puts("#{key}='#{value}'")
end
OK
@@ -370,7 +373,6 @@ def hestia_change_sys_config_value(key, value)
end
File.open(temp_file, "w") do |output_f|
output_f.flock(File::LOCK_EX)
lines.each { |l| output_f.puts(l) }
end