Make AmneziaWG 3.1 the default generation

install.sh now defaults to AWG_GEN=3.1: an incompatible module or kernel
fails with diagnostics instead of silently falling back to 2.0 and handing
out a server with weaker obfuscation. AWG_GEN=auto keeps the old fallback
for old kernels, AWG_GEN=2.0 still forces 2.0.

Servers already installed on 2.0 no longer need a reinstall: POST
/awg/upgrade (button in the users tab) backs up awg1.conf, rewrites
[Interface] with HeaderProtectionKey and the 3.1 block install.sh writes,
raises any S1-S4 below 12 (header protection needs a 12-byte nonce and the
module only reports "Invalid argument"), restarts the interface and
reissues every vpn:// key. Bringing the interface up is the only real proof
the kernel accepted the params, so a failure restores the previous conf and
brings 2.0 back up. Reissue is not optional: 2.0-era keys stop working the
moment the generation changes.

restartAwg() now re-reads the obfuscation params, generation and keepalive
from awg1.conf before syncing peers. The conf can change while the
interface is down, and a stale CONFIG.gen meant new keys were built on the
old params.

README: install from git.ma7neko.ru (Gitea) instead of raw.githubusercontent,
and document the 3.1 default with the AWG_GEN=auto escape hatch.
This commit is contained in:
2026-08-29 03:08:07 +03:00
parent 0dbb13f120
commit 38e76da84f
4 changed files with 227 additions and 19 deletions
+28
View File
@@ -19,6 +19,7 @@ export default function UsersPage({ token, showMsg }: PageProps) {
// Поколение, на котором сейчас работает интерфейс. Ключи, выданные на другом
// поколении, уже не подключатся — их надо перевыпустить.
const [serverGen, setServerGen] = useState<AwgGen>('2');
const [upgrading, setUpgrading] = useState(false);
const statsRef = useRef<ReturnType<typeof setInterval> | null>(null);
const stale = users.filter(u => u.key_gen !== serverGen);
@@ -62,6 +63,28 @@ export default function UsersPage({ token, showMsg }: PageProps) {
}
}, [stale.length, serverGen, token, loadUsers, showMsg]);
// Перевод сервера с 2.0 на 3.1 без переустановки: awg-ctrl дописывает
// 3.x-параметры в awg1.conf, перезапускает интерфейс (с откатом, если ядро
// их не примет) и сразу перевыпускает ключи — старые собраны на
// 2.0-параметрах и работать не будут.
const upgradeGen = useCallback(async () => {
if (!confirm(
'Перевести сервер на AmneziaWG 3.1?\n\n' +
'Интерфейс будет перезапущен, а все vpn:// ключи перевыпущены — ' +
'клиентам придётся импортировать ключ заново.',
)) return;
setUpgrading(true);
try {
const r = await apiFetch('POST', '/awg/upgrade', token);
showMsg(`Сервер переведён на ${genLabel(r.gen)}, перевыпущено ключей: ${r.reissue?.reissued ?? 0}`);
await loadUsers(token);
} catch (e: any) {
showMsg(e?.response?.data?.error ?? 'Не удалось перейти на 3.1');
} finally {
setUpgrading(false);
}
}, [token, loadUsers, showMsg]);
const createUser = useCallback(async () => {
if (!newName) return;
const u = await apiFetch('POST', '/api/users', token, { name: newName });
@@ -120,6 +143,11 @@ export default function UsersPage({ token, showMsg }: PageProps) {
<button className="btn btn--tonal" onClick={() => loadUsers(token)}>
<IcoRefresh /> Обновить
</button>
{serverGen !== '3.1' && (
<button className="btn btn--danger" onClick={upgradeGen} disabled={upgrading}>
<IcoRefresh /> {upgrading ? 'Переход…' : 'Перейти на AWG 3.1'}
</button>
)}
{stale.length > 0 && (
<button className="btn btn--danger" onClick={reissueKeys}>
<IcoRefresh /> Перевыпустить ключи ({stale.length})