Technical Briefing – Vpnnode (Mysterium Network Node) Clone: https://github.com/moses-y/Vpnnode (use verbatim)
The Problem
Running a node in the Mysterium dVPN requires assembling a cross‑platform Go service that must compile on Linux, macOS, Windows, and embedded devices (Raspberry Pi, Yocto). The repository is a portfolio of 36 semi‑independent projects (core, services, tequilapi, session, …) rather than a single monolith, which makes onboarding, building, and securing the whole stack non‑trivial. Moreover, the CI/CD configuration contains several hygiene gaps (mutable GitHub‑Action pins, root‑privileged Docker images, missing dependency‑scan gates) that raise the risk of unintended changes or credential leaks.
What This Does
The repo delivers a full‑stack VPN node:
- Core VPN stack – WireGuard transport, NAT discovery, and session management live in
core/andservices/wireguard/. - Tequila API – HTTP‑JSON client‑facing API defined in
tequilapi/(101 files, 99 code files). - CLI & bootstrap – Entry points
cmd/mysterium_node/mysterium_node.go(main) andcmd/di.go(Bootstrap) wire dependency injection, configuration loading, and P2P hand‑shakes. - Docker images – Multi‑stage builds under
bin/docker/produce themysteriumnetwork/mystimage used by the one‑linerdocker run … service --agreed‑terms-and‑conditions. - Installation scripts –
install.sh(referenced from README) provisions a systemd service on Debian/Ubuntu/Raspbian and a Docker container on any host with Docker.
Key files that own the primary effects:
| Effect | Owner |
|---|---|
| Configuration loading & persistence | config/config.go (reads/writes files, env‑var resolution) |
| WireGuard endpoint creation & TUN routing | services/wireguard/endpoint/netstack/netstack.go (creates TUN, batches events) |
| P2P discovery & connection manager | core/connection/manager.go (manages peer state, connects/disconnects) |
| Service startup & lifecycle | cmd/node.go (Start reaches 409 downstream functions) |
| CLI command dispatch | cmd/commands/cli/command.go (defines the public CLI surface) |
Execution flows start at main (cmd/mysterium_node/mysterium_node.go:58) which calls Bootstrap (cmd/di.go:216). From there the call graph fans out: Bootstrap → Check → GloballyReachable → Close → Clean → cleanDNS (subprocess via command.Output), and Run → SaveUserConfig (filesystem write via os.WriteFile). The shortest path to an outbound network call is main → Bootstrap → Check [subprocess].
How It Is Wired
- Entry points (from the internal call graph):
main– reaches 400 functions, no caller inside the repo.Bootstrap– reaches 400 functions, called from 47 places.handler(core/control/handler.go:27) – reaches 32 functions, called from 4 places.run(cmd/natdisco/main.go:42) – reaches 402 functions, called from 1 place.Run(cmd/commands/cli/command.go:171) – reaches 399 functions, called from 51 places.Start(cmd/node.go:65) – reaches 409 functions, called from 41 places.
- Hub modules (high
Ca/Cecounts):Equal(180 callers),New(168),Info(149),Warn(108),Close(97). Changes to these ripple widely.
- Outbound touches (per the “WHAT THIS CODE TOUCHES OUTSIDE ITSELF” block):
- 9 functions make network calls (e.g.,
providerServiceviasession.request.GetConfig). - 30 functions read/write files (
config/config.go,core/storage/boltdb/storage.go). - 5 functions run external commands (
command.Output,cmd.Run). - 3 functions read/write a database (BoltDB).
- 1 function performs crypto operations.
- Module graph – 891 of 891 code files analyzed; 1 internal module, no circular dependencies. The most connected modules are the equality‑checking and new‑type constructors that appear in many call stacks.
How To Use It
Setup
| Platform | Command (from README / repo) |
|---|---|
| Debian/Ubuntu/Raspbian (stable) | sudo -E bash -c "$(curl -s https://raw.githubusercontent.com/mysteriumnetwork/node/master/install.sh)" |
| Docker (any OS with Docker) | ``bash\ndocker run \\\n --cap-add NET_ADMIN \\\n --net host \\\n --name myst -d \\\n mysteriumnetwork/myst service --agreed‑terms‑and‑conditions\n`` |
| Build from source | go build ./cmd/mysterium_node/ (requires Go 1.2+ and the go.mod in the repo root). |
Configuration
- Primary config file:
config/config.godefinesNewConfig,LoadUserConfig,SaveUserConfig. - Environment variables are read by
config/config.go; key vars includeMYSTERIUM_NODE_KEY,MYSTERIUM_NODE_SECRET(generated on first run). - Docker run uses the image
mysteriumnetwork/myst; no extra env vars are required beyond the--agreed‑terms-and‑conditionsflag.
Running it
- Systemd service (post‑install):
sudo systemctl status mysterium-node.service/sudo journalctl -u mysterium-node.service. - Docker: the one‑liner above starts the daemon; logs are fetched with
docker logs -f myst. - CLI:
mysterium node <subcommand>(seecmd/commands/cli/command.gofor subcommands such asstatus,connect,disconnect).
Real‑World Use
A typical deployment: a startup runs the Docker image on a cloud VM with --cap-add NET_ADMIN to provision a WireGuard TUN device. The node registers with the Mysterium network, advertises its exit‑node capacity, and clients route traffic through it. The operator can monitor peer count via mysterium node status and rotate keys by deleting the persisted config (config/config.go) and re‑running the install script. Because the stack is modular, the same binary can be cross‑compiled for a Raspberry Pi (using the bin/build_xgo helper) to run a low‑power exit node in a home network.
Code Health & Issues
The static analysis (42 measured findings) reports:
| Severity | Issue | Files |
|---|---|---|
| HIGH | Pin third‑party GitHub Actions to commit SHA (.github/workflows) | docker/login-action@v3, docker/setup-buildx-action@v3, cpina/github-action-push-to-another-repository@main, indiesdev/curl@v1 |
| HIGH | PRs push directly to default branch (.github/workflows/mobile-release.yml) | git push origin $BRANCH_NAME |
| MEDIUM | Declare least‑privilege GITHUB_TOKEN permissions (.github/workflows/build-packages.yml) | 4 workflows with no permissions declaration |
| MEDIUM | Enable Dependabot/Renovate (no bot configured) | 1 manifest, no update bot |
| MEDIUM | Pin container base image by digest (bin/builder_docker/Dockerfile) | golang:1.26 (mutable tag) |
| MEDIUM | Gate PRs on dependency vulnerability scan (no scan in CI) | absent |
| MEDIUM | Add non‑root USER to Docker image (bin/builder_docker/Dockerfile) | CMD/ENTRYPOINT with no USER directive |
| LOW | Set timeout-minutes on workflow jobs (.github/workflows/build-packages.yml) | 4 jobs with no timeout |
No committed secrets were found; licence and lockfile are present; CI (GitLab) and Dockerfiles exist.
The Bottom Line
The repository provides a mature, well‑tested implementation of a distributed VPN node, with clear separation between core VPN logic, API surface, and deployment tooling. The modular “portfolio” structure is useful for targeting diverse platforms but demands careful onboarding: newcomers must navigate ~36 independent projects and several CI hygiene gaps. Security‑focused operators should pin Action SHAs, add non‑root users to Docker images, and enable dependency scanning. Teams looking for a ready‑to‑run dVPN exit node will find the Docker one‑liner and Debian/Ubuntu install script the fastest path; those needing custom builds or embedded devices will benefit from the Go module layout and cross‑compilation helpers, while investing time in the noted code‑health remediations.