Files
wireguard-ui-multi/templates/wg.conf
T
sysops cf9c136874 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.
2026-07-25 19:53:26 +02:00

50 lines
2.5 KiB
Plaintext

# This file was generated using wireguard-ui (https://github.com/ngoduykhanh/wireguard-ui)
# Please don't modify it manually, otherwise your change might get replaced.
# Address updated at: {{ .serverConfig.Interface.UpdatedAt }}
# Private Key updated at: {{ .serverConfig.KeyPair.UpdatedAt }}
[Interface]
Address = {{$first :=true}}{{range .serverConfig.Interface.Addresses }}{{if $first}}{{$first = false}}{{else}},{{end}}{{.}}{{end}}
ListenPort = {{ .serverConfig.Interface.ListenPort }}
PrivateKey = {{ .serverConfig.KeyPair.PrivateKey }}
{{if .globalSettings.MTU}}MTU = {{ .globalSettings.MTU }}{{end}}
PreUp = {{ .serverConfig.Interface.PreUp }}
# Table is forced to "off" and routes are (re)installed explicitly below via
# `ip route replace` instead of letting wg-quick manage them with `ip route
# add`. Multiple servers on this box can legitimately share an overlapping
# AllowedIPs entry (e.g. the same /32 reachable via more than one tunnel);
# wg-quick's own route handling hard-fails the whole interface with
# "RTNETLINK: File exists" the moment two servers claim the same route,
# which used to take down every server started after the first. `replace`
# is idempotent and never fails on a pre-existing route.
PostUp = {{ .serverConfig.Interface.PostUp }}{{range .clientDataList}}{{if eq .Client.Enabled true}}{{range .Client.AllocatedIPs}}ip route replace {{.}} dev %i; {{end}}{{range .Client.ExtraAllowedIPs}}ip route replace {{.}} dev %i; {{end}}{{end}}{{end}}
PreDown = {{ .serverConfig.Interface.PreDown }}
PostDown = {{ .serverConfig.Interface.PostDown }}
Table = off
{{range .clientDataList}}{{if eq .Client.Enabled true}}
# ID: {{ .Client.ID }}
# Name: {{ .Client.Name }}
# Email: {{ .Client.Email }}
# Telegram: {{ .Client.TgUserid }}
# Created at: {{ .Client.CreatedAt }}
# Update at: {{ .Client.UpdatedAt }}
{{- if .Client.AdditionalNotes}}
# Notes:
# {{ .Client.AdditionalNotes }}{{end}}
[Peer]
PublicKey = {{ .Client.PublicKey }}
{{if .Client.PresharedKey}}PresharedKey = {{ .Client.PresharedKey }}{{end}}
AllowedIPs = {{ $first := true }}
{{- range .Client.AllocatedIPs -}}
{{- if not $first}}, {{ end -}}{{ . -}}{{ $first = false -}}
{{- end -}}
{{- range .Client.ExtraAllowedIPs -}}
{{- if not $first}}, {{ end -}}{{ . -}}{{ $first = false -}}
{{- end }}
{{"\n"}}
{{if $.globalSettings.PersistentKeepalive}}PersistentKeepalive = {{ $.globalSettings.PersistentKeepalive }}{{end}}
{{if .Client.Endpoint}}Endpoint = {{ .Client.Endpoint }}{{end}}
{{end}}{{end}}