Docker parses each new line in a RUN command as a potential instruction.
The multi-line python3 -c "..." caused 'unknown instruction: data' errors.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Pre-starting pured in the entrypoint caused ETXTBSY when the install
subprocess (triggered by createRootProcessForMissingComponents) tried
to overwrite the running daemon binary.
- Remove pured pre-start from entrypoint; daemon starts via
`systemctl start pured` inside the install subprocess instead
- systemctl stop: use pkill -9 + sleep 1 for reliable termination
- systemctl start: wait up to 15s for :9485 instead of blind sleep 2
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
purevpn-cli checks `systemctl is-active pured.service` to determine if
components are installed. Without systemd this always returns inactive,
triggering endless sudo/reinstall loop and ETXTBSY when trying to overwrite
the running daemon binary.
Fake systemctl returns "active" when pured is listening on :9485, "inactive"
otherwise. Also handles start/stop/disable/daemon-reload as no-ops.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The purevpn-cli binary hardcodes a wrong S3 path for the daemon download
which returns HTTP 403. The correct URL (from the installer script) is:
/cross-platform/linux-daemon/1.4.1/pured-linux-x64.gz
purevpn-cli is a client that talks to the pured daemon on :9485.
Pre-download the daemon during Docker build and start it in the entrypoint
before any purevpn-cli invocations.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
purevpn-cli is designed to run as non-root and calls sudo internally for
privileged VPN setup. Running as root skips this flow and crashes.
- Add vpnuser (home=/root so login tokens are shared with root setup)
- Configure sudoers secure_path to include /opt/purevpn-cli/bin
- Wrap all purevpn-cli calls in entrypoint with pvpn() helper (su vpnuser)
- Keep iptables/danted running as root
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Real sudo uses env_reset by default, which naturally clears PKG_EXECPATH.
This lets the child binary's pkg bootstrap start fresh and load the embedded
main module correctly — no more 'Cannot find module' crash.
Removes the sudo-wrapper.sh hack entirely; the real sudo package handles
all edge cases (environment cleanup, privilege semantics) correctly.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
PKG_EXECPATH inherited from parent caused pkg bootstrap to treat argv[1] as
a module path. Fix: env -u unsets only PKG_EXECPATH so bootstrap starts fresh
while all auth/session vars are preserved. Depth guard prevents loops.
Also pre-run component installation during Docker build so the sudo code path
is never hit at runtime.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The real issue: PKG_EXECPATH inherited from parent makes pkg bootstrap treat
argv[1] as a module path regardless of arg order. Fix: unset only PKG_EXECPATH
(env -u) so bootstrap starts fresh and loads embedded main. Strip
--install-missing-components since it's not a commander.js flag. Keep all other
env vars for auth/session. Parent handles actual connection after child exits.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
env -i was stripping auth/session env vars the child process needs
to complete the VPN connection. Replace with PUREVPN_SUDO_DEPTH counter
that stops recursion at depth 2 while preserving parent environment.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
pkg bootstrap crashes when argv[1]='--connect' and --install-missing-components
is present — it tries require('/--connect'). Moving --install-missing-components
to argv[1] lets pkg handle it as its own bootstrap flag. Extracted wrapper to
sudo-wrapper.sh for readability.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- MANUAL_CONNECT=true: container waits for tun0, user connects via docker exec
- MANUAL_CONNECT=false: auto mode (current), now with env -i in sudo wrapper
- sudo wrapper logs inherited env key names so we can see what parent injects
- monitor_loop extracted as shared function used by both modes
- auto mode connect logic cleaned up into a single while-true rotation loop
- Removes gcc/make/git and the microsocks git clone+build step
- Installs dante-server from apt — zero compilation required
- danted uses 'external: tun0' to explicitly route all proxied traffic
through the VPN interface, more reliable than iptables-based routing
- Config is generated at runtime after tun0 is confirmed up
HAProxy SOCKS5 entry point + scalable purevpn-cli/microsocks exit nodes.
Supports up to 10 simultaneous connections (PureVPN limit), random location
selection from a predefined pool, and automatic reconnect to an unused
location on server-side drop.