feat(wireguard): client config UX, collapsible config card, configurable DNS

Land the WireGuard client-config UX work on main (the upstream PR #5642
branch could not be pushed to).

- Reusable collapsible ConfigBlock (copy/download/QR, actions aligned right)
  for the client .conf, used by client info and the public sub page.
- Correct .conf: canonical PresharedKey casing and DNS sourced from the inbound
  (configurable per-inbound, default 1.1.1.1, 1.0.0.1).
- Configurable per-inbound DNS for WireGuard (schema + form + backend hint via
  InboundOption.WgDns); inert at the Xray layer.
- Public sub page now shows the WireGuard config, rebuilt from the share link;
  the Go wireguard:// link carries dns/presharedkey/keepalive for completeness.
- QR enabled for the wireguard:// link; link rows are compact like other protocols.
- Client information order is subscription, copy URL, WireGuard config; the
  redundant config tab is removed from the add/edit client modal.
- Drop the Inbound Information and QR Code row actions for WireGuard inbounds.
This commit is contained in:
MHSanaei
2026-06-29 00:50:34 +02:00
parent 60c54827aa
commit a329882e0e
26 changed files with 509 additions and 57 deletions
+9
View File
@@ -545,6 +545,15 @@ func (s *SubService) genWireguardLink(inbound *model.Inbound, email string) stri
if mtu, ok := settings["mtu"].(float64); ok && mtu > 0 {
params["mtu"] = strconv.Itoa(int(mtu))
}
if dns, ok := settings["dns"].(string); ok && dns != "" {
params["dns"] = dns
}
if client.PreSharedKey != "" {
params["presharedkey"] = client.PreSharedKey
}
if client.KeepAlive > 0 {
params["keepalive"] = strconv.Itoa(client.KeepAlive)
}
return buildLinkWithParams(link, params, s.genRemark(inbound, email, "", ""))
}
+34
View File
@@ -18,6 +18,7 @@ import (
"github.com/mhsanaei/3x-ui/v3/internal/mtproto"
"github.com/mhsanaei/3x-ui/v3/internal/util/common"
"github.com/mhsanaei/3x-ui/v3/internal/util/netsafe"
wgutil "github.com/mhsanaei/3x-ui/v3/internal/util/wireguard"
"github.com/mhsanaei/3x-ui/v3/internal/xray"
"gorm.io/gorm"
@@ -298,6 +299,9 @@ type InboundOption struct {
Port int `json:"port" example:"443"`
TlsFlowCapable bool `json:"tlsFlowCapable" example:"true"`
SsMethod string `json:"ssMethod"`
WgPublicKey string `json:"wgPublicKey,omitempty"`
WgMtu int `json:"wgMtu,omitempty"`
WgDns string `json:"wgDns,omitempty"`
// Hosting node; nil for this panel's own inbounds. Lets the clients
// page map a node filter onto inbound IDs (#4997).
NodeId *int `json:"nodeId,omitempty"`
@@ -325,6 +329,7 @@ func (s *InboundService) GetInboundOptions(userId int) ([]InboundOption, error)
}
out := make([]InboundOption, 0, len(rows))
for _, r := range rows {
wgPublicKey, wgMtu, wgDns := inboundWireguardHints(r.Protocol, r.Settings)
out = append(out, InboundOption{
Id: r.Id,
Remark: r.Remark,
@@ -333,12 +338,41 @@ func (s *InboundService) GetInboundOptions(userId int) ([]InboundOption, error)
Port: r.Port,
TlsFlowCapable: inboundCanEnableTlsFlow(r.Protocol, r.StreamSettings, r.Settings),
SsMethod: inboundShadowsocksMethod(r.Protocol, r.Settings),
WgPublicKey: wgPublicKey,
WgMtu: wgMtu,
WgDns: wgDns,
NodeId: r.NodeId,
})
}
return out, nil
}
func inboundWireguardHints(protocol string, settings string) (string, int, string) {
if protocol != string(model.WireGuard) || strings.TrimSpace(settings) == "" {
return "", 0, ""
}
var parsed struct {
PublicKey string `json:"publicKey"`
PubKey string `json:"pubKey"`
SecretKey string `json:"secretKey"`
MTU int `json:"mtu"`
DNS string `json:"dns"`
}
if err := json.Unmarshal([]byte(settings), &parsed); err != nil {
return "", 0, ""
}
publicKey := parsed.PublicKey
if publicKey == "" {
publicKey = parsed.PubKey
}
if publicKey == "" && parsed.SecretKey != "" {
if derived, err := wgutil.PublicKeyFromPrivate(parsed.SecretKey); err == nil {
publicKey = derived
}
}
return publicKey, parsed.MTU, parsed.DNS
}
// GetAllInbounds retrieves all inbounds with client stats.
func (s *InboundService) GetAllInbounds() ([]*model.Inbound, error) {
db := database.GetDB()
+2
View File
@@ -718,6 +718,8 @@
"tabBasics": "Basics",
"tabCredentials": "Credentials",
"tabLinks": "Links",
"wireguardConfig": "WireGuard config",
"conf": "CONF",
"linksHint": "Add third-party share links and remote subscription URLs to include in this client's subscription.",
"addExternalLink": "Add External Link",
"addExternalSubscription": "Add External Subscription",