Skip to content

PureVPN provider revamp#3165

Draft
reedog117 wants to merge 21 commits intoqdm12:masterfrom
reedog117:codex/purevpn-deb-updater
Draft

PureVPN provider revamp#3165
reedog117 wants to merge 21 commits intoqdm12:masterfrom
reedog117:codex/purevpn-deb-updater

Conversation

@reedog117
Copy link
Copy Markdown

@reedog117 reedog117 commented Feb 27, 2026

Description

PureVPN provider revamp:

  • integrates PureVPN inventory-driven server selection and OpenVPN template ingestion by extracting this from the PureVPN Linux client
  • removes legacy fallback port behavior in OpenVPN config generation and uses inventory-provided ports
  • aligns filtering behavior around stable location fields and inventory tags (including p2p/category/type filtering updates)

Issue

Assertions

  • I am aware that we do not accept manual changes to the servers.json file
  • I am aware that any changes to settings should be reflected in the wiki

@reedog117
Copy link
Copy Markdown
Author

This PR is more comprehensive but addresses much of the shortcomings of #3149 by finding a better avenue to get an updated server list and parsing accepted protocols, port numbers, and other attributes directly from the same source used by PureVPN's GUI clients.

@reedog117
Copy link
Copy Markdown
Author

Test results summary for the PureVPN provider revamp branch.

Branch / commit

  • Branch: codex/purevpn-deb-updater
  • Head: 9c634605

1) Targeted validation on host (macOS)

go build ./cmd/gluetun
go test ./internal/provider/purevpn/... ./internal/provider/purevpn/updater/...

Result: ✅ pass

2) Targeted validation in Linux amd64 container

docker run --rm --platform linux/amd64 \
  -v "$PWD":/src -w /src golang:1.25-alpine3.22 \
  sh -lc '/usr/local/go/bin/go build ./cmd/gluetun && /usr/local/go/bin/go test ./internal/provider/purevpn/... ./internal/provider/purevpn/updater/...'

Result: ✅ pass

3) Full suite on host (informational)

go test ./...

Result: ⚠️ not fully green in this local macOS environment due unrelated/platform-sensitive tests:

  • internal/natpmp (UDP/rpc timeout expectation mismatch)
  • internal/netlink (wireguard support panic on unspecified platform)
  • internal/tun (operation not permitted on TUN node creation)

PureVPN-related packages are green in all runs above.

@reedog117
Copy link
Copy Markdown
Author

This potentially also closes #1501 #1725 and #1653

1. The VPN server IP address you are trying to connect to is no longer valid 🔌
Check out https://github.com/qdm12/gluetun-wiki/blob/main/setup/servers.md#update-the-vpn-servers-list

2. The VPN server crashed 💥, try changing your VPN servers filtering options such as SERVER_REGIONS
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

revert

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed. I reverted this message change and restored SERVER_REGIONS in internal/openvpn/logs.go (and corresponding test).

Comment on lines +157 to +158
_ = ss
_ = warner
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

??????

Also we want to maintain retro-compatibility

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed. I removed the placeholder _ = ss / _ = warner edits and restored the Surfshark retro-compatibility branch in getLocationFilterChoices.

Comment on lines +62 to +64
// PureVPNCountryCodes filters PureVPN servers by deterministic
// 2-letter country code parsed from the hostname prefix.
PureVPNCountryCodes []string `json:"purevpn_country_codes"`
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use the Countries field and do a lookup country->country-code to maintain retro-compatibility and simplify code.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed by removing the PureVPNCountryCodes feature from this PR. PureVPN now uses the existing selection fields (including Countries) for compatibility; the extra country-code filter knobs are no longer part of this PR.

Comment on lines +65 to +67
// PureVPNLocationCodes filters PureVPN servers by deterministic
// location code parsed from the hostname prefix (for example usca, ukm).
PureVPNLocationCodes []string `json:"purevpn_location_codes"`
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sounds like we could use the Hostnames field then

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed by removing PureVPNLocationCodes from this PR. Deterministic per-host selection remains available through the existing Hostnames field.

return fmt.Errorf("%w: %w", ErrCountryNotValid, err)
}

err = atLeastOneIsOneOfCaseInsensitive(settings.Regions, filterChoices.Regions, warner)
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

regions is used for nordvpn. I get AI makes it easier to rewrite stuff, but please at the very least read changes made and verify a bit. Otherwise it adds excessive load for me to review these, especially with the increasing amount of AI generated PRs.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey sorry I was a bit moody on the AI-generated PR; if you're not a Go developer, then I 100% appreciate the gesture, and I'll comment on what's to change and the AI can then adapt it. However if you're a Go dev, I would definitely appreciate you reading up on the changes first 😉 !

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No worries - I'm def not a Go dev - my specialty in infra bash/terraform/NodeJS. My understanding was that I stopped using the regions field for PureVPN, but it was still being used for any other provider. Currently doing another scan to doublecheck, but unfortunately I don't have another set of creds with another provider other than PureVPN to confirm.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm trying to figure out a way to populate regions for PureVPN but I think I end up getting ratelimited by the IP geolocation APIs due to the sheer number of servers that need to be looked up.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed. Region validation remains for non-PureVPN providers (including NordVPN) and the broader region logic has been restored. For PureVPN specifically, I now ignore SERVER_REGIONS at validation time to avoid impacting PureVPN selection.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Appreciate it. I went through each requested change line-by-line, restored the non-PureVPN region behavior, and split out the extra PureVPN filtering feature work from this PR.

ss.Countries = r.CSV("SERVER_COUNTRIES", reader.RetroKeys(countriesRetroKeys...))

ss.Regions = r.CSV("SERVER_REGIONS", reader.RetroKeys("REGION"))
ss.Regions = nil
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

revert

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed. I reverted ss.Regions = nil in read() so SERVER_REGIONS is still parsed normally. PureVPN-specific behavior is now handled later in validation (regions are ignored only when provider is PureVPN).

Check out https://github.com/qdm12/gluetun-wiki/blob/main/setup/servers.md#update-the-vpn-servers-list

2. The VPN server crashed 💥, try changing your VPN servers filtering options such as SERVER_REGIONS
2. The VPN server crashed 💥, try changing your VPN servers filtering options such as SERVER_CITIES
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unneeded change, revert

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed. Reverted this test change so it matches the restored SERVER_REGIONS log message.


const url = "https://d11a57lttb2ffq.cloudfront.net/heartbleed/router/Recommended-CA2.zip"
contents, err := u.unzipper.FetchAndExtract(ctx, url)
debContent, err := fetchURL(ctx, http.DefaultClient, debURL)
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use the u.client instead of http.DefaultClient. If not present, inject it into the Updater New function

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed. I injected the HTTP client into the PureVPN updater (Updater now has client *http.Client), defaulting to http.DefaultClient only if nil. .deb URL/content and inventory fetches now use u.client.

@reedog117
Copy link
Copy Markdown
Author

[Generated by Codex]

Summary of review feedback addressed:

  • Reverted OpenVPN TLS help text change and restored SERVER_REGIONS wording in:
    • internal/openvpn/logs.go
    • internal/openvpn/logs_test.go
  • Restored Surfshark retro-compatibility logic in getLocationFilterChoices.
  • Restored region validation/filtering behavior for non-PureVPN providers (including NordVPN).
  • Kept SERVER_REGIONS parsing in read() for compatibility, and now ignore regions only when provider is PureVPN during validation.
  • Removed the extra PureVPN filtering feature set (PureVPNServerTypes, PureVPNCountryCodes, PureVPNLocationCodes) from this PR so it can be split separately.
  • Updated PureVPN updater networking to use injected client (u.client) instead of direct http.DefaultClient calls:
    • Added client *http.Client to updater
    • Default to http.DefaultClient only if nil
    • Switched .deb and inventory fetches to u.client

Validation done locally:

  • go test ./internal/configuration/settings ./internal/provider/purevpn/... ./internal/provider/utils ./internal/storage ./internal/openvpn
  • go build ./cmd/gluetun
  • Real containerized PureVPN UDP connect test with credentials:
    • OpenVPN reached Initialization Sequence Completed
    • In-container egress IP checks confirmed VPN-routed traffic (distinct from host IP)

@reedog117
Copy link
Copy Markdown
Author

[Generated by Codex]\n\nI split the selector work into a dedicated stacked PR based on :\n- https://github.com/reedog117/gluetun/pull/1\n\nThis contains the PureVPN selector functionality (, , , , country/location code selectors) separated from the base updater changes.

@reedog117
Copy link
Copy Markdown
Author

[Generated by Codex]

I split the selector work into a dedicated stacked PR based on codex/purevpn-deb-updater:

This contains the PureVPN selector functionality (p2p, quantumresistant, obfuscation, portforwarding, and country/location code selectors) separated from the base updater changes.

@reedog117
Copy link
Copy Markdown
Author

[Generated by Codex]

I split the selector work into a dedicated stacked PR based on codex/purevpn-deb-updater:

This contains the PureVPN selector functionality (p2p, quantumresistant, obfuscation, portforwarding, and country/location code selectors) separated from the base updater changes.

This PR #3165 needs to be merged in before I can bring the selector functionality in as a separate PR as it's dependent on the new server inventory selection methods from here.

@reedog117
Copy link
Copy Markdown
Author

@qdm12 what additional steps are needed at this point to merge this and then i can bring in the newer selector functionality?

@reedog117 reedog117 requested a review from qdm12 March 28, 2026 21:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: gluetun is always trying port 53 for connection when downloaded OpenVPN files from PureVPN reference port 1194.

2 participants