refactor(traffic): update traffic flow host file generation and configuration scripts
Docker images / prepare-release (push) Successful in 6s
Docker images / backend-image (push) Successful in 1m39s
Docker images / frontend-image (push) Successful in 3m2s
Docker images / notify-webhook (push) Skipped
Docker images / updater-image (push) Successful in 43s
Docker images / publish-release (push) Successful in 9s

- Renamed and refactored functions for better clarity, including `buildHostComposeSnippet` to `buildHostComposeOverride` and `buildHostNftSnippet` to `buildHostLinuxInstallSh`.
- Introduced a new script for Linux installation of WireGuard, enhancing the setup process for Docker hosts.
- Updated the `generateNativeConf` function to conditionally include the listen port in the configuration.
- Adjusted the `FlowOverlaySheet` component to default to the new Linux tab and improved the user interface for selecting jump-hosts.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Denozordec
2026-09-06 23:20:12 +07:00
co-authored by Cursor
parent f0dc5acfd3
commit 13889005f8
6 changed files with 149 additions and 90 deletions
+81 -35
View File
@@ -2,12 +2,13 @@ import { generateNativeConf } from "./wireguard-config.js"
import { getTrafficFlowSettingsRow, listHostPeers } from "./traffic-flow-settings.js"
import type { TrafficFlowHostFile } from "@mmapp/contracts/traffic-flow"
const COMPOSE_DIR = "/opt/cdn-mm"
export function buildHostWgQuickConf(): string {
const row = getTrafficFlowSettingsRow()
const peers = listHostPeers()
return generateNativeConf({
name: "wg-flow",
listenPort: row.wgListenPort,
mtu: 1420,
privateKey: row.hostPrivateKey || undefined,
address: `${row.collectorIp}/24`,
@@ -22,47 +23,92 @@ export function buildHostWgQuickConf(): string {
})
}
export function buildHostComposeSnippet(): string {
const row = getTrafficFlowSettingsRow()
return `# Вставить в /opt/cdn-mm/docker-compose.yml под services.backend
# На хосте сначала: wg-quick up wg-flow (адрес ${row.collectorIp})
# затем: docker compose up -d backend
# Traefik не трогать. UDP ${row.flowListenPort} не публиковать на 0.0.0.0.
environment:
FLOW_LISTEN_HOST: "0.0.0.0"
ports:
- "${row.collectorIp}:${row.flowListenPort}:${row.flowListenPort}/udp"
`
}
export function buildHostNftSnippet(): string {
const row = getTrafficFlowSettingsRow()
return `# Firewall хоста Docker MM. WG — клиент к JH:13232 (исходящий).
# UDP ${row.flowListenPort} наружу НЕ открывать.
table inet filter {
chain input {
type filter hook input priority 0;
iifname "wg-flow" udp dport ${row.flowListenPort} accept
udp dport ${row.flowListenPort} drop
}
}
`
}
export function buildHostUfwSnippet(): string {
export function buildHostComposeOverride(): string {
const row = getTrafficFlowSettingsRow()
return [
`# WG клиент: входящий listen не нужен`,
`ufw deny ${row.flowListenPort}/udp comment 'ipfix-not-public'`,
"# Docker Compose merge для /opt/cdn-mm",
"# Не править docker-compose.yml. Traefik не трогать.",
"# Сначала: wg-quick up wg-flow (адрес " + row.collectorIp + ")",
"# затем: docker compose up -d backend",
"",
"services:",
" backend:",
" environment:",
" FLOW_LISTEN_HOST: \"0.0.0.0\"",
" ports:",
` - "${row.collectorIp}:${row.flowListenPort}:${row.flowListenPort}/udp"`,
"",
].join("\n")
}
export function buildHostLinuxInstallSh(): string {
const row = getTrafficFlowSettingsRow()
const conf = buildHostWgQuickConf().replace(/\s+$/, "") + "\n"
const override = buildHostComposeOverride()
const collector = row.collectorIp
const flowPort = row.flowListenPort
return `#!/usr/bin/env bash
# WG-клиент на хосте /opt/cdn-mm → JH:13232, IPFIX в контейнер backend.
# Запуск: sudo bash install-wg-flow.sh
set -euo pipefail
if [[ \${EUID:-$(id -u)} -ne 0 ]]; then
echo "Запустите от root: sudo bash $0" >&2
exit 1
fi
COLLECTOR_IP="${collector}"
FLOW_PORT="${flowPort}"
COMPOSE_DIR="${COMPOSE_DIR}"
if ! command -v wg >/dev/null 2>&1; then
apt-get update
DEBIAN_FRONTEND=noninteractive apt-get install -y wireguard
fi
install -d -m 700 /etc/wireguard
cat > /etc/wireguard/wg-flow.conf <<'WGEOF'
${conf}WGEOF
chmod 600 /etc/wireguard/wg-flow.conf
systemctl enable --now wg-quick@wg-flow
echo "=== wg show wg-flow ==="
wg show wg-flow
echo "=== адрес (ожидаем \${COLLECTOR_IP}/24) ==="
ip -4 addr show dev wg-flow
if [[ ! -d "\$COMPOSE_DIR" ]]; then
echo "Нет \$COMPOSE_DIR — положите override.yml туда вручную (вкладка compose)." >&2
exit 1
fi
cat > "\$COMPOSE_DIR/docker-compose.override.yml" <<'OVEOF'
${override}OVEOF
cd "\$COMPOSE_DIR"
docker compose up -d backend
echo "=== UDP \${FLOW_PORT} на хосте ==="
ss -ulnp | grep -E "\${FLOW_PORT}" || true
echo "=== PortBindings mmapp-backend ==="
docker inspect -f '{{json .HostConfig.PortBindings}}' mmapp-backend
echo "=== handshake (keepalive 25s к JH:13232) ==="
wg show wg-flow
# ufw: исходящий WG не открывать; 4739 на WAN не публиковать
if command -v ufw >/dev/null 2>&1; then
ufw deny "\${FLOW_PORT}/udp" comment 'ipfix-not-public' || true
fi
echo "Готово. Traefik не трогали. UDP \${FLOW_PORT} только на \${COLLECTOR_IP}, не на 0.0.0.0."
`
}
export function listTrafficFlowHostFiles(): TrafficFlowHostFile[] {
return [
{ id: "linux", label: "Linux", filename: "install-wg-flow.sh", code: buildHostLinuxInstallSh() },
{ id: "wg-quick", label: "wg-flow.conf", filename: "wg-flow.conf", code: buildHostWgQuickConf() },
{ id: "compose", label: "docker-compose", filename: "docker-compose.flow.yml", code: buildHostComposeSnippet() },
{ id: "nft", label: "nftables", filename: "wg-flow.nft", code: buildHostNftSnippet() },
{ id: "ufw", label: "ufw", filename: "wg-flow.ufw.sh", code: buildHostUfwSnippet() },
{ id: "compose", label: "compose", filename: "docker-compose.override.yml", code: buildHostComposeOverride() },
]
}
+3 -3
View File
@@ -35,7 +35,7 @@ export type WgParsedConfig = {
export type WgExportIface = {
name: string
listenPort: number
listenPort?: number
mtu: number
comment?: string
enabled?: boolean
@@ -258,7 +258,7 @@ export function generateNativeConf(iface: WgExportIface, opts?: { includePrivate
lines.push(`# PrivateKey = <заполните приватный ключ с роутера>`)
}
if (iface.address) lines.push(`Address = ${iface.address}`)
lines.push(`ListenPort = ${iface.listenPort}`)
if (iface.listenPort) lines.push(`ListenPort = ${iface.listenPort}`)
if (iface.mtu) lines.push(`MTU = ${iface.mtu}`)
lines.push(``)
@@ -312,7 +312,7 @@ export function generateMikrotikRsc(iface: WgExportIface): string {
lines.push(``)
lines.push(`/interface wireguard add \\`)
lines.push(` name=${iface.name} \\`)
lines.push(` listen-port=${iface.listenPort} \\`)
lines.push(` listen-port=${iface.listenPort ?? 13231} \\`)
lines.push(` mtu=${iface.mtu} \\`)
if (iface.privateKey) lines.push(` private-key="${iface.privateKey}" \\`)
if (iface.comment) lines.push(` comment="${iface.comment.replace(/"/g, '\\"')}" \\`)