mirror of
https://github.com/qdm12/gluetun.git
synced 2026-06-11 06:42:23 +02:00
SERVER_DEDICATED option
This commit is contained in:
@@ -192,6 +192,8 @@ ENV VPN_SERVICE_PROVIDER=pia \
|
|||||||
PREMIUM_ONLY= \
|
PREMIUM_ONLY= \
|
||||||
# # PIA and ProtonVPN only:
|
# # PIA and ProtonVPN only:
|
||||||
PORT_FORWARD_ONLY= \
|
PORT_FORWARD_ONLY= \
|
||||||
|
# # Ovpn only:
|
||||||
|
SERVER_DEDICATED=no \
|
||||||
# Firewall
|
# Firewall
|
||||||
FIREWALL_ENABLED_DISABLING_IT_SHOOTS_YOU_IN_YOUR_FOOT=on \
|
FIREWALL_ENABLED_DISABLING_IT_SHOOTS_YOU_IN_YOUR_FOOT=on \
|
||||||
FIREWALL_VPN_INPUT_PORTS= \
|
FIREWALL_VPN_INPUT_PORTS= \
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ require (
|
|||||||
github.com/mdlayher/netlink v1.9.0
|
github.com/mdlayher/netlink v1.9.0
|
||||||
github.com/pelletier/go-toml/v2 v2.2.4
|
github.com/pelletier/go-toml/v2 v2.2.4
|
||||||
github.com/qdm12/dns/v2 v2.0.0-rc9.0.20260421173011-9de8e7fdbe3a
|
github.com/qdm12/dns/v2 v2.0.0-rc9.0.20260421173011-9de8e7fdbe3a
|
||||||
github.com/qdm12/gluetun-servers v0.1.1-0.20260521235724-060a16d4b34c
|
github.com/qdm12/gluetun-servers v0.1.1-0.20260522005421-14277e92ce82
|
||||||
github.com/qdm12/goservices v0.1.1-0.20251104135713-6bee97bd4978
|
github.com/qdm12/goservices v0.1.1-0.20251104135713-6bee97bd4978
|
||||||
github.com/qdm12/gosettings v0.4.4
|
github.com/qdm12/gosettings v0.4.4
|
||||||
github.com/qdm12/goshutdown v0.3.0
|
github.com/qdm12/goshutdown v0.3.0
|
||||||
|
|||||||
@@ -76,8 +76,8 @@ github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0leargg
|
|||||||
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||||
github.com/qdm12/dns/v2 v2.0.0-rc9.0.20260421173011-9de8e7fdbe3a h1:TE157yPQmAbVruH0MWCQzs0vTT/6t96DkoWUXd6PVuc=
|
github.com/qdm12/dns/v2 v2.0.0-rc9.0.20260421173011-9de8e7fdbe3a h1:TE157yPQmAbVruH0MWCQzs0vTT/6t96DkoWUXd6PVuc=
|
||||||
github.com/qdm12/dns/v2 v2.0.0-rc9.0.20260421173011-9de8e7fdbe3a/go.mod h1:98foWgXJZ+g8gJIuO+fdO+oWpFei5WShMFTeN4Im2lE=
|
github.com/qdm12/dns/v2 v2.0.0-rc9.0.20260421173011-9de8e7fdbe3a/go.mod h1:98foWgXJZ+g8gJIuO+fdO+oWpFei5WShMFTeN4Im2lE=
|
||||||
github.com/qdm12/gluetun-servers v0.1.1-0.20260521235724-060a16d4b34c h1:rPgmhMt9uOq6pdPr8k0sXUnZ0fjTBw+yUOaIl0ttFu4=
|
github.com/qdm12/gluetun-servers v0.1.1-0.20260522005421-14277e92ce82 h1:tE44IEW7o9yPQaO8HBeoO9RxtTTxqhboIypegrQlVt8=
|
||||||
github.com/qdm12/gluetun-servers v0.1.1-0.20260521235724-060a16d4b34c/go.mod h1:acttuyHyoFDu6GTbf3kAV+QXeiX8oJeh0MBic67/9z8=
|
github.com/qdm12/gluetun-servers v0.1.1-0.20260522005421-14277e92ce82/go.mod h1:acttuyHyoFDu6GTbf3kAV+QXeiX8oJeh0MBic67/9z8=
|
||||||
github.com/qdm12/goservices v0.1.1-0.20251104135713-6bee97bd4978 h1:TRGpCU1l0lNwtogEUSs5U+RFceYxkAJUmrGabno7J5c=
|
github.com/qdm12/goservices v0.1.1-0.20251104135713-6bee97bd4978 h1:TRGpCU1l0lNwtogEUSs5U+RFceYxkAJUmrGabno7J5c=
|
||||||
github.com/qdm12/goservices v0.1.1-0.20251104135713-6bee97bd4978/go.mod h1:D1Po4CRQLYjccnAR2JsVlN1sBMgQrcNLONbvyuzcdTg=
|
github.com/qdm12/goservices v0.1.1-0.20251104135713-6bee97bd4978/go.mod h1:D1Po4CRQLYjccnAR2JsVlN1sBMgQrcNLONbvyuzcdTg=
|
||||||
github.com/qdm12/gosettings v0.4.4 h1:SM6tOZDf6k8qbjWU8KWyBF4mWIixfsKCfh9DGRLHlj4=
|
github.com/qdm12/gosettings v0.4.4 h1:SM6tOZDf6k8qbjWU8KWyBF4mWIixfsKCfh9DGRLHlj4=
|
||||||
|
|||||||
@@ -63,6 +63,9 @@ type ServerSelection struct {
|
|||||||
// TorOnly is true if VPN servers without tor should
|
// TorOnly is true if VPN servers without tor should
|
||||||
// be filtered. This is used with ProtonVPN.
|
// be filtered. This is used with ProtonVPN.
|
||||||
TorOnly *bool `json:"tor_only"`
|
TorOnly *bool `json:"tor_only"`
|
||||||
|
// Dedicated is true if dedicated VPN servers should be chosen only.
|
||||||
|
// This is used with OVPN.
|
||||||
|
Dedicated *bool `json:"dedicated"`
|
||||||
// OpenVPN contains settings to select OpenVPN servers
|
// OpenVPN contains settings to select OpenVPN servers
|
||||||
// and the final connection.
|
// and the final connection.
|
||||||
OpenVPN OpenVPNSelection `json:"openvpn"`
|
OpenVPN OpenVPNSelection `json:"openvpn"`
|
||||||
@@ -272,6 +275,8 @@ func validateFeatureFilters(settings ServerSelection, vpnServiceProvider string)
|
|||||||
return errors.New("secure core only filter is not supported")
|
return errors.New("secure core only filter is not supported")
|
||||||
case *settings.TorOnly && vpnServiceProvider != providers.Protonvpn:
|
case *settings.TorOnly && vpnServiceProvider != providers.Protonvpn:
|
||||||
return errors.New("tor only filter is not supported")
|
return errors.New("tor only filter is not supported")
|
||||||
|
case *settings.Dedicated && vpnServiceProvider != providers.Ovpn:
|
||||||
|
return errors.New("dedicated filter is not supported")
|
||||||
default:
|
default:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -296,6 +301,7 @@ func (ss *ServerSelection) copy() (copied ServerSelection) {
|
|||||||
TorOnly: gosettings.CopyPointer(ss.TorOnly),
|
TorOnly: gosettings.CopyPointer(ss.TorOnly),
|
||||||
PortForwardOnly: gosettings.CopyPointer(ss.PortForwardOnly),
|
PortForwardOnly: gosettings.CopyPointer(ss.PortForwardOnly),
|
||||||
MultiHopOnly: gosettings.CopyPointer(ss.MultiHopOnly),
|
MultiHopOnly: gosettings.CopyPointer(ss.MultiHopOnly),
|
||||||
|
Dedicated: gosettings.CopyPointer(ss.Dedicated),
|
||||||
OpenVPN: ss.OpenVPN.copy(),
|
OpenVPN: ss.OpenVPN.copy(),
|
||||||
Wireguard: ss.Wireguard.copy(),
|
Wireguard: ss.Wireguard.copy(),
|
||||||
}
|
}
|
||||||
@@ -319,6 +325,7 @@ func (ss *ServerSelection) overrideWith(other ServerSelection) {
|
|||||||
ss.TorOnly = gosettings.OverrideWithPointer(ss.TorOnly, other.TorOnly)
|
ss.TorOnly = gosettings.OverrideWithPointer(ss.TorOnly, other.TorOnly)
|
||||||
ss.MultiHopOnly = gosettings.OverrideWithPointer(ss.MultiHopOnly, other.MultiHopOnly)
|
ss.MultiHopOnly = gosettings.OverrideWithPointer(ss.MultiHopOnly, other.MultiHopOnly)
|
||||||
ss.PortForwardOnly = gosettings.OverrideWithPointer(ss.PortForwardOnly, other.PortForwardOnly)
|
ss.PortForwardOnly = gosettings.OverrideWithPointer(ss.PortForwardOnly, other.PortForwardOnly)
|
||||||
|
ss.Dedicated = gosettings.OverrideWithPointer(ss.Dedicated, other.Dedicated)
|
||||||
ss.OpenVPN.overrideWith(other.OpenVPN)
|
ss.OpenVPN.overrideWith(other.OpenVPN)
|
||||||
ss.Wireguard.overrideWith(other.Wireguard)
|
ss.Wireguard.overrideWith(other.Wireguard)
|
||||||
}
|
}
|
||||||
@@ -335,6 +342,7 @@ func (ss *ServerSelection) setDefaults(vpnProvider string, portForwardingEnabled
|
|||||||
defaultPortForwardOnly := portForwardingEnabled &&
|
defaultPortForwardOnly := portForwardingEnabled &&
|
||||||
helpers.IsOneOf(vpnProvider, providers.PrivateInternetAccess, providers.Protonvpn)
|
helpers.IsOneOf(vpnProvider, providers.PrivateInternetAccess, providers.Protonvpn)
|
||||||
ss.PortForwardOnly = gosettings.DefaultPointer(ss.PortForwardOnly, defaultPortForwardOnly)
|
ss.PortForwardOnly = gosettings.DefaultPointer(ss.PortForwardOnly, defaultPortForwardOnly)
|
||||||
|
ss.Dedicated = gosettings.DefaultPointer(ss.Dedicated, false)
|
||||||
ss.OpenVPN.setDefaults(vpnProvider)
|
ss.OpenVPN.setDefaults(vpnProvider)
|
||||||
ss.Wireguard.setDefaults()
|
ss.Wireguard.setDefaults()
|
||||||
}
|
}
|
||||||
@@ -410,6 +418,10 @@ func (ss ServerSelection) toLinesNode() (node *gotree.Node) {
|
|||||||
node.Appendf("Multi-hop only servers: yes")
|
node.Appendf("Multi-hop only servers: yes")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if *ss.Dedicated {
|
||||||
|
node.Appendf("Dedicated servers: yes")
|
||||||
|
}
|
||||||
|
|
||||||
if *ss.PortForwardOnly {
|
if *ss.PortForwardOnly {
|
||||||
node.Appendf("Port forwarding only servers: yes")
|
node.Appendf("Port forwarding only servers: yes")
|
||||||
}
|
}
|
||||||
@@ -501,6 +513,12 @@ func (ss *ServerSelection) read(r *reader.Reader,
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ovpn only
|
||||||
|
ss.Dedicated, err = r.BoolPtr("SERVER_DEDICATED")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
err = ss.OpenVPN.read(r)
|
err = ss.OpenVPN.read(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ type Server struct {
|
|||||||
SecureCore bool `json:"secure_core,omitempty"`
|
SecureCore bool `json:"secure_core,omitempty"`
|
||||||
Tor bool `json:"tor,omitempty"`
|
Tor bool `json:"tor,omitempty"`
|
||||||
PortForward bool `json:"port_forward,omitempty"`
|
PortForward bool `json:"port_forward,omitempty"`
|
||||||
|
Dedicated bool `json:"dedicated,omitempty"`
|
||||||
Keep bool `json:"keep,omitempty"`
|
Keep bool `json:"keep,omitempty"`
|
||||||
IPs []netip.Addr `json:"ips,omitempty"`
|
IPs []netip.Addr `json:"ips,omitempty"`
|
||||||
PortsTCP []uint16 `json:"ports_tcp,omitempty"`
|
PortsTCP []uint16 `json:"ports_tcp,omitempty"`
|
||||||
|
|||||||
@@ -22,13 +22,16 @@ type apiDataCenter struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type apiServer struct {
|
type apiServer struct {
|
||||||
IP netip.Addr `json:"ip"`
|
IP netip.Addr `json:"ip"`
|
||||||
Ptr string `json:"ptr"` // hostname
|
Ptr string `json:"ptr"` // hostname
|
||||||
Online bool `json:"online"`
|
Online bool `json:"online"`
|
||||||
PublicKey string `json:"public_key"`
|
// PublicKey is for the Standard Shared Entry Point
|
||||||
WireguardPorts []uint16 `json:"wireguard_ports"`
|
PublicKey string `json:"public_key"`
|
||||||
MultiHopOpenvpnPort uint16 `json:"multihop_openvpn_port"`
|
// PublicKeyIPv4 is for the Public / Dedicated IP Entry Point
|
||||||
MultiHopWireguardPort uint16 `json:"multihop_wireguard_port"`
|
PublicKeyIPv4 string `json:"public_key_ipv4"`
|
||||||
|
WireguardPorts []uint16 `json:"wireguard_ports"`
|
||||||
|
MultiHopOpenvpnPort uint16 `json:"multihop_openvpn_port"`
|
||||||
|
MultiHopWireguardPort uint16 `json:"multihop_wireguard_port"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchAPI(ctx context.Context, client *http.Client) (
|
func fetchAPI(ctx context.Context, client *http.Client) (
|
||||||
@@ -106,6 +109,7 @@ func (a *apiServer) validate() (err error) {
|
|||||||
{err: "ip address is not set", condition: !a.IP.IsValid()},
|
{err: "ip address is not set", condition: !a.IP.IsValid()},
|
||||||
{err: "hostname field is not set", condition: a.Ptr == ""},
|
{err: "hostname field is not set", condition: a.Ptr == ""},
|
||||||
{err: "public key field is not set", condition: a.PublicKey == ""},
|
{err: "public key field is not set", condition: a.PublicKey == ""},
|
||||||
|
{err: "public key IPv4 field is not set", condition: a.PublicKeyIPv4 == ""},
|
||||||
{err: "wireguard ports array is not set", condition: len(a.WireguardPorts) == 0},
|
{err: "wireguard ports array is not set", condition: len(a.WireguardPorts) == 0},
|
||||||
{
|
{
|
||||||
err: "wireguard port is not the default 9929",
|
err: "wireguard port is not the default 9929",
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ func Test_fetchAPI(t *testing.T) {
|
|||||||
Ptr: "vpn44.prd.vienna.ovpn.com",
|
Ptr: "vpn44.prd.vienna.ovpn.com",
|
||||||
Online: true,
|
Online: true,
|
||||||
PublicKey: "r83LIc0Q2F8s3dY9x5y17Yz8wTADJc7giW1t5eSmoXc=",
|
PublicKey: "r83LIc0Q2F8s3dY9x5y17Yz8wTADJc7giW1t5eSmoXc=",
|
||||||
|
PublicKeyIPv4: "wFbSRyjSXBmkjJodlqz7DoYn3WNDPYFUIXyIUS2QU2A=",
|
||||||
WireguardPorts: []uint16{9929},
|
WireguardPorts: []uint16{9929},
|
||||||
MultiHopOpenvpnPort: 20044,
|
MultiHopOpenvpnPort: 20044,
|
||||||
MultiHopWireguardPort: 30044,
|
MultiHopWireguardPort: 30044,
|
||||||
|
|||||||
@@ -56,7 +56,18 @@ func (u *Updater) FetchServers(ctx context.Context, minServers int) (
|
|||||||
multiHopWireguardServer := wireguardServer
|
multiHopWireguardServer := wireguardServer
|
||||||
multiHopWireguardServer.MultiHop = true
|
multiHopWireguardServer.MultiHop = true
|
||||||
multiHopWireguardServer.PortsUDP = []uint16{apiServer.MultiHopWireguardPort}
|
multiHopWireguardServer.PortsUDP = []uint16{apiServer.MultiHopWireguardPort}
|
||||||
servers = append(servers, wireguardServer, multiHopWireguardServer)
|
dedicatedWireguardServer := wireguardServer
|
||||||
|
dedicatedWireguardServer.WgPubKey = apiServer.PublicKeyIPv4
|
||||||
|
dedicatedWireguardServer.Dedicated = true
|
||||||
|
dedicatedMultiHopWireguardServer := multiHopWireguardServer
|
||||||
|
dedicatedMultiHopWireguardServer.WgPubKey = apiServer.PublicKeyIPv4
|
||||||
|
dedicatedMultiHopWireguardServer.Dedicated = true
|
||||||
|
servers = append(servers,
|
||||||
|
wireguardServer,
|
||||||
|
multiHopWireguardServer,
|
||||||
|
dedicatedWireguardServer,
|
||||||
|
dedicatedMultiHopWireguardServer,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ func Test_Updater_FetchServers(t *testing.T) {
|
|||||||
errMessage: "validating data center 1 of 1: data center Vienna: country name is not set",
|
errMessage: "validating data center 1 of 1: data center Vienna: country name is not set",
|
||||||
},
|
},
|
||||||
"not_enough_servers": {
|
"not_enough_servers": {
|
||||||
minServers: 5,
|
minServers: 7,
|
||||||
responseStatus: http.StatusOK,
|
responseStatus: http.StatusOK,
|
||||||
responseBody: `{
|
responseBody: `{
|
||||||
"success": true,
|
"success": true,
|
||||||
@@ -69,6 +69,7 @@ func Test_Updater_FetchServers(t *testing.T) {
|
|||||||
"ptr": "vpn44.prd.vienna.ovpn.com",
|
"ptr": "vpn44.prd.vienna.ovpn.com",
|
||||||
"online": true,
|
"online": true,
|
||||||
"public_key": "r83LIc0Q2F8s3dY9x5y17Yz8wTADJc7giW1t5eSmoXc=",
|
"public_key": "r83LIc0Q2F8s3dY9x5y17Yz8wTADJc7giW1t5eSmoXc=",
|
||||||
|
"public_key_ipv4": "wFbSRyjSXBmkjJodlqz7DoYn3WNDPYFUIXyIUS2QU2A=",
|
||||||
"wireguard_ports": [9929],
|
"wireguard_ports": [9929],
|
||||||
"multihop_openvpn_port": 20044,
|
"multihop_openvpn_port": 20044,
|
||||||
"multihop_wireguard_port": 30044
|
"multihop_wireguard_port": 30044
|
||||||
@@ -78,7 +79,9 @@ func Test_Updater_FetchServers(t *testing.T) {
|
|||||||
]
|
]
|
||||||
}`,
|
}`,
|
||||||
errWrapped: common.ErrNotEnoughServers,
|
errWrapped: common.ErrNotEnoughServers,
|
||||||
errMessage: "not enough servers found: 4 and expected at least 5",
|
// Wireguard + dedicated Wireguard + Wireguard multi-hop +
|
||||||
|
// dedicated Wireguard multi-hop + OpenVPN + OpenVPN multi-hop
|
||||||
|
errMessage: "not enough servers found: 6 and expected at least 7",
|
||||||
},
|
},
|
||||||
"success": {
|
"success": {
|
||||||
minServers: 4,
|
minServers: 4,
|
||||||
@@ -114,6 +117,7 @@ func Test_Updater_FetchServers(t *testing.T) {
|
|||||||
"ptr": "vpn45.prd.vienna.ovpn.com",
|
"ptr": "vpn45.prd.vienna.ovpn.com",
|
||||||
"online": false,
|
"online": false,
|
||||||
"public_key": "r93LIc0Q2F8s3dY9x5y17Yz8wTADJc7giW1t5eSmoXc=",
|
"public_key": "r93LIc0Q2F8s3dY9x5y17Yz8wTADJc7giW1t5eSmoXc=",
|
||||||
|
"public_key_ipv4": "wGbSRyjSXBmkjJodlqz7DoYn3WNDPYFUIXyIUS2QU2A=",
|
||||||
"wireguard_ports": [9929],
|
"wireguard_ports": [9929],
|
||||||
"multihop_openvpn_port": 20045,
|
"multihop_openvpn_port": 20045,
|
||||||
"multihop_wireguard_port": 30045
|
"multihop_wireguard_port": 30045
|
||||||
@@ -163,6 +167,26 @@ func Test_Updater_FetchServers(t *testing.T) {
|
|||||||
MultiHop: true,
|
MultiHop: true,
|
||||||
PortsUDP: []uint16{30044},
|
PortsUDP: []uint16{30044},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Country: "Austria",
|
||||||
|
City: "Vienna",
|
||||||
|
Hostname: "vpn44.prd.vienna.ovpn.com",
|
||||||
|
IPs: []netip.Addr{netip.MustParseAddr("37.120.212.227")},
|
||||||
|
VPN: vpn.Wireguard,
|
||||||
|
WgPubKey: "wFbSRyjSXBmkjJodlqz7DoYn3WNDPYFUIXyIUS2QU2A=",
|
||||||
|
Dedicated: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Country: "Austria",
|
||||||
|
City: "Vienna",
|
||||||
|
Hostname: "vpn44.prd.vienna.ovpn.com",
|
||||||
|
IPs: []netip.Addr{netip.MustParseAddr("37.120.212.227")},
|
||||||
|
VPN: vpn.Wireguard,
|
||||||
|
WgPubKey: "wFbSRyjSXBmkjJodlqz7DoYn3WNDPYFUIXyIUS2QU2A=",
|
||||||
|
MultiHop: true,
|
||||||
|
Dedicated: true,
|
||||||
|
PortsUDP: []uint16{30044},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ func (s *Storage) FilterServers(provider string, selection settings.ServerSelect
|
|||||||
return servers, nil
|
return servers, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//nolint:gocognit,gocyclo
|
||||||
func filterServer(server models.Server,
|
func filterServer(server models.Server,
|
||||||
selection settings.ServerSelection,
|
selection settings.ServerSelection,
|
||||||
) (filtered bool) {
|
) (filtered bool) {
|
||||||
@@ -91,6 +92,11 @@ func filterServer(server models.Server,
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (*selection.Dedicated && !server.Dedicated) ||
|
||||||
|
(!*selection.Dedicated && server.Dedicated) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
if filterByPossibilities(server.Country, selection.Countries) {
|
if filterByPossibilities(server.Country, selection.Countries) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user