Manage several servers from one panel: core + nodes
A node is a VPN server without a panel. awg-agent on it dials the panel (core) over an outbound WSS connection and runs the panel's requests on its own awg-ctrl, which stays on 127.0.0.1 and is unchanged. No inbound port on the node, works behind NAT. - awg-ui/nodes.ts: node registry in ui.db, WSS hub on NODE_PORT with a self-signed cert whose SPKI pin goes into the join string, RPC with timeouts, health polling, /ui/nodes routes. - Nodes enroll with a one-time awgjoin:// string (secret stored hashed, 1 hour) and then authenticate by their own Ed25519 key. The agent checks the pin before sending anything and only forwards /health, /api/*, /awg/*. - server_id 0 is the panel's own awg-ctrl; LOCAL_NODE=off makes the panel run without a VPN of its own. The panel picks a server with X-Server-Id, API keys use their server_id. sen:// still serves one server. - UI: a card per server in the server bar, switching remounts the tab, «Добавить сервер» gives the join command. - CLI: agent service, roles from cli.env, join / unjoin commands. - Release archives include awg-agent.
This commit is contained in:
@@ -47,10 +47,32 @@ export interface PageProps {
|
||||
export const BRAND_FALLBACK = 'Forgetting';
|
||||
export interface Brand { brand: string; channel: string; version: string }
|
||||
|
||||
export const TOKEN_KEY = 'awg_token';
|
||||
export const THEME_KEY = 'awg_theme';
|
||||
export const TOKEN_KEY = 'awg_token';
|
||||
export const THEME_KEY = 'awg_theme';
|
||||
export const SERVER_KEY = 'awg_server';
|
||||
|
||||
// Сервер (core или нода) в списке ServerBar: то, что отдаёт GET /ui/nodes.
|
||||
export interface NodeInfo {
|
||||
id: number;
|
||||
name: string;
|
||||
local: boolean; // id 0 — локальный awg-ctrl этой же машины
|
||||
online: boolean;
|
||||
pending: boolean; // нода создана, но ещё ни разу не подключалась
|
||||
last_seen: number | null;
|
||||
health: { server: string; ip: string; gen: AwgGen; peers: number; awg_up: boolean; module: string; tools: string } | null;
|
||||
}
|
||||
|
||||
// Выбранный сервер. Вкладки зовут apiFetch без явного id — заголовок X-Server-Id
|
||||
// подставляется здесь; App ставит значение до смены key у вкладки, поэтому та
|
||||
// перечитывает данные уже с новым сервером.
|
||||
let currentServerId: number | null = null;
|
||||
export const setServerId = (id: number | null) => { currentServerId = id; };
|
||||
export const getServerId = () => currentServerId;
|
||||
|
||||
export async function apiFetch(method: string, path: string, token: string, body?: object): Promise<any> {
|
||||
const r = await axios({ method, url: path, headers: { Authorization: `Bearer ${token}` }, data: body });
|
||||
const headers: Record<string, string> = { Authorization: `Bearer ${token}` };
|
||||
if (currentServerId !== null) headers['X-Server-Id'] = String(currentServerId);
|
||||
const r = await axios({ method, url: path, headers, data: body });
|
||||
return r.data;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user