Add wireguard-ui-multi core: multi-server DB, WireGuard manager, REST API, UI, installers
Implements the from-scratch multi-server WireGuard management fork per CLAUDE.md spec: sqlite schema (servers/peers/audit_log/users), Curve25519 key generation, per-interface config rendering + wg-quick/systemd control, nftables hook scaffolding, session+CSRF-protected REST API with QR code and config download endpoints, a minimal vanilla-JS web UI, legacy wg0.conf migration, and both a native installer and a Proxmox LXC provisioning script (with auto-detected latest Debian template). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
3d6608ef80
commit
3b3ffd8ebf
@@ -0,0 +1,78 @@
|
||||
package wireguard
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Status of a WireGuard interface.
|
||||
type Status string
|
||||
|
||||
const (
|
||||
StatusUp Status = "UP"
|
||||
StatusDown Status = "DOWN"
|
||||
)
|
||||
|
||||
// Up brings up the given interface via wg-quick.
|
||||
func Up(iface string) error {
|
||||
return run("wg-quick", "up", iface)
|
||||
}
|
||||
|
||||
// Down brings down the given interface via wg-quick.
|
||||
func Down(iface string) error {
|
||||
return run("wg-quick", "down", iface)
|
||||
}
|
||||
|
||||
// Reload applies config changes to a running interface without a full restart,
|
||||
// using `wg syncconf` against a stripped config (wg-quick strip).
|
||||
func Reload(iface, confPath string) error {
|
||||
strip := exec.Command("wg-quick", "strip", confPath)
|
||||
stripped, err := strip.Output()
|
||||
if err != nil {
|
||||
return fmt.Errorf("wg-quick strip: %w", err)
|
||||
}
|
||||
sync := exec.Command("wg", "syncconf", iface, "/dev/stdin")
|
||||
sync.Stdin = strings.NewReader(string(stripped))
|
||||
if out, err := sync.CombinedOutput(); err != nil {
|
||||
return fmt.Errorf("wg syncconf: %w: %s", err, out)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsUp checks whether the interface currently exists / is up.
|
||||
func IsUp(iface string) bool {
|
||||
cmd := exec.Command("wg", "show", iface)
|
||||
return cmd.Run() == nil
|
||||
}
|
||||
|
||||
func GetStatus(iface string) Status {
|
||||
if IsUp(iface) {
|
||||
return StatusUp
|
||||
}
|
||||
return StatusDown
|
||||
}
|
||||
|
||||
// EnableService enables and starts the systemd wg-quick@<iface>.service unit.
|
||||
func EnableService(iface string) error {
|
||||
if err := run("systemctl", "enable", "wg-quick@"+iface); err != nil {
|
||||
return err
|
||||
}
|
||||
return run("systemctl", "start", "wg-quick@"+iface)
|
||||
}
|
||||
|
||||
// DisableService stops and disables the systemd wg-quick@<iface>.service unit.
|
||||
func DisableService(iface string) error {
|
||||
if err := run("systemctl", "stop", "wg-quick@"+iface); err != nil {
|
||||
return err
|
||||
}
|
||||
return run("systemctl", "disable", "wg-quick@"+iface)
|
||||
}
|
||||
|
||||
func run(name string, args ...string) error {
|
||||
cmd := exec.Command(name, args...)
|
||||
if out, err := cmd.CombinedOutput(); err != nil {
|
||||
return fmt.Errorf("%s %s: %w: %s", name, strings.Join(args, " "), err, out)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user