docs: update README with desktop requirements, helper builds, and realistic MVP usage notes

Expand README with desktop platform requirements (Windows x86, macOS ARM), helper build commands, gateway utility scripts, and updated local test flow. Add realistic MVP usage section clarifying current platform build status, gateway configuration needs, and admin debug profile behavior with client private key handling.
This commit is contained in:
2026-03-16 06:30:08 +01:00
parent 7c4bba1021
commit 6ec5133773
32 changed files with 1076 additions and 49 deletions

View File

@@ -12,3 +12,10 @@ DEFAULT_DNS_SERVERS=10.20.0.53
DEFAULT_VPN_CIDR=100.96.0.0/24
DEFAULT_GATEWAY_ENDPOINT=vpn.example.com:51820
DEFAULT_GATEWAY_PUBLIC_KEY=replace-me
NEXAVPN_GATEWAY_ID=
NEXAVPN_GATEWAY_SYNC_URL=http://backend:8080/api/v1/admin/gateways
NEXAVPN_API_TOKEN=
NEXAVPN_GATEWAY_PRIVATE_KEY=
NEXAVPN_GATEWAY_INTERFACE=wg0
NEXAVPN_UPLINK_INTERFACE=eth0
NEXAVPN_ENABLE_MASQUERADE=true

View File

@@ -52,16 +52,28 @@ services:
- control
gateway:
image: alpine:3.21
command: ["sh", "/scripts/gateway-entrypoint.sh"]
build:
context: .
dockerfile: gateway/Dockerfile
cap_add:
- NET_ADMIN
- SYS_MODULE
devices:
- /dev/net/tun:/dev/net/tun
environment:
NEXAVPN_GATEWAY_ID: ${NEXAVPN_GATEWAY_ID:-}
NEXAVPN_GATEWAY_SYNC_URL: ${NEXAVPN_GATEWAY_SYNC_URL:-http://backend:8080/api/v1/admin/gateways}
NEXAVPN_API_TOKEN: ${NEXAVPN_API_TOKEN:-}
NEXAVPN_GATEWAY_PRIVATE_KEY: ${NEXAVPN_GATEWAY_PRIVATE_KEY:-}
NEXAVPN_GATEWAY_INTERFACE: ${NEXAVPN_GATEWAY_INTERFACE:-wg0}
NEXAVPN_UPLINK_INTERFACE: ${NEXAVPN_UPLINK_INTERFACE:-eth0}
NEXAVPN_ENABLE_MASQUERADE: ${NEXAVPN_ENABLE_MASQUERADE:-true}
volumes:
- ./scripts/gateway-entrypoint.sh:/scripts/gateway-entrypoint.sh:ro
- gateway-state:/var/lib/nexavpn
networks:
- gateway
- control
volumes:
postgres-data:

View File

@@ -0,0 +1,8 @@
FROM alpine:3.21
RUN apk add --no-cache bash curl jq wireguard-tools nftables
WORKDIR /app
COPY scripts/gateway-entrypoint.sh /scripts/gateway-entrypoint.sh
ENTRYPOINT ["bash", "/scripts/gateway-entrypoint.sh"]

View File

@@ -1,8 +1,104 @@
#!/bin/sh
#!/usr/bin/env bash
set -eu
echo "NexaVPN gateway helper starting"
echo "This container is a placeholder for WireGuard + nftables sync logic."
echo "Mount generated gateway state into /var/lib/nexavpn and apply rules from there."
mkdir -p /var/lib/nexavpn
tail -f /dev/null
IFACE="${NEXAVPN_GATEWAY_INTERFACE:-wg0}"
UPLINK_IFACE="${NEXAVPN_UPLINK_INTERFACE:-eth0}"
ENABLE_MASQUERADE="${NEXAVPN_ENABLE_MASQUERADE:-true}"
if [ -z "${NEXAVPN_GATEWAY_ID:-}" ] || [ -z "${NEXAVPN_API_TOKEN:-}" ] || [ -z "${NEXAVPN_GATEWAY_PRIVATE_KEY:-}" ]; then
echo "Gateway sync is not configured yet."
echo "Set NEXAVPN_GATEWAY_ID, NEXAVPN_API_TOKEN and NEXAVPN_GATEWAY_PRIVATE_KEY."
echo "Gateway apply state will be written to /var/lib/nexavpn when configured."
tail -f /dev/null
exit 0
fi
SYNC_URL="${NEXAVPN_GATEWAY_SYNC_URL}/${NEXAVPN_GATEWAY_ID}/sync"
STATE_JSON="/var/lib/nexavpn/sync-bundle.json"
WG_CONF="/etc/wireguard/${IFACE}.conf"
WG_GENERATED="/var/lib/nexavpn/${IFACE}.generated.conf"
NFT_CONF="/var/lib/nexavpn/nftables.generated.conf"
mkdir -p /etc/wireguard
apply_bundle() {
echo "Fetching bundle from ${SYNC_URL}"
curl -fsSL \
-H "Authorization: Bearer ${NEXAVPN_API_TOKEN}" \
"${SYNC_URL}" \
-o "${STATE_JSON}"
INTERFACE_ADDRESS=$(jq -r '.interface.address' "${STATE_JSON}")
NETWORK_CIDR=$(jq -r '.interface.network_cidr' "${STATE_JSON}")
LISTEN_PORT=$(jq -r '.interface.listen_port' "${STATE_JSON}")
cat > "${WG_GENERATED}" <<EOF
[Interface]
Address = ${INTERFACE_ADDRESS}
ListenPort = ${LISTEN_PORT}
PrivateKey = ${NEXAVPN_GATEWAY_PRIVATE_KEY}
EOF
jq -c '.peers[]?' "${STATE_JSON}" | while read -r peer; do
PUBLIC_KEY=$(printf '%s' "${peer}" | jq -r '.public_key')
ASSIGNED_IP=$(printf '%s' "${peer}" | jq -r '.assigned_ip')
cat >> "${WG_GENERATED}" <<EOF
[Peer]
PublicKey = ${PUBLIC_KEY}
AllowedIPs = ${ASSIGNED_IP}
EOF
done
cp "${WG_GENERATED}" "${WG_CONF}"
{
echo "flush ruleset"
echo "table inet nexavpn {"
echo " chain forward {"
echo " type filter hook forward priority 0;"
echo " policy drop;"
echo " ct state established,related accept"
echo " iifname \"${IFACE}\" ip saddr ${NETWORK_CIDR} oifname \"${UPLINK_IFACE}\" accept"
jq -c '.peers[]?' "${STATE_JSON}" | while read -r peer; do
ASSIGNED_IP=$(printf '%s' "${peer}" | jq -r '.assigned_ip')
printf '%s' "${peer}" | jq -r '.allowed_destinations[]?' | while read -r destination; do
echo " iifname \"${IFACE}\" ip saddr ${ASSIGNED_IP} ip daddr ${destination} accept"
done
done
echo " }"
if [ "${ENABLE_MASQUERADE}" = "true" ]; then
echo " chain postrouting {"
echo " type nat hook postrouting priority 100;"
echo " oifname \"${UPLINK_IFACE}\" ip saddr ${NETWORK_CIDR} masquerade"
echo " }"
fi
echo "}"
} > "${NFT_CONF}"
sysctl -w net.ipv4.ip_forward=1 >/dev/null
nft -f "${NFT_CONF}"
if ip link show "${IFACE}" >/dev/null 2>&1; then
wg syncconf "${IFACE}" <(wg-quick strip "${WG_CONF}")
ip link set "${IFACE}" up
else
wg-quick up "${WG_CONF}"
fi
echo "Applied WireGuard config from ${WG_CONF}"
echo "Applied nftables config from ${NFT_CONF}"
}
while true; do
apply_bundle || echo "Gateway apply failed; retrying in 15 seconds"
sleep 15
done

View File

@@ -0,0 +1,13 @@
#!/usr/bin/env bash
set -eu
if ! command -v wg >/dev/null 2>&1; then
echo "wg is required to generate gateway keys"
exit 1
fi
PRIVATE_KEY="$(wg genkey)"
PUBLIC_KEY="$(printf '%s' "${PRIVATE_KEY}" | wg pubkey)"
echo "NEXAVPN_GATEWAY_PRIVATE_KEY=${PRIVATE_KEY}"
echo "GATEWAY_PUBLIC_KEY=${PUBLIC_KEY}"

View File

@@ -0,0 +1,16 @@
#!/usr/bin/env bash
set -eu
if [ "$#" -lt 3 ]; then
echo "usage: get-admin-token.sh <base-url> <username> <password>"
exit 1
fi
BASE_URL="$1"
USERNAME="$2"
PASSWORD="$3"
curl -fsSL \
-H "Content-Type: application/json" \
-d "{\"username\":\"${USERNAME}\",\"password\":\"${PASSWORD}\"}" \
"${BASE_URL%/}/api/v1/auth/login"