The direct tunnel port (8446 by default) and the host agents dial for it can be set in Settings. The server moves its listeners at once and agents pick the address up from the panel: on connect and with every poll, unless TUNNEL_ADDR / TUNNEL_PORT pin it locally. ufw: run with a C locale (the output is translated), do not adopt rules that existed before the panel, skip loopback-only listeners, re-open what saved forwards need on start and when the integration is turned on, move the shared tunnel rule with the port and drop it when no direct forward is left. The last ufw error is shown in Settings. The forwards page shows the real tunnel and panel ports.
166 lines
8.7 KiB
HTML
166 lines
8.7 KiB
HTML
<!doctype html>
|
|
<html lang="ru">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>Настройки — LPRA</title>
|
|
<link rel="stylesheet" href="/static/app.css">
|
|
</head>
|
|
<body>
|
|
<header class="topbar">
|
|
<div class="brand">LPRA · Удалённый доступ</div>
|
|
<nav>
|
|
<a href="/">Машины</a>
|
|
<a href="/settings">Настройки</a>
|
|
<form method="post" action="/logout" style="display:inline; margin-left:22px">
|
|
<button class="btn ghost small" type="submit">Выйти</button>
|
|
</form>
|
|
</nav>
|
|
</header>
|
|
<div class="wrap">
|
|
<h1>Настройки</h1>
|
|
{{if .Error}}<div class="err">{{.Error}}</div>{{end}}
|
|
|
|
<div class="card">
|
|
<h2>Установка на новую машину</h2>
|
|
<p class="muted">Выполните на Linux-клиенте под root. Скрипт сам скачает бинарник,
|
|
поставит сервис и зарегистрирует машину.</p>
|
|
|
|
<label>Короткая команда (секрет уже вшит в ссылку)</label>
|
|
<pre id="short">{{.InstallShort}}</pre>
|
|
|
|
<details style="margin-top:10px">
|
|
<summary class="muted" style="cursor:pointer">Полные варианты (секрет в команде)</summary>
|
|
<label>curl</label>
|
|
<pre id="curl">{{.InstallCurl}}</pre>
|
|
<label>wget</label>
|
|
<pre id="wget">{{.InstallWget}}</pre>
|
|
<p class="muted">Без переменных окружения скрипт спросит секрет интерактивно:
|
|
<code>curl -fsSL {{.Host}}/install.sh | sudo sh</code></p>
|
|
</details>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<h2>Адрес хоста</h2>
|
|
<p class="muted">URL, на который звонят агенты. Подставляется в скрипт установки.</p>
|
|
<form method="post" action="/settings/host" class="row">
|
|
<input type="hidden" name="csrf" value="{{.CSRF}}">
|
|
<input type="text" name="host" value="{{.Host}}" style="max-width:420px">
|
|
<button type="submit">Сохранить</button>
|
|
</form>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<h2>Прямой туннель (tcp/udp проброс)</h2>
|
|
{{if not .TunnelDefault}}
|
|
<p class="muted">Прямой туннель отключён при запуске сервера (пустой <code>-tunnel</code> / <code>LPRA_TUNNEL_ADDR</code>).</p>
|
|
{{else}}
|
|
<p class="muted">Адрес, к которому агенты подключаются для проброса в режимах tcp/udp. Агенты забирают его
|
|
с панели сами — при подключении и при каждом опросе, так что смена применяется без переустановки.
|
|
Хост можно оставить пустым (тогда берётся хост из адреса панели) или указать IP/другое имя.</p>
|
|
<form method="post" action="/settings/tunnel" class="row">
|
|
<input type="hidden" name="csrf" value="{{.CSRF}}">
|
|
<input type="text" name="tunnel_host" value="{{.TunnelHost}}" placeholder="хост (как у панели)" style="max-width:260px">
|
|
<input type="number" name="tunnel_port" min="1" max="65535" value="{{if .TunnelCustom}}{{.TunnelPort}}{{end}}" placeholder="{{.TunnelDefault}}" style="max-width:120px">
|
|
<button type="submit">Сохранить</button>
|
|
</form>
|
|
<p class="muted" style="font-size:13px">Сейчас сервер слушает порт <b>{{.TunnelPort}}</b> (tcp и udp). При смене порта сервер
|
|
сразу начинает слушать новый, агенты переподключаются в течение ~30 секунд, правило ufw переносится.
|
|
Агенты старше 0.0.3 и агенты с заданными <code>TUNNEL_ADDR</code>/<code>TUNNEL_PORT</code> адрес с панели не берут.</p>
|
|
{{end}}
|
|
</div>
|
|
|
|
<div class="card">
|
|
<h2>Enroll-секрет</h2>
|
|
<p class="muted">Общий секрет для регистрации новых агентов.</p>
|
|
<div class="row">
|
|
<code>{{.Secret}}</code>
|
|
<form method="post" action="/settings/secret/rotate" style="display:inline"
|
|
onsubmit="return confirm('Сменить секрет? Старые one-liner перестанут работать для новых установок.')">
|
|
<input type="hidden" name="csrf" value="{{.CSRF}}">
|
|
<button class="btn ghost small" type="submit">Сменить</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<h2>Администраторы</h2>
|
|
<table>
|
|
<tbody>
|
|
{{range .Admins}}
|
|
<tr>
|
|
<td>{{.Username}}</td>
|
|
<td style="text-align:right">
|
|
<form method="post" action="/settings/admins/delete" style="display:inline"
|
|
onsubmit="return confirm('Удалить администратора {{.Username}}?')">
|
|
<input type="hidden" name="csrf" value="{{$.CSRF}}">
|
|
<input type="hidden" name="id" value="{{.ID}}">
|
|
<button class="btn danger small" type="submit">Удалить</button>
|
|
</form>
|
|
</td>
|
|
</tr>
|
|
{{end}}
|
|
</tbody>
|
|
</table>
|
|
<form method="post" action="/settings/admins/add" style="margin-top:14px">
|
|
<input type="hidden" name="csrf" value="{{.CSRF}}">
|
|
<div class="row">
|
|
<input type="text" name="username" placeholder="логин" style="max-width:200px" required>
|
|
<input type="password" name="password" placeholder="пароль (мин. 8)" style="max-width:200px" required>
|
|
<button type="submit">Добавить</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<h2>Firewall (ufw)</h2>
|
|
{{if not .UfwInstalled}}
|
|
<p class="muted">ufw не установлен на хосте — интеграция недоступна.</p>
|
|
{{else if not .UfwRunnable}}
|
|
<p class="muted">ufw установлен, но сервер не может им управлять (нужны права root).
|
|
Запустите сервер под root или настройте sudo для ufw.</p>
|
|
{{else}}
|
|
<p class="muted">
|
|
Статус ufw: {{if .UfwActive}}<span style="color:var(--ok)">активен</span>{{else}}<span style="color:var(--danger)">выключен</span>{{end}}
|
|
· Интеграция: {{if .UfwEnabled}}<span style="color:var(--ok)">включена</span>{{else}}<span class="muted">выключена</span>{{end}}
|
|
</p>
|
|
<p class="muted" style="font-size:13px">При создании правила проброса порт открывается в ufw автоматически (для tcp/udp — также порт туннеля{{if .TunnelPort}} {{.TunnelPort}}{{end}}); для http-проброса открывается tcp-порт хоста. Порты правил, слушающих только 127.0.0.1, не открываются.</p>
|
|
{{if .UfwError}}<div class="err">Последняя команда ufw завершилась ошибкой: <code>{{.UfwError}}</code></div>{{end}}
|
|
<form method="post" action="/settings/ufw/toggle" style="display:inline">
|
|
<input type="hidden" name="csrf" value="{{.CSRF}}">
|
|
<input type="hidden" name="enabled" value="{{if .UfwEnabled}}0{{else}}1{{end}}">
|
|
<button class="btn {{if .UfwEnabled}}ghost{{end}} small" type="submit">
|
|
{{if .UfwEnabled}}Выключить интеграцию{{else}}Включить интеграцию{{end}}
|
|
</button>
|
|
</form>
|
|
|
|
{{if .UfwRules}}
|
|
<h2 style="margin-top:18px; font-size:15px">Правила, созданные панелью</h2>
|
|
<table>
|
|
<tbody>
|
|
{{range .UfwRules}}
|
|
<tr>
|
|
<td><code>{{.Port}}/{{.Proto}}</code></td>
|
|
<td style="text-align:right">
|
|
<form method="post" action="/settings/ufw/revoke" style="display:inline"
|
|
onsubmit="return confirm('Отменить правило ufw {{.Port}}/{{.Proto}}?')">
|
|
<input type="hidden" name="csrf" value="{{$.CSRF}}">
|
|
<input type="hidden" name="id" value="{{.ID}}">
|
|
<button class="btn danger small" type="submit">Отменить</button>
|
|
</form>
|
|
</td>
|
|
</tr>
|
|
{{end}}
|
|
</tbody>
|
|
</table>
|
|
{{else}}
|
|
<p class="muted" style="font-size:13px; margin-top:10px">Панель пока не открывала портов в ufw.</p>
|
|
{{end}}
|
|
{{end}}
|
|
</div>
|
|
|
|
<p class="muted" style="font-size:12px; text-align:center">LPRA сервер · версия {{.ServerVersion}}</p>
|
|
</div>
|
|
</body>
|
|
</html>
|