feat: enhance SQL migration handling and add Docker installation instructions for remote servers

This commit is contained in:
infosave2007
2026-04-04 15:48:15 +03:00
parent 1ff23b8ed9
commit bc1d9d531b
3 changed files with 73 additions and 6 deletions
+24 -2
View File
@@ -37,18 +37,40 @@ docker compose up -d
docker compose exec web composer install docker compose exec web composer install
# Ensure all SQL migrations are applied (safe to run repeatedly) # Ensure all SQL migrations are applied (safe to run repeatedly)
docker compose exec -T db sh -lc 'for f in /docker-entrypoint-initdb.d/*.sql; do mysql -uroot -p"$MYSQL_ROOT_PASSWORD" "$MYSQL_DATABASE" < "$f" || true; done' for f in migrations/*.sql; do
docker compose exec -T db mysql -uroot -p"$MYSQL_ROOT_PASSWORD" "$MYSQL_DATABASE" < "$f" || true
done
# Or for older Docker Compose V1 # Or for older Docker Compose V1
docker-compose up -d docker-compose up -d
docker-compose exec web composer install docker-compose exec web composer install
docker-compose exec -T db sh -lc 'for f in /docker-entrypoint-initdb.d/*.sql; do mysql -uroot -p"$MYSQL_ROOT_PASSWORD" "$MYSQL_DATABASE" < "$f" || true; done' for f in migrations/*.sql; do
docker-compose exec -T db mysql -uroot -p"$MYSQL_ROOT_PASSWORD" "$MYSQL_DATABASE" < "$f" || true
done
``` ```
Access: http://localhost:8082 Access: http://localhost:8082
Default login: admin@amnez.ia / admin123 Default login: admin@amnez.ia / admin123
### Remote Server Prerequisite
For protocol deployment on a clean remote host, Docker Engine must be available on that host.
If Docker is missing, install it first (Ubuntu example):
```bash
apt-get update -y
apt-get install -y ca-certificates curl gnupg lsb-release
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --batch --yes --dearmor -o /etc/apt/keyrings/docker.gpg
chmod a+r /etc/apt/keyrings/docker.gpg
. /etc/os-release
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu ${VERSION_CODENAME} stable" > /etc/apt/sources.list.d/docker.list
apt-get update -y
apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
systemctl enable --now docker
```
## Configuration ## Configuration
Edit `.env`: Edit `.env`:
+32 -3
View File
@@ -1149,7 +1149,7 @@ class InstallProtocolManager
if ($isAwg) { if ($isAwg) {
$detection = self::detectBuiltinAwg($server, $protocol); $detection = self::detectBuiltinAwg($server, $protocol);
if (in_array($detection['status'] ?? '', ['existing', 'partial'], true)) { if (($detection['status'] ?? '') === 'existing') {
Logger::appendInstall($serverId, 'Existing AWG installation detected, restoring instead of reinstalling'); Logger::appendInstall($serverId, 'Existing AWG installation detected, restoring instead of reinstalling');
$restoreResult = self::restoreBuiltinAwg($server, $protocol, $detection, $options); $restoreResult = self::restoreBuiltinAwg($server, $protocol, $detection, $options);
// Import existing clients into DB // Import existing clients into DB
@@ -1177,7 +1177,7 @@ class InstallProtocolManager
if ($isXray) { if ($isXray) {
$xrayDetection = self::detectBuiltinXray($server, $protocol); $xrayDetection = self::detectBuiltinXray($server, $protocol);
if (in_array($xrayDetection['status'] ?? '', ['existing', 'partial'], true)) { if (($xrayDetection['status'] ?? '') === 'existing') {
Logger::appendInstall($serverId, 'Existing X-Ray installation detected, restoring instead of reinstalling'); Logger::appendInstall($serverId, 'Existing X-Ray installation detected, restoring instead of reinstalling');
$restoreResult = self::restoreBuiltinXray($server, $protocol, $xrayDetection, $options); $restoreResult = self::restoreBuiltinXray($server, $protocol, $xrayDetection, $options);
return array_merge($restoreResult, ['mode' => 'restore_existing']); return array_merge($restoreResult, ['mode' => 'restore_existing']);
@@ -1189,12 +1189,41 @@ class InstallProtocolManager
if ($engine === 'builtin_awg') { if ($engine === 'builtin_awg') {
$res = $server->runAwgInstall($options); $res = $server->runAwgInstall($options);
Logger::appendInstall($serverId, 'Builtin AWG install finished'); Logger::appendInstall($serverId, 'Builtin AWG install finished');
$resolvedPort = null;
if (isset($res['vpn_port']) && (int) $res['vpn_port'] > 0) {
$resolvedPort = (int) $res['vpn_port'];
} elseif (isset($res['server_port']) && (int) $res['server_port'] > 0) {
$resolvedPort = (int) $res['server_port'];
}
$resolvedAwgParams = $res['awg_params'] ?? null;
if (!is_array($resolvedAwgParams)) {
$candidate = [];
foreach (['Jc', 'Jmin', 'Jmax', 'S1', 'S2', 'H1', 'H2', 'H3', 'H4'] as $k) {
if (array_key_exists($k, $res)) {
$candidate[$k] = $res[$k];
}
}
if ($candidate) {
$resolvedAwgParams = $candidate;
}
}
self::markServerActive($serverId, null, [
'vpn_port' => $resolvedPort,
'server_public_key' => $res['server_public_key'] ?? null,
'preshared_key' => $res['preshared_key'] ?? null,
'container_name' => $res['container_name'] ?? null,
'awg_params' => $resolvedAwgParams,
]);
$pdo = DB::conn(); $pdo = DB::conn();
$pid = self::resolveProtocolId($protocol); $pid = self::resolveProtocolId($protocol);
if ($pid) { if ($pid) {
$config = [ $config = [
'server_host' => $server->getData()['host'] ?? null, 'server_host' => $server->getData()['host'] ?? null,
'server_port' => $res['vpn_port'] ?? null, 'server_port' => $resolvedPort,
'extras' => $res 'extras' => $res
]; ];
$stmt2 = $pdo->prepare('INSERT INTO server_protocols (server_id, protocol_id, config_data, applied_at, created_at) VALUES (?, ?, ?, NOW(), NOW()) ON DUPLICATE KEY UPDATE config_data = VALUES(config_data), applied_at = NOW()'); $stmt2 = $pdo->prepare('INSERT INTO server_protocols (server_id, protocol_id, config_data, applied_at, created_at) VALUES (?, ?, ?, NOW(), NOW()) ON DUPLICATE KEY UPDATE config_data = VALUES(config_data), applied_at = NOW()');
+17 -1
View File
@@ -1459,10 +1459,19 @@ class VpnClient
$awgParams = []; $awgParams = [];
} }
// Accept mixed-case keys from installer outputs (e.g. Jc/Jmin/Jmax)
// by duplicating them into canonical uppercase AWG keys.
foreach ($awgParams as $k => $v) {
$uk = strtoupper((string) $k);
if (in_array($uk, ['JC', 'JMIN', 'JMAX', 'S1', 'S2', 'S3', 'S4', 'H1', 'H2', 'H3', 'H4'], true) && !isset($awgParams[$uk])) {
$awgParams[$uk] = $v;
}
}
// If AWG params are missing (common after reinstall), fetch them directly from wg0.conf // If AWG params are missing (common after reinstall), fetch them directly from wg0.conf
// to avoid falling back to template defaults that will not match the server. // to avoid falling back to template defaults that will not match the server.
if (in_array($slug, ['amnezia-wg-advanced', 'awg2'], true)) { if (in_array($slug, ['amnezia-wg-advanced', 'awg2'], true)) {
$needKeys = ['JC', 'JMIN', 'JMAX', 'S1', 'S2', 'S3', 'S4', 'H1', 'H2', 'H3', 'H4']; $needKeys = ['JC', 'JMIN', 'JMAX', 'S1', 'S2', 'H1', 'H2', 'H3', 'H4'];
$missing = false; $missing = false;
foreach ($needKeys as $k) { foreach ($needKeys as $k) {
if (!isset($awgParams[$k])) { if (!isset($awgParams[$k])) {
@@ -1494,6 +1503,13 @@ class VpnClient
} }
} }
if (!isset($awgParams['S3'])) {
$awgParams['S3'] = 0;
}
if (!isset($awgParams['S4'])) {
$awgParams['S4'] = 0;
}
// Still missing? Refuse to overwrite config with template defaults. // Still missing? Refuse to overwrite config with template defaults.
foreach ($needKeys as $k) { foreach ($needKeys as $k) {
if (!isset($awgParams[$k])) { if (!isset($awgParams[$k])) {