Replace wg-quick route management with idempotent PostUp routes

wg-quick's own AllowedIPs route handling does a plain `ip route add`
per entry into the main table and hard-fails the whole interface
bring-up with "RTNETLINK: File exists" the moment two servers share
an overlapping AllowedIPs entry (real case: a client's transit IP
duplicated across 4 imported servers). Set Table = off and generate
`ip route replace` PostUp commands instead - idempotent, never fails
on a pre-existing route, and multiple servers can coexist even when
their peers' AllowedIPs overlap.

Also make ServerServiceRestart write the config to disk first, same
as ServerServiceStart already does - it had the same "config file
missing" failure mode.
This commit is contained in:
sysops
2026-07-25 19:53:26 +02:00
parent d585d53fa7
commit cf9c136874
3 changed files with 19 additions and 4 deletions
+8 -1
View File
@@ -1203,7 +1203,7 @@ func ServerServiceStop(db store.IStore) echo.HandlerFunc {
// ServerServiceRestart restarts a server's WireGuard interface via
// `systemctl restart wg-quick@<iface>.service`. Admin-only.
func ServerServiceRestart(db store.IStore) echo.HandlerFunc {
func ServerServiceRestart(db store.IStore, tmplDir fs.FS) echo.HandlerFunc {
return func(c echo.Context) error {
serverID := c.Param("id")
server, err := db.GetServerByID(serverID)
@@ -1211,6 +1211,13 @@ func ServerServiceRestart(db store.IStore) echo.HandlerFunc {
return c.JSON(http.StatusNotFound, jsonHTTPResponse{false, "Server not found"})
}
if err := writeServerConfigToDisk(db, tmplDir, serverID); err != nil {
log.Errorf("Failed to write config before restarting server %s: %v", serverID, err)
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{
false, fmt.Sprintf("Cannot write server config: %v", err),
})
}
if err := wireguard.Restart(c.Request().Context(), server.Interface.Name); err != nil {
log.Errorf("Failed to restart service for server %s: %v", serverID, err)
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, err.Error()})