feat: ssh auth, protocol management, and cleanup

This commit is contained in:
infosave2007
2026-01-23 17:55:40 +03:00
parent 60fc55fd47
commit bbab877eac
70 changed files with 16225 additions and 986 deletions
+788
View File
@@ -0,0 +1,788 @@
INSERT INTO translations (locale, category, key_name, translation) VALUES
('en','servers','backup_upload_type','Backup type'),
('en','servers','backup_type_auto','Auto detect'),
('en','servers','backup_type_amnezia','Amnezia app (.backup)'),
('en','servers','backup_type_panel','Panel export (.json)'),
('en','servers','backup_upload_hint','Upload a .backup or .json file. After upload, pick a server entry above.'),
('ru','servers','backup_upload_type','Тип бэкапа'),
('ru','servers','backup_type_auto','Определить автоматически'),
('ru','servers','backup_type_amnezia','Приложение Amnezia (.backup)'),
('ru','servers','backup_type_panel','Экспорт панели (.json)'),
('ru','servers','backup_upload_hint','Загрузите файл .backup или .json. После загрузки выберите сервер выше.'),
('es','servers','backup_upload_type','Tipo de copia de seguridad'),
('es','servers','backup_type_auto','Detectar automáticamente'),
('es','servers','backup_type_amnezia','Aplicación Amnezia (.backup)'),
('es','servers','backup_type_panel','Exportación del panel (.json)'),
('es','servers','backup_upload_hint','Suba un archivo .backup o .json. Después seleccione el servidor arriba.'),
('de','servers','backup_upload_type','Backup-Typ'),
('de','servers','backup_type_auto','Automatisch erkennen'),
('de','servers','backup_type_amnezia','Amnezia-App (.backup)'),
('de','servers','backup_type_panel','Panel-Export (.json)'),
('de','servers','backup_upload_hint','Laden Sie eine .backup- oder .json-Datei hoch. Wählen Sie anschließend oben einen Server aus.'),
('fr','servers','backup_upload_type','Type de sauvegarde'),
('fr','servers','backup_type_auto','Détection automatique'),
('fr','servers','backup_type_amnezia','Application Amnezia (.backup)'),
('fr','servers','backup_type_panel','Export du panneau (.json)'),
('fr','servers','backup_upload_hint','Téléversez un fichier .backup ou .json, puis sélectionnez un serveur ci-dessus.'),
('zh','servers','backup_upload_type','备份类型'),
('zh','servers','backup_type_auto','自动检测'),
('zh','servers','backup_type_amnezia','Amnezia 应用 (.backup)'),
('zh','servers','backup_type_panel','面板导出 (.json)'),
('zh','servers','backup_upload_hint','上传 .backup 或 .json 文件,随后在上方选择服务器。')
ON DUPLICATE KEY UPDATE translation = VALUES(translation);
INSERT INTO translations (locale, category, key_name, translation) VALUES
('en', 'servers', 'config_import_title', 'Import configuration'),
('en', 'servers', 'config_import_hint', 'Upload a configuration backup to update this server and its clients.'),
('en', 'servers', 'config_import_type_label', 'Backup type'),
('en', 'servers', 'config_import_type_panel', 'Panel backup (.json)'),
('en', 'servers', 'config_import_type_amnezia', 'Amnezia app backup (.backup)'),
('en', 'servers', 'config_import_file_label', 'Configuration file'),
('en', 'servers', 'config_import_file_hint', 'Our panel uses .json files. The Amnezia app uses .backup files.'),
('en', 'servers', 'config_import_submit', 'Import configuration'),
('ru', 'servers', 'config_import_title', 'Импорт конфигурации'),
('ru', 'servers', 'config_import_hint', 'Загрузите файл бэкапа, чтобы обновить настройки сервера и список клиентов.'),
('ru', 'servers', 'config_import_type_label', 'Источник бэкапа'),
('ru', 'servers', 'config_import_type_panel', 'Бэкап панели (.json)'),
('ru', 'servers', 'config_import_type_amnezia', 'Бэкап приложения Amnezia (.backup)'),
('ru', 'servers', 'config_import_file_label', 'Файл конфигурации'),
('ru', 'servers', 'config_import_file_hint', 'Панель использует файлы .json. Приложение Amnezia — файлы .backup.'),
('ru', 'servers', 'config_import_submit', 'Импортировать конфигурацию'),
('es', 'servers', 'config_import_title', 'Importar configuración'),
('es', 'servers', 'config_import_hint', 'Cargue un respaldo para actualizar este servidor y sus clientes.'),
('es', 'servers', 'config_import_type_label', 'Tipo de backup'),
('es', 'servers', 'config_import_type_panel', 'Backup del panel (.json)'),
('es', 'servers', 'config_import_type_amnezia', 'Backup de la app Amnezia (.backup)'),
('es', 'servers', 'config_import_file_label', 'Archivo de configuración'),
('es', 'servers', 'config_import_file_hint', 'El panel usa archivos .json. La app Amnezia usa archivos .backup.'),
('es', 'servers', 'config_import_submit', 'Importar configuración'),
('de', 'servers', 'config_import_title', 'Konfiguration importieren'),
('de', 'servers', 'config_import_hint', 'Laden Sie eine Sicherung hoch, um diesen Server und seine Clients zu aktualisieren.'),
('de', 'servers', 'config_import_type_label', 'Backup-Typ'),
('de', 'servers', 'config_import_type_panel', 'Panel-Backup (.json)'),
('de', 'servers', 'config_import_type_amnezia', 'Amnezia-App-Backup (.backup)'),
('de', 'servers', 'config_import_file_label', 'Konfigurationsfile'),
('de', 'servers', 'config_import_file_hint', 'Die Panel-Backups sind .json. Die Amnezia-App nutzt .backup-Dateien.'),
('de', 'servers', 'config_import_submit', 'Konfiguration importieren'),
('fr', 'servers', 'config_import_title', 'Importer la configuration'),
('fr', 'servers', 'config_import_hint', 'Téléversez un fichier de sauvegarde pour mettre à jour ce serveur et ses clients.'),
('fr', 'servers', 'config_import_type_label', 'Type de sauvegarde'),
('fr', 'servers', 'config_import_type_panel', 'Sauvegarde du panneau (.json)'),
('fr', 'servers', 'config_import_type_amnezia', 'Sauvegarde de lapplication Amnezia (.backup)'),
('fr', 'servers', 'config_import_file_label', 'Fichier de configuration'),
('fr', 'servers', 'config_import_file_hint', 'Notre panneau utilise des fichiers .json. Lapplication Amnezia utilise des fichiers .backup.'),
('fr', 'servers', 'config_import_submit', 'Importer la configuration'),
('zh', 'servers', 'config_import_title', '导入配置'),
('zh', 'servers', 'config_import_hint', '上传备份文件以更新此服务器及其客户端。'),
('zh', 'servers', 'config_import_type_label', '备份类型'),
('zh', 'servers', 'config_import_type_panel', '面板备份 (.json)'),
('zh', 'servers', 'config_import_type_amnezia', 'Amnezia 应用备份 (.backup)'),
('zh', 'servers', 'config_import_file_label', '配置文件'),
('zh', 'servers', 'config_import_file_hint', '面板使用 .json 文件,Amnezia 应用使用 .backup 文件。'),
('zh', 'servers', 'config_import_submit', '导入配置')
ON DUPLICATE KEY UPDATE translation = VALUES(translation);
INSERT INTO translations (locale, category, key_name, translation) VALUES
('en','servers','creation_mode','Creation mode'),
('en','servers','creation_mode_manual','Manual setup'),
('en','servers','creation_mode_backup','Import from backup'),
('en','servers','upload_backup_file','Upload backup file'),
('en','servers','backup_upload_hint','Supported formats: panel JSON export or Amnezia application .backup'),
('en','servers','backup_server_entry','Select server entry'),
('en','servers','backup_summary_host','Host'),
('en','servers','backup_summary_clients','Clients'),
('en','servers','config_import_title','Restore configuration from backup'),
('en','servers','config_import_hint','Import server configuration (and optional clients) from a panel export or Amnezia application backup.'),
('en','servers','config_import_type_label','Backup type'),
('en','servers','config_import_type_panel','Panel export (.json)'),
('en','servers','config_import_type_amnezia','Amnezia app backup (.backup)'),
('en','servers','config_import_file_label','Configuration file'),
('en','servers','config_import_file_hint','The file remains on the server only during import and is deleted afterwards.'),
('en','servers','config_import_submit','Import configuration'),
('ru','servers','creation_mode','Режим создания'),
('ru','servers','creation_mode_manual','Ручная настройка'),
('ru','servers','creation_mode_backup','Импорт из бэкапа'),
('ru','servers','upload_backup_file','Загрузите файл бэкапа'),
('ru','servers','backup_upload_hint','Поддерживаются форматы: экспорт панели JSON или бэкап приложения Amnezia (.backup)'),
('ru','servers','backup_server_entry','Выберите запись сервера'),
('ru','servers','backup_summary_host','Хост'),
('ru','servers','backup_summary_clients','Клиенты'),
('ru','servers','config_import_title','Восстановление конфигурации из бэкапа'),
('ru','servers','config_import_hint','Импортируйте конфигурацию сервера (и при необходимости клиентов) из экспорта панели или бэкапа приложения Amnezia.'),
('ru','servers','config_import_type_label','Тип бэкапа'),
('ru','servers','config_import_type_panel','Экспорт панели (.json)'),
('ru','servers','config_import_type_amnezia','Бэкап приложения Amnezia (.backup)'),
('ru','servers','config_import_file_label','Файл конфигурации'),
('ru','servers','config_import_file_hint','Файл хранится на сервере только во время импорта и удаляется сразу после завершения.'),
('ru','servers','config_import_submit','Импортировать конфигурацию')
ON DUPLICATE KEY UPDATE translation = VALUES(translation);
CREATE TABLE IF NOT EXISTS protocols (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
slug VARCHAR(100) UNIQUE NOT NULL,
description TEXT,
install_script TEXT,
output_template TEXT,
ubuntu_compatible BOOLEAN DEFAULT false,
is_active BOOLEAN DEFAULT true,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_protocols_slug (slug),
INDEX idx_protocols_active (is_active),
INDEX idx_protocols_ubuntu_compatible (ubuntu_compatible)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS protocol_templates (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
protocol_id INT UNSIGNED NOT NULL,
template_name VARCHAR(255) NOT NULL,
template_content TEXT NOT NULL,
is_default BOOLEAN DEFAULT false,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_protocol_templates_protocol (protocol_id),
INDEX idx_protocol_templates_default (is_default),
FOREIGN KEY (protocol_id) REFERENCES protocols(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS protocol_variables (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
protocol_id INT UNSIGNED NOT NULL,
variable_name VARCHAR(100) NOT NULL,
variable_type VARCHAR(50) NOT NULL DEFAULT 'string',
default_value TEXT,
description TEXT,
required BOOLEAN DEFAULT false,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_protocol_variables_protocol (protocol_id),
INDEX idx_protocol_variables_name (variable_name),
FOREIGN KEY (protocol_id) REFERENCES protocols(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS server_protocols (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
server_id INT UNSIGNED NOT NULL,
protocol_id INT UNSIGNED NOT NULL,
config_data JSON,
applied_at TIMESTAMP NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_server_protocols_server (server_id),
INDEX idx_server_protocols_protocol (protocol_id),
INDEX idx_server_protocols_applied (applied_at),
UNIQUE KEY unique_server_protocol (server_id, protocol_id),
FOREIGN KEY (server_id) REFERENCES vpn_servers(id) ON DELETE CASCADE,
FOREIGN KEY (protocol_id) REFERENCES protocols(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS ai_generations (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
protocol_id INT UNSIGNED NULL,
model_used VARCHAR(100) NOT NULL,
prompt TEXT NOT NULL,
generated_script TEXT,
suggestions JSON,
ubuntu_compatible BOOLEAN,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_ai_generations_protocol (protocol_id),
INDEX idx_ai_generations_model (model_used),
INDEX idx_ai_generations_created (created_at DESC),
FOREIGN KEY (protocol_id) REFERENCES protocols(id) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO protocols (name, slug, description, install_script, output_template, ubuntu_compatible, is_active)
SELECT 'AmneziaWG Advanced', 'amnezia-wg-advanced', 'AmneziaWG protocol with advanced junk packet obfuscation parameters', '#!/bin/bash
echo "AmneziaWG Advanced installed"
', '[Interface]
PrivateKey = {{private_key}}
Address = {{client_ip}}/32
DNS = 8.8.8.8, 8.8.4.4
[Peer]
PublicKey = {{server_public_key}}
PresharedKey = {{preshared_key}}
Endpoint = {{server_host}}:{{server_port}}
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25
Jc = {{jc}}
Jmin = {{jmin}}
Jmax = {{jmax}}
S1 = {{s1}}
S2 = {{s2}}
H1 = {{h1}}
H2 = {{h2}}
H3 = {{h3}}
H4 = {{h4}}', true, true
WHERE NOT EXISTS (SELECT 1 FROM protocols WHERE slug='amnezia-wg-advanced');
INSERT INTO protocols (name, slug, description, install_script, output_template, ubuntu_compatible, is_active)
SELECT 'WireGuard Standard', 'wireguard-standard', 'Standard WireGuard VPN protocol', '#!/bin/bash
CONTAINER_NAME="wireguard"
VPN_SUBNET="10.8.2.0/24"
PRIVATE_KEY=$(wg genkey)
PUBLIC_KEY=$(echo $PRIVATE_KEY | wg pubkey)
PRESHARED_KEY=$(wg genpsk)
docker run -d \
--name $CONTAINER_NAME \
--cap-add=NET_ADMIN \
--cap-add=SYS_MODULE \
-v /opt/wireguard:/etc/wireguard \
linuxserver/wireguard
cat > /opt/wireguard/wg0.conf << EOF
[Interface]
PrivateKey = $PRIVATE_KEY
Address = 10.8.2.1/24
ListenPort = 51820
[Peer]
PublicKey =
PresharedKey = $PRESHARED_KEY
AllowedIPs = 10.8.2.2/32
EOF
echo "WireGuard Standard installed successfully"
echo "Server Public Key: $PUBLIC_KEY"', '[Interface]
PrivateKey = {{private_key}}
Address = {{client_ip}}/32
DNS = 8.8.8.8, 8.8.4.4
[Peer]
PublicKey = {{server_public_key}}
PresharedKey = {{preshared_key}}
Endpoint = {{server_host}}:{{server_port}}
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25', true, true
WHERE NOT EXISTS (SELECT 1 FROM protocols WHERE slug='wireguard-standard');
INSERT INTO protocols (name, slug, description, install_script, output_template, ubuntu_compatible, is_active)
SELECT 'OpenVPN', 'openvpn', 'OpenVPN protocol with TCP/UDP support', '#!/bin/bash
CONTAINER_NAME="openvpn"
VPN_SUBNET="10.8.3.0/24"
docker run -d \
--name $CONTAINER_NAME \
--cap-add=NET_ADMIN \
-p 1194:1194/udp \
-p 1194:1194/tcp \
-v /opt/openvpn:/etc/openvpn \
kylemanna/openvpn
docker exec -it $CONTAINER_NAME ovpn_genconfig -u udp://{{server_host}}:1194
docker exec -it $CONTAINER_NAME ovpn_initpki
echo "OpenVPN installed successfully"
echo "Available on ports: 1194/udp, 1194/tcp"', 'client
dev tun
proto {{protocol}}
remote {{server_host}} {{server_port}}
resolv-retry infinite
nobind
persist-key
persist-tun
ca ca.crt
cert client.crt
key client.key
remote-cert-tls server
cipher AES-256-GCM
auth SHA256
verb 3', true, true
WHERE NOT EXISTS (SELECT 1 FROM protocols WHERE slug='openvpn');
INSERT INTO protocols (name, slug, description, install_script, output_template, ubuntu_compatible, is_active)
SELECT 'Shadowsocks', 'shadowsocks', 'Shadowsocks proxy protocol', '#!/bin/bash
CONTAINER_NAME="shadowsocks"
PASSWORD=$(openssl rand -base64 12)
docker run -d \
--name $CONTAINER_NAME \
-p 8388:8388 \
-e METHOD=aes-256-gcm \
-e PASSWORD=$PASSWORD \
shadowsocks/shadowsocks-libev
echo "Shadowsocks installed successfully"
echo "Port: 8388"
echo "Method: aes-256-gcm"
echo "Password: $PASSWORD"', '{
"server": "{{server_host}}",
"server_port": {{server_port}},
"password": "{{password}}",
"method": "{{method}}"
}', true, true
WHERE NOT EXISTS (SELECT 1 FROM protocols WHERE slug='shadowsocks');
INSERT INTO protocol_templates (protocol_id, template_name, template_content, is_default)
SELECT p.id, 'Default AmneziaWG', '[Interface]
PrivateKey = {{private_key}}
Address = {{client_ip}}/32
DNS = 8.8.8.8, 8.8.4.4
[Peer]
PublicKey = {{server_public_key}}
PresharedKey = {{preshared_key}}
Endpoint = {{server_host}}:{{server_port}}
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25
Jc = {{jc}}
Jmin = {{jmin}}
Jmax = {{jmax}}
S1 = {{s1}}
S2 = {{s2}}
H1 = {{h1}}
H2 = {{h2}}
H3 = {{h3}}
H4 = {{h4}}', true
FROM protocols p WHERE p.slug='amnezia-wg-advanced' AND NOT EXISTS (SELECT 1 FROM protocol_templates WHERE protocol_id=p.id AND template_name='Default AmneziaWG');
INSERT INTO protocol_templates (protocol_id, template_name, template_content, is_default)
SELECT p.id, 'Default WireGuard', '[Interface]
PrivateKey = {{private_key}}
Address = {{client_ip}}/32
DNS = 8.8.8.8, 8.8.4.4
[Peer]
PublicKey = {{server_public_key}}
PresharedKey = {{preshared_key}}
Endpoint = {{server_host}}:{{server_port}}
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25', true
FROM protocols p WHERE p.slug='wireguard-standard' AND NOT EXISTS (SELECT 1 FROM protocol_templates WHERE protocol_id=p.id AND template_name='Default WireGuard');
INSERT INTO protocol_templates (protocol_id, template_name, template_content, is_default)
SELECT p.id, 'Default OpenVPN', 'client
dev tun
proto {{protocol}}
remote {{server_host}} {{server_port}}
resolv-retry infinite
nobind
persist-key
persist-tun
ca ca.crt
cert client.crt
key client.key
remote-cert-tls server
cipher AES-256-GCM
auth SHA256
verb 3', true
FROM protocols p WHERE p.slug='openvpn' AND NOT EXISTS (SELECT 1 FROM protocol_templates WHERE protocol_id=p.id AND template_name='Default OpenVPN');
INSERT INTO protocol_templates (protocol_id, template_name, template_content, is_default)
SELECT p.id, 'Default Shadowsocks', '{
"server": "{{server_host}}",
"server_port": {{server_port}},
"password": "{{password}}",
"method": "{{method}}"
}', true
FROM protocols p WHERE p.slug='shadowsocks' AND NOT EXISTS (SELECT 1 FROM protocol_templates WHERE protocol_id=p.id AND template_name='Default Shadowsocks');
INSERT INTO protocol_variables (protocol_id, variable_name, variable_type, default_value, description, required)
SELECT p.id, 'private_key', 'string', '', 'Client private key', true FROM protocols p WHERE p.slug='amnezia-wg-advanced' AND NOT EXISTS (SELECT 1 FROM protocol_variables WHERE protocol_id=p.id AND variable_name='private_key');
INSERT INTO protocol_variables (protocol_id, variable_name, variable_type, default_value, description, required)
SELECT p.id, 'client_ip', 'string', '10.8.1.2', 'Client IP address', true FROM protocols p WHERE p.slug='amnezia-wg-advanced' AND NOT EXISTS (SELECT 1 FROM protocol_variables WHERE protocol_id=p.id AND variable_name='client_ip');
INSERT INTO protocol_variables (protocol_id, variable_name, variable_type, default_value, description, required)
SELECT p.id, 'server_public_key', 'string', '', 'Server public key', true FROM protocols p WHERE p.slug='amnezia-wg-advanced' AND NOT EXISTS (SELECT 1 FROM protocol_variables WHERE protocol_id=p.id AND variable_name='server_public_key');
INSERT INTO protocol_variables (protocol_id, variable_name, variable_type, default_value, description, required)
SELECT p.id, 'preshared_key', 'string', '', 'Pre-shared key for additional security', true FROM protocols p WHERE p.slug='amnezia-wg-advanced' AND NOT EXISTS (SELECT 1 FROM protocol_variables WHERE protocol_id=p.id AND variable_name='preshared_key');
INSERT INTO protocol_variables (protocol_id, variable_name, variable_type, default_value, description, required)
SELECT p.id, 'server_host', 'string', '', 'Server hostname or IP', true FROM protocols p WHERE p.slug='amnezia-wg-advanced' AND NOT EXISTS (SELECT 1 FROM protocol_variables WHERE protocol_id=p.id AND variable_name='server_host');
INSERT INTO protocol_variables (protocol_id, variable_name, variable_type, default_value, description, required)
SELECT p.id, 'server_port', 'number', '51820', 'Server port', true FROM protocols p WHERE p.slug='amnezia-wg-advanced' AND NOT EXISTS (SELECT 1 FROM protocol_variables WHERE protocol_id=p.id AND variable_name='server_port');
INSERT INTO protocol_variables (protocol_id, variable_name, variable_type, default_value, description, required)
SELECT p.id, 'jc', 'number', '4', 'Junk packet count', false FROM protocols p WHERE p.slug='amnezia-wg-advanced' AND NOT EXISTS (SELECT 1 FROM protocol_variables WHERE protocol_id=p.id AND variable_name='jc');
INSERT INTO protocol_variables (protocol_id, variable_name, variable_type, default_value, description, required)
SELECT p.id, 'jmin', 'number', '50', 'Minimum junk packet size', false FROM protocols p WHERE p.slug='amnezia-wg-advanced' AND NOT EXISTS (SELECT 1 FROM protocol_variables WHERE protocol_id=p.id AND variable_name='jmin');
INSERT INTO protocol_variables (protocol_id, variable_name, variable_type, default_value, description, required)
SELECT p.id, 'jmax', 'number', '1000', 'Maximum junk packet size', false FROM protocols p WHERE p.slug='amnezia-wg-advanced' AND NOT EXISTS (SELECT 1 FROM protocol_variables WHERE protocol_id=p.id AND variable_name='jmax');
INSERT INTO protocol_variables (protocol_id, variable_name, variable_type, default_value, description, required)
SELECT p.id, 's1', 'number', '148', 'Junk packet size 1', false FROM protocols p WHERE p.slug='amnezia-wg-advanced' AND NOT EXISTS (SELECT 1 FROM protocol_variables WHERE protocol_id=p.id AND variable_name='s1');
INSERT INTO protocol_variables (protocol_id, variable_name, variable_type, default_value, description, required)
SELECT p.id, 's2', 'number', '450', 'Junk packet size 2', false FROM protocols p WHERE p.slug='amnezia-wg-advanced' AND NOT EXISTS (SELECT 1 FROM protocol_variables WHERE protocol_id=p.id AND variable_name='s2');
INSERT INTO protocol_variables (protocol_id, variable_name, variable_type, default_value, description, required)
SELECT p.id, 'h1', 'number', '320121696', 'Junk packet header 1', false FROM protocols p WHERE p.slug='amnezia-wg-advanced' AND NOT EXISTS (SELECT 1 FROM protocol_variables WHERE protocol_id=p.id AND variable_name='h1');
INSERT INTO protocol_variables (protocol_id, variable_name, variable_type, default_value, description, required)
SELECT p.id, 'h2', 'number', '51525354', 'Junk packet header 2', false FROM protocols p WHERE p.slug='amnezia-wg-advanced' AND NOT EXISTS (SELECT 1 FROM protocol_variables WHERE protocol_id=p.id AND variable_name='h2');
INSERT INTO protocol_variables (protocol_id, variable_name, variable_type, default_value, description, required)
SELECT p.id, 'h3', 'number', '13141516', 'Junk packet header 3', false FROM protocols p WHERE p.slug='amnezia-wg-advanced' AND NOT EXISTS (SELECT 1 FROM protocol_variables WHERE protocol_id=p.id AND variable_name='h3');
INSERT INTO protocol_variables (protocol_id, variable_name, variable_type, default_value, description, required)
SELECT p.id, 'h4', 'number', '92435495', 'Junk packet header 4', false FROM protocols p WHERE p.slug='amnezia-wg-advanced' AND NOT EXISTS (SELECT 1 FROM protocol_variables WHERE protocol_id=p.id AND variable_name='h4');
INSERT INTO protocol_variables (protocol_id, variable_name, variable_type, default_value, description, required)
SELECT p.id, 'private_key', 'string', '', 'Client private key', true FROM protocols p WHERE p.slug='wireguard-standard' AND NOT EXISTS (SELECT 1 FROM protocol_variables WHERE protocol_id=p.id AND variable_name='private_key');
INSERT INTO protocol_variables (protocol_id, variable_name, variable_type, default_value, description, required)
SELECT p.id, 'client_ip', 'string', '10.8.2.2', 'Client IP address', true FROM protocols p WHERE p.slug='wireguard-standard' AND NOT EXISTS (SELECT 1 FROM protocol_variables WHERE protocol_id=p.id AND variable_name='client_ip');
INSERT INTO protocol_variables (protocol_id, variable_name, variable_type, default_value, description, required)
SELECT p.id, 'server_public_key', 'string', '', 'Server public key', true FROM protocols p WHERE p.slug='wireguard-standard' AND NOT EXISTS (SELECT 1 FROM protocol_variables WHERE protocol_id=p.id AND variable_name='server_public_key');
INSERT INTO protocol_variables (protocol_id, variable_name, variable_type, default_value, description, required)
SELECT p.id, 'preshared_key', 'string', '', 'Pre-shared key for additional security', true FROM protocols p WHERE p.slug='wireguard-standard' AND NOT EXISTS (SELECT 1 FROM protocol_variables WHERE protocol_id=p.id AND variable_name='preshared_key');
INSERT INTO protocol_variables (protocol_id, variable_name, variable_type, default_value, description, required)
SELECT p.id, 'server_host', 'string', '', 'Server hostname or IP', true FROM protocols p WHERE p.slug='wireguard-standard' AND NOT EXISTS (SELECT 1 FROM protocol_variables WHERE protocol_id=p.id AND variable_name='server_host');
INSERT INTO protocol_variables (protocol_id, variable_name, variable_type, default_value, description, required)
SELECT p.id, 'server_port', 'number', '51820', 'Server port', true FROM protocols p WHERE p.slug='wireguard-standard' AND NOT EXISTS (SELECT 1 FROM protocol_variables WHERE protocol_id=p.id AND variable_name='server_port');
INSERT INTO protocol_variables (protocol_id, variable_name, variable_type, default_value, description, required)
SELECT p.id, 'protocol', 'string', 'udp', 'Connection protocol (udp/tcp)', true FROM protocols p WHERE p.slug='openvpn' AND NOT EXISTS (SELECT 1 FROM protocol_variables WHERE protocol_id=p.id AND variable_name='protocol');
INSERT INTO protocol_variables (protocol_id, variable_name, variable_type, default_value, description, required)
SELECT p.id, 'server_host', 'string', '', 'Server hostname or IP', true FROM protocols p WHERE p.slug='openvpn' AND NOT EXISTS (SELECT 1 FROM protocol_variables WHERE protocol_id=p.id AND variable_name='server_host');
INSERT INTO protocol_variables (protocol_id, variable_name, variable_type, default_value, description, required)
SELECT p.id, 'server_port', 'number', '1194', 'Server port', true FROM protocols p WHERE p.slug='openvpn' AND NOT EXISTS (SELECT 1 FROM protocol_variables WHERE protocol_id=p.id AND variable_name='server_port');
INSERT INTO protocol_variables (protocol_id, variable_name, variable_type, default_value, description, required)
SELECT p.id, 'server_host', 'string', '', 'Server hostname or IP', true FROM protocols p WHERE p.slug='shadowsocks' AND NOT EXISTS (SELECT 1 FROM protocol_variables WHERE protocol_id=p.id AND variable_name='server_host');
INSERT INTO protocol_variables (protocol_id, variable_name, variable_type, default_value, description, required)
SELECT p.id, 'server_port', 'number', '8388', 'Server port', true FROM protocols p WHERE p.slug='shadowsocks' AND NOT EXISTS (SELECT 1 FROM protocol_variables WHERE protocol_id=p.id AND variable_name='server_port');
INSERT INTO protocol_variables (protocol_id, variable_name, variable_type, default_value, description, required)
SELECT p.id, 'password', 'string', '', 'Connection password', true FROM protocols p WHERE p.slug='shadowsocks' AND NOT EXISTS (SELECT 1 FROM protocol_variables WHERE protocol_id=p.id AND variable_name='password');
INSERT INTO translations (locale, category, key_name, translation) VALUES
('en','common','cancel','Cancel'),
('ru','common','cancel','Отмена'),
('es','common','cancel','Cancelar'),
('de','common','cancel','Abbrechen'),
('fr','common','cancel','Annuler'),
('zh','common','cancel','取消'),
('en','common','format','Format'),
('ru','common','format','Форматировать'),
('es','common','format','Formatear'),
('de','common','format','Formatieren'),
('fr','common','format','Formater'),
('zh','common','format','格式化'),
('en','common','clear','Clear'),
('ru','common','clear','Очистить'),
('es','common','clear','Borrar'),
('de','common','clear','Leeren'),
('fr','common','clear','Effacer'),
('zh','common','clear','清空'),
('en','protocols','template_editor_help','Use placeholders like {{variable}} and preview client output'),
('ru','protocols','template_editor_help','Используйте плейсхолдеры вида {{variable}} и просматривайте вывод клиента'),
('es','protocols','template_editor_help','Usa marcadores como {{variable}} y previsualiza la salida del cliente'),
('de','protocols','template_editor_help','Verwenden Sie Platzhalter wie {{variable}} und sehen Sie die ClientAusgabe in der Vorschau'),
('fr','protocols','template_editor_help','Utilisez des placeholders comme {{variable}} et prévisualisez la sortie client'),
('zh','protocols','template_editor_help','使用如 {{variable}} 的占位符并预览客户端输出'),
('en','protocols','variable_private_key_help','Client private key'),
('ru','protocols','variable_private_key_help','Приватный ключ клиента'),
('es','protocols','variable_private_key_help','Clave privada del cliente'),
('de','protocols','variable_private_key_help','Privater Schlüssel des Clients'),
('fr','protocols','variable_private_key_help','Clé privée du client'),
('zh','protocols','variable_private_key_help','客户端私钥'),
('en','protocols','variable_public_key_help','Server public key'),
('ru','protocols','variable_public_key_help','Публичный ключ сервера'),
('es','protocols','variable_public_key_help','Clave pública del servidor'),
('de','protocols','variable_public_key_help','Öffentlicher Schlüssel des Servers'),
('fr','protocols','variable_public_key_help','Clé publique du serveur'),
('zh','protocols','variable_public_key_help','服务器公钥'),
('en','protocols','variable_client_ip_help','Client IP address'),
('ru','protocols','variable_client_ip_help','IP‑адрес клиента'),
('es','protocols','variable_client_ip_help','Dirección IP del cliente'),
('de','protocols','variable_client_ip_help','IPAdresse des Clients'),
('fr','protocols','variable_client_ip_help','Adresse IP du client'),
('zh','protocols','variable_client_ip_help','客户端 IP 地址'),
('en','protocols','variable_server_host_help','VPN server host'),
('ru','protocols','variable_server_host_help','Хост VPN‑сервера'),
('es','protocols','variable_server_host_help','Host del servidor VPN'),
('de','protocols','variable_server_host_help','VPNServerHost'),
('fr','protocols','variable_server_host_help','Hôte du serveur VPN'),
('zh','protocols','variable_server_host_help','VPN 服务器主机'),
('en','protocols','variable_server_port_help','VPN server port'),
('ru','protocols','variable_server_port_help','Порт VPN‑сервера'),
('es','protocols','variable_server_port_help','Puerto del servidor VPN'),
('de','protocols','variable_server_port_help','VPNServerPort'),
('fr','protocols','variable_server_port_help','Port du serveur VPN'),
('zh','protocols','variable_server_port_help','VPN 服务器端口'),
('en','protocols','variable_preshared_key_help','WireGuard preshared key'),
('ru','protocols','variable_preshared_key_help','Предварительно общий ключ WireGuard'),
('es','protocols','variable_preshared_key_help','Clave precompartida de WireGuard'),
('de','protocols','variable_preshared_key_help','WireGuardvorausgeteilter Schlüssel'),
('fr','protocols','variable_preshared_key_help','Clé prépartagée WireGuard'),
('zh','protocols','variable_preshared_key_help','WireGuard 预共享密钥')
ON DUPLICATE KEY UPDATE translation = VALUES(translation);
INSERT INTO translations (locale, category, key_name, translation) VALUES
('en','ai','enter_protocol_id_to_apply','Enter protocol ID to apply'),
('ru','ai','enter_protocol_id_to_apply','Введите ID протокола для применения'),
('es','ai','enter_protocol_id_to_apply','Introduce el ID de protocolo para aplicar'),
('de','ai','enter_protocol_id_to_apply','ProtokollID zum Anwenden eingeben'),
('fr','ai','enter_protocol_id_to_apply','Saisissez lID du protocole à appliquer'),
('zh','ai','enter_protocol_id_to_apply','输入要应用的协议 ID'),
('en','ai','improve_protocol','Improve protocol script for'),
('ru','ai','improve_protocol','Улучшить скрипт протокола для'),
('es','ai','improve_protocol','Mejorar script del protocolo для'),
('de','ai','improve_protocol','Protokollskript verbessern für'),
('fr','ai','improve_protocol','Améliorer le script du protocole pour'),
('zh','ai','improve_protocol','改进协议脚本:'),
('en','protocols','enter_protocol_name','Enter protocol name'),
('ru','protocols','enter_protocol_name','Введите имя протокола'),
('es','protocols','enter_protocol_name','Introduce el nombre del protocolo'),
('de','protocols','enter_protocol_name','Protokollnamen eingeben'),
('fr','protocols','enter_protocol_name','Saisissez le nom du protocole'),
('zh','protocols','enter_protocol_name','输入协议名称'),
('en','protocols','enter_protocol_slug','Enter protocol slug'),
('ru','protocols','enter_protocol_slug','Введите slug протокола'),
('es','protocols','enter_protocol_slug','Introduce el slug del protocolo'),
('de','protocols','enter_protocol_slug','ProtokollSlug eingeben'),
('fr','protocols','enter_protocol_slug','Saisissez le slug du protocole'),
('zh','protocols','enter_protocol_slug','输入协议 slug'),
('en','protocols','protocol_created_successfully','Protocol created successfully'),
('ru','protocols','protocol_created_successfully','Протокол успешно создан'),
('es','protocols','protocol_created_successfully','Protocolo creado correctamente'),
('de','protocols','protocol_created_successfully','Protokoll erfolgreich erstellt'),
('fr','protocols','protocol_created_successfully','Protocole créé avec succès'),
('zh','protocols','protocol_created_successfully','协议创建成功'),
('en','protocols','error_creating_protocol','Error creating protocol'),
('ru','protocols','error_creating_protocol','Ошибка создания протокола'),
('es','protocols','error_creating_protocol','Error al crear el protocolo'),
('de','protocols','error_creating_protocol','Fehler beim Erstellen des Protokolls'),
('fr','protocols','error_creating_protocol','Erreur lors de la création du protocole'),
('zh','protocols','error_creating_protocol','创建协议时出错')
ON DUPLICATE KEY UPDATE translation = VALUES(translation);
INSERT INTO translations (locale, category, key_name, translation) VALUES
('en','settings','protocols','Protocols'),
('ru','settings','protocols','Протоколы'),
('es','settings','protocols','Protocolos'),
('de','settings','protocols','Protokolle'),
('fr','settings','protocols','Protocoles'),
('zh','settings','protocols','协议'),
('en','settings','protocol_management','Protocol Management'),
('ru','settings','protocol_management','Управление протоколами'),
('es','settings','protocol_management','Gestión de protocolos'),
('de','settings','protocol_management','Protokollverwaltung'),
('fr','settings','protocol_management','Gestion des protocoles'),
('zh','settings','protocol_management','协议管理')
ON DUPLICATE KEY UPDATE translation = VALUES(translation);
INSERT INTO translations (locale, category, key_name, translation) VALUES
('en','protocols','test_install','Test install'),
('ru','protocols','test_install','Протестировать установку'),
('es','protocols','test_install','Probar instalación'),
('de','protocols','test_install','Installation testen'),
('fr','protocols','test_install','Tester linstallation'),
('zh','protocols','test_install','测试安装'),
('en','protocols','testing_on_ubuntu22','Testing on Ubuntu 22.04 in isolated Docker'),
('ru','protocols','testing_on_ubuntu22','Тест на Ubuntu 22.04 в изолированном Docker'),
('es','protocols','testing_on_ubuntu22','Prueba en Ubuntu 22.04 en Docker aislado'),
('de','protocols','testing_on_ubuntu22','Test auf Ubuntu 22.04 in isoliertem Docker'),
('fr','protocols','testing_on_ubuntu22','Test sur Ubuntu 22.04 dans Docker isolé'),
('zh','protocols','testing_on_ubuntu22','在隔离的 Docker 中于 Ubuntu 22.04 测试'),
('en','protocols','test_result','Test result'),
('ru','protocols','test_result','Результат теста'),
('es','protocols','test_result','Resultado de la prueba'),
('de','protocols','test_result','Testergebnis'),
('fr','protocols','test_result','Résultat du test'),
('zh','protocols','test_result','测试结果'),
('en','protocols','client_output_preview','Client output preview'),
('ru','protocols','client_output_preview','Предпросмотр ответа клиенту'),
('es','protocols','client_output_preview','Vista previa de salida del cliente'),
('de','protocols','client_output_preview','ClientAusgabevorschau'),
('fr','protocols','client_output_preview','Aperçu de la sortie client'),
('zh','protocols','client_output_preview','客户端输出预览'),
('en','protocols','test_failed','Test failed'),
('ru','protocols','test_failed','Ошибка теста'),
('es','protocols','test_failed','La prueba falló'),
('de','protocols','test_failed','Test fehlgeschlagen'),
('fr','protocols','test_failed','Échec du test'),
('zh','protocols','test_failed','测试失败')
ON DUPLICATE KEY UPDATE translation = VALUES(translation);
INSERT INTO protocols (name, slug, description, install_script, output_template, ubuntu_compatible, is_active, created_at, updated_at)
SELECT 'SMB Server', 'smb', 'Samba SMB file share inside Docker with random host port', '#!/bin/bash\n\nset -euo pipefail\nset -x\n\nCONTAINER_NAME="${CONTAINER_NAME:-amnezia-smb}"\nPORT_RANGE_START=${PORT_RANGE_START:-30000}\nPORT_RANGE_END=${PORT_RANGE_END:-65000}\nSMB_PORT=$((RANDOM % (PORT_RANGE_END - PORT_RANGE_START + 1) + PORT_RANGE_START))\n\n docker rm -f "$CONTAINER_NAME" >/dev/null 2>&1 || true\nmkdir -p /opt/amnezia/smb/share\n docker run -d \\\n --name "$CONTAINER_NAME" \\\n -p "${SMB_PORT}:445" \\\n -v /opt/amnezia/smb/share:/share \\\n dperson/samba -p -u "amnezia;amnezia" -s "share;/share;yes;no;no;amnezia"\n echo "Port: ${SMB_PORT}"\n echo "Password: amnezia"\n', 'smb://{{server_host}}:{{server_port}}/share\nUsername: amnezia\nPassword: {{password}}', true, true, NOW(), NOW()
WHERE NOT EXISTS (SELECT 1 FROM protocols WHERE slug='smb');
INSERT INTO protocol_variables (protocol_id, variable_name, variable_type, default_value, description, required)
SELECT id, 'server_host', 'string', '127.0.0.1', 'Server hostname or IP', true FROM protocols WHERE slug = 'smb' AND NOT EXISTS (SELECT 1 FROM protocol_variables WHERE protocol_id = (SELECT id FROM protocols WHERE slug='smb') AND variable_name='server_host');
INSERT INTO protocol_variables (protocol_id, variable_name, variable_type, default_value, description, required)
SELECT id, 'server_port', 'number', '445', 'Server port', true FROM protocols WHERE slug = 'smb' AND NOT EXISTS (SELECT 1 FROM protocol_variables WHERE protocol_id = (SELECT id FROM protocols WHERE slug='smb') AND variable_name='server_port');
INSERT INTO protocol_variables (protocol_id, variable_name, variable_type, default_value, description, required)
SELECT id, 'password', 'string', '', 'Connection password', true FROM protocols WHERE slug = 'smb' AND NOT EXISTS (SELECT 1 FROM protocol_variables WHERE protocol_id = (SELECT id FROM protocols WHERE slug='smb') AND variable_name='password');
INSERT INTO protocols (name, slug, description, install_script, output_template, ubuntu_compatible, is_active, created_at, updated_at)
SELECT 'XRay VLESS', 'xray-vless', 'XRay VLESS server inside Docker with generated client UUID', '#!/bin/bash\n\nset -euo pipefail\nset -x\n\nCONTAINER_NAME="${CONTAINER_NAME:-amnezia-xray}"\nPORT_RANGE_START=${PORT_RANGE_START:-30000}\nPORT_RANGE_END=${PORT_RANGE_END:-65000}\nXRAY_PORT=$((RANDOM % (PORT_RANGE_END - PORT_RANGE_START + 1) + PORT_RANGE_START))\nCLIENT_ID=$(cat /proc/sys/kernel/random/uuid)\n docker rm -f "$CONTAINER_NAME" >/dev/null 2>&1 || true\nmkdir -p /opt/amnezia/xray\n cat > /opt/amnezia/xray/config.json << EOF\n{\n "inbounds": [\n {\n "listen": "0.0.0.0",\n "port": 443,\n "protocol": "vless",\n "settings": {\n "clients": [\n { "id": "${CLIENT_ID}" }\n ],\n "decryption": "none"\n },\n "streamSettings": {\n "network": "tcp",\n "security": "none"\n }\n }\n ],\n "outbounds": [\n { "protocol": "freedom" }\n ]\n}\nEOF\n docker run -d \\\n --name "$CONTAINER_NAME" \\\n --restart always \\\n -p "${XRAY_PORT}:443" \\\n -v /opt/amnezia/xray:/etc/xray \\\n teddysun/xray\n echo "Port: ${XRAY_PORT}"\n echo "ClientID: ${CLIENT_ID}"\n', 'vless://{{client_id}}@{{server_host}}:{{server_port}}?security=none&type=tcp', true, true, NOW(), NOW()
WHERE NOT EXISTS (SELECT 1 FROM protocols WHERE slug='xray-vless');
INSERT INTO protocol_variables (protocol_id, variable_name, variable_type, default_value, description, required)
SELECT id, 'server_host', 'string', '127.0.0.1', 'Server hostname or IP', true FROM protocols WHERE slug = 'xray-vless' AND NOT EXISTS (SELECT 1 FROM protocol_variables WHERE protocol_id = (SELECT id FROM protocols WHERE slug='xray-vless') AND variable_name='server_host');
INSERT INTO protocol_variables (protocol_id, variable_name, variable_type, default_value, description, required)
SELECT id, 'server_port', 'number', '443', 'Server port', true FROM protocols WHERE slug = 'xray-vless' AND NOT EXISTS (SELECT 1 FROM protocol_variables WHERE protocol_id = (SELECT id FROM protocols WHERE slug='xray-vless') AND variable_name='server_port');
INSERT INTO protocol_variables (protocol_id, variable_name, variable_type, default_value, description, required)
SELECT id, 'client_id', 'string', '', 'VLESS client ID (UUID)', true FROM protocols WHERE slug = 'xray-vless' AND NOT EXISTS (SELECT 1 FROM protocol_variables WHERE protocol_id = (SELECT id FROM protocols WHERE slug='xray-vless') AND variable_name='client_id');
DELIMITER $$
CREATE PROCEDURE add_protocol_column_and_constraints()
BEGIN
IF (SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME='vpn_clients' AND COLUMN_NAME='protocol_id') = 0 THEN
ALTER TABLE vpn_clients ADD COLUMN protocol_id INT UNSIGNED NULL AFTER user_id;
END IF;
IF (SELECT COUNT(*) FROM information_schema.STATISTICS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME='vpn_clients' AND INDEX_NAME='idx_protocol_id') = 0 THEN
ALTER TABLE vpn_clients ADD INDEX idx_protocol_id (protocol_id);
END IF;
IF (SELECT COUNT(*) FROM information_schema.TABLE_CONSTRAINTS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME='vpn_clients' AND CONSTRAINT_NAME='fk_vpn_clients_protocol') = 0 THEN
ALTER TABLE vpn_clients ADD CONSTRAINT fk_vpn_clients_protocol FOREIGN KEY (protocol_id) REFERENCES protocols(id) ON DELETE SET NULL;
END IF;
END$$
DELIMITER ;
CALL add_protocol_column_and_constraints();
DROP PROCEDURE add_protocol_column_and_constraints;
DELIMITER $$
CREATE PROCEDURE ensure_users_role_column_and_index()
BEGIN
IF (SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME='users' AND COLUMN_NAME='role') = 0 THEN
ALTER TABLE users ADD COLUMN role ENUM('admin','user') DEFAULT 'user' AFTER name;
END IF;
IF (SELECT COUNT(*) FROM information_schema.STATISTICS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME='users' AND INDEX_NAME='idx_role') = 0 THEN
ALTER TABLE users ADD INDEX idx_role (role);
END IF;
END$$
DELIMITER ;
CALL ensure_users_role_column_and_index();
DROP PROCEDURE ensure_users_role_column_and_index;
DELIMITER $$
CREATE PROCEDURE add_protocols_optional_columns()
BEGIN
IF (SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME='protocols' AND COLUMN_NAME='uninstall_script') = 0 THEN
ALTER TABLE protocols ADD COLUMN uninstall_script MEDIUMTEXT NULL AFTER install_script;
END IF;
IF (SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME='protocols' AND COLUMN_NAME='password_command') = 0 THEN
ALTER TABLE protocols ADD COLUMN password_command TEXT NULL AFTER uninstall_script;
END IF;
END$$
DELIMITER ;
CALL add_protocols_optional_columns();
DROP PROCEDURE add_protocols_optional_columns;
DELIMITER $$
CREATE PROCEDURE ensure_users_display_name_column()
BEGIN
IF (SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME='users' AND COLUMN_NAME='display_name') = 0 THEN
ALTER TABLE users ADD COLUMN display_name VARCHAR(255) NULL AFTER name;
END IF;
END$$
DELIMITER ;
CALL ensure_users_display_name_column();
DROP PROCEDURE ensure_users_display_name_column;
UPDATE users SET display_name = name WHERE (display_name IS NULL OR display_name = '') AND name IS NOT NULL;
UPDATE protocols SET
install_script = '#!/bin/bash
set -euo pipefail
CONTAINER_NAME="${CONTAINER_NAME:-amnezia-awg}"
PORT_RANGE_START=${PORT_RANGE_START:-30000}
PORT_RANGE_END=${PORT_RANGE_END:-65000}
VPN_PORT=${VPN_PORT:-$((RANDOM % (PORT_RANGE_END - PORT_RANGE_START + 1) + PORT_RANGE_START))}
MTU=${MTU:-1420}
EXISTING=$(docker ps -aq -f "name=$CONTAINER_NAME" 2>/dev/null | head -1)
if [ -z "$EXISTING" ]; then
docker run -d --name "$CONTAINER_NAME" --restart always --privileged --cap-add=NET_ADMIN --cap-add=SYS_MODULE -p "${VPN_PORT}:${VPN_PORT}/udp" -v /lib/modules:/lib/modules amneziavpn/amnezia-wg:latest
sleep 2
else
STATUS=$(docker inspect --format="{{.State.Status}}" "$CONTAINER_NAME" 2>/dev/null || echo "")
if [ "$STATUS" != "running" ]; then
docker start "$CONTAINER_NAME" >/dev/null 2>&1 || true
fi
fi
docker exec -i "$CONTAINER_NAME" sh -lc "mkdir -p /opt/amnezia/awg"
HAS_CONF=$(docker exec "$CONTAINER_NAME" sh -lc "[ -f /opt/amnezia/awg/wg0.conf ] && echo yes || echo no")
if [ "$HAS_CONF" = "yes" ]; then
PORT=$(docker exec "$CONTAINER_NAME" sh -lc "grep -E \"^ListenPort\" /opt/amnezia/awg/wg0.conf | cut -d= -f2 | tr -d \"[:space:]\"")
PSK=$(docker exec "$CONTAINER_NAME" cat /opt/amnezia/awg/wireguard_psk.key 2>/dev/null || true)
if [ -z "$PSK" ]; then
PSK=$(docker exec "$CONTAINER_NAME" sh -lc "grep -E \"^PresharedKey\" /opt/amnezia/awg/wg0.conf | cut -d= -f2 | tr -d \"[:space:]\"")
fi
PUBKEY=$(docker exec "$CONTAINER_NAME" cat /opt/amnezia/awg/wireguard_server_public_key.key 2>/dev/null || true)
if [ -z "$PUBKEY" ]; then
PRIVKEY=$(docker exec "$CONTAINER_NAME" cat /opt/amnezia/awg/wireguard_server_private_key.key 2>/dev/null || true)
if [ -n "$PRIVKEY" ]; then
PUBKEY=$(echo "$PRIVKEY" | docker exec -i "$CONTAINER_NAME" wg pubkey)
fi
fi
echo "Using existing AmneziaWG configuration"
echo "Port: ${PORT:-$VPN_PORT}"
if [ -n "${PUBKEY:-}" ]; then echo "Server Public Key: $PUBKEY"; fi
if [ -n "${PSK:-}" ]; then echo "PresharedKey = $PSK"; fi
exit 0
fi
PRIVATE_KEY=$(docker exec "$CONTAINER_NAME" wg genkey)
PUBLIC_KEY=$(echo "$PRIVATE_KEY" | docker exec -i "$CONTAINER_NAME" wg pubkey)
PRESHARED_KEY=$(docker exec "$CONTAINER_NAME" wg genpsk)
cat > /opt/amnezia/awg/wg0.conf << EOF
[Interface]
PrivateKey = $PRIVATE_KEY
Address = 10.8.1.1/24
ListenPort = $VPN_PORT
MTU = $MTU
Jc = 5
Jmin = 100
Jmax = 200
S1 = 50
S2 = 100
S3 = 20
S4 = 10
H1 = 0xDEADBEEF
H2 = 0xCAFEBABE
H3 = 0x12345678
H4 = 0x9ABCDEF0
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
[Peer]
PublicKey =
PresharedKey = $PRESHARED_KEY
AllowedIPs = 10.8.1.2/32
EOF
docker exec "$CONTAINER_NAME" sh -lc "echo $PRIVATE_KEY > /opt/amnezia/awg/wireguard_server_private_key.key"
docker exec "$CONTAINER_NAME" sh -lc "echo $PUBLIC_KEY > /opt/amnezia/awg/wireguard_server_public_key.key"
docker exec "$CONTAINER_NAME" sh -lc "echo $PRESHARED_KEY > /opt/amnezia/awg/wireguard_psk.key"
docker exec "$CONTAINER_NAME" sh -lc "echo [] > /opt/amnezia/awg/clientsTable"
docker exec "$CONTAINER_NAME" wg-quick up /opt/amnezia/awg/wg0.conf || true
echo "AmneziaWG Advanced installed successfully"
echo "Port: $VPN_PORT"
echo "Server Public Key: $PUBLIC_KEY"
echo "PresharedKey = $PRESHARED_KEY'
WHERE slug = 'amnezia-wg-advanced';
UPDATE protocols SET
uninstall_script = '#!/bin/bash
set -euo pipefail
CONTAINER_NAME="${CONTAINER_NAME:-amnezia-awg}"
docker stop "$CONTAINER_NAME" 2>/dev/null || true
docker rm -fv "$CONTAINER_NAME" 2>/dev/null || true
docker image rm amneziavpn/amnezia-wg:latest 2>/dev/null || true
docker network rm amnezia-dns-net 2>/dev/null || true
rm -rf /opt/amnezia/amnezia-awg 2>/dev/null || true
rm -rf /opt/amnezia/awg 2>/dev/null || true
echo "{\"success\":true,\"message\":\"AmneziaWG uninstalled\"}"'
WHERE slug = 'amnezia-wg-advanced';
DELIMITER $$
CREATE PROCEDURE ensure_vpn_servers_install_columns()
BEGIN
IF (SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME='vpn_servers' AND COLUMN_NAME='install_protocol') = 0 THEN
ALTER TABLE vpn_servers ADD COLUMN install_protocol VARCHAR(100) NULL AFTER container_name;
END IF;
IF (SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME='vpn_servers' AND COLUMN_NAME='install_options') = 0 THEN
ALTER TABLE vpn_servers ADD COLUMN install_options JSON NULL AFTER install_protocol;
END IF;
END$$
DELIMITER ;
CALL ensure_vpn_servers_install_columns();
DROP PROCEDURE ensure_vpn_servers_install_columns;