The Story Behind This
I built FourDollarVPN because every time I wanted a personal VPN, I hit the same wall: spin up a server, SSH in, install WireGuard, edit config files, fight with the firewall, generate keys, copy them around, then debug why the tunnel won't come up. It's the kind of task that takes ten minutes if you've done it a hundred times — and an entire afternoon if you haven't.
Meanwhile the alternative — paying a commercial VPN provider — means handing your traffic to a company that might be logging it, might be owned by someone you've never heard of, and might be quietly compromised the next time their shared infrastructure gets popped. Several have been caught lying about their no-log policies. A significant share of the popular "privacy" VPNs are quietly owned by holding companies in jurisdictions with opaque data-handling laws.
FourDollarVPN collapses the do-it-yourself path into one command:
fourdollarvpn setup
About 90 seconds later, you have a hardened WireGuard server running on DigitalOcean and a .conf file (plus a QR code) ready to import into the WireGuard client on any device.
What FourDollarVPN Actually Does
When you run fourdollarvpn setup, it walks through nine steps with a live progress bar showing the current step, elapsed time, and step counter:
- Creates a small Ubuntu 24.04 droplet on DigitalOcean (~$4/month, size
s-1vcpu-512mb-10gb) - Tags the droplet
fourdollarvpnat creation so later commands identify it by tag rather than guessing from its name - Connects over SSH using a freshly generated Ed25519 key. The public half is removed from your DigitalOcean account the moment it's served its purpose (DO bakes it into the droplet's
authorized_keysonce, at create time). The private half is persisted locally, indexed by the droplet's ID — so if DO ever recycles an IP to a different droplet, the CLI refuses to trust the stranger on the other end. - Installs WireGuard, generates server keys, and configures the interface
- Locks down the firewall — only SSH (22/tcp) and WireGuard (51820/udp) are open
- Installs
fail2ban(5 failed logins = 1 hour ban) and disables SSH password authentication outright - Enables
unattended-upgradesso security patches land automatically — with conditional auto-reboot at 04:00 UTC on days a reboot is actually required (a globally-quiet window, typically once every week or two when a kernel lands) - Kicks off a full
apt upgradein the background (your VPN works during it) - Generates your client config locally on your machine — the private key never touches the server
- Drops a
.conffile and an SVG QR code in your working directory, filenames tagged with the server IP and creation time so nothing silently overwrites anything
Total time typically lands between 60 and 90 seconds.
Adding More Devices
Want your VPN on your phone too? After setup, run:
fourdollarvpn add-client --name phone --open-qr
A QR code pops up in your browser. Open the WireGuard app on your phone, scan, done. The new peer is added to the live WireGuard interface without a restart — existing clients stay connected.
The --name flag is new in v1.0.10 and optional. If you pass one, it's stored as a comment above the peer block on the server (WireGuard ignores comments, so every machine managing the droplet sees the same names). It shows up in fourdollarvpn list-clients, and fourdollarvpn remove-client phone revokes it directly — no more guessing which opaque public-key prefix is the old phone you want to kill. The generated filename also carries the name, so fourdollarvpn-client-phone-10-66-66-3-14220417.conf is self-explanatory when you come back to it three months later.
You can have up to 253 clients per server. Each one gets its own keypair generated locally, so compromising one device doesn't compromise the rest.
Don't reuse the same .conf file on two devices at once. WireGuard will peer-roam to whichever device sent a packet most recently and traffic will flip-flop between them. add-client takes ten seconds — just run it again.
The Security Story
This is where I spent the most time. A VPN you can set up in 90 seconds is only useful if it's actually secure.
Cryptography you can't misconfigure
WireGuard's crypto is fixed and modern — Curve25519, ChaCha20-Poly1305, BLAKE2s. There are no cipher suites to misconfigure because there are no cipher suites to choose.
Strict key separation
Three different kinds of secret, three different lifecycles:
- DigitalOcean API token. Used only against the DO API. If you run
fourdollarvpn init, it's saved to~/.config/fourdollarvpn/config.jsonon Linux/macOS or%LOCALAPPDATA%\fourdollarvpn\config.jsonon Windows, with0600perms. On Windows, that path is deliberately not%APPDATA%— Roaming AppData is OneDrive-KFM-synced, and silently uploading a DO token to Microsoft is precisely the problem this tool is supposed to solve. If you'd rather not persist the token at all, skipinitand pass it as an env var or flag. Either way, the token never reaches the WireGuard server itself. - SSH management key. Generated per-droplet during
setup. The public half goes into DigitalOcean just long enough for droplet creation (DO copies it into/root/.ssh/authorized_keysat boot), then gets deleted from your DO account. The private half is saved locally, keyed by droplet ID rather than IP — so a future droplet that lands on a recycled IP can't impersonate the one you set up. That file is the only thing on earth that can authenticate to your server. - VPN keys. Client private key is generated on your machine and never leaves it. Only the public key goes to the server. The server's private key is generated on the server and never leaves either — its public half is derived via
wg pubkeyreading stdin, so the private key never appears in a process argv.
Hardened before any port is exposed
Password authentication is disabled across the board. Root SSH is restricted to key-only (PermitRootLogin prohibit-password). fail2ban rate-limits SSH (5 failures = 1-hour ban) on top of UFW's built-in connection rate limiter. UFW blocks everything except SSH and WireGuard. Kernel hardening (reverse-path filtering, SYN cookies, disabled ICMP redirects, disabled source routing, disabled IPv6, martian-packet logging) is applied via /etc/sysctl.d/ before setup declares victory. WireGuard does not log traffic by design — there's nothing to disable.
Want to go further? Pass --lock during setup to firewall-block SSH entirely after provisioning. The server becomes a black box that does exactly one thing: route encrypted packets. Heads up — this also prevents add-client and check from working, so add all the devices you need first. DigitalOcean's web console (a browser-based VNC, not SSH) still works for emergency recovery.
What About DNS Leaks?
Every client config ships with Cloudflare DNS (1.1.1.1, 1.0.0.1) baked in, and AllowedIPs = 0.0.0.0/0 routes all IPv4 traffic through the tunnel. IPv6 is deliberately not tunneled: the droplet is provisioned with ipv6=false and the kernel has disable_ipv6=1, so any IPv6 traffic on your device stays on your local interface rather than silently blackholing inside the tunnel. Combine that with the WireGuard app's built-in kill switch (Windows, macOS, iOS, and Android all have one) and you get full-tunnel protection that fails closed. If your network is IPv6-only, enable the kill switch — it'll block clear IPv6 rather than fall back to unprotected.
On Linux there's no app-level switch, but a single iptables rule achieves the same thing — full docs are in the repo.
Other Useful Commands
fourdollarvpn status # list your active FourDollarVPN servers
fourdollarvpn check # SSH in and verify everything is healthy
fourdollarvpn destroy # tear it down and stop billing
fourdollarvpn check is the one I use most after the initial setup — it shows ✓/× for each service, the latest WireGuard handshake (so you can confirm a remote client is actually connecting), the firewall state, and whether the background upgrade has finished.
fourdollarvpn destroy gives you an interactive picker if you don't pass a droplet ID, which matters more than it sounds — nobody wants to memorize droplet IDs at 11pm when they're trying to stop a bill.
Why a Personal VPN Beats a Commercial One
A personal VPN inverts the trust model:
- You own the logs. WireGuard doesn't write them, and nobody can subpoena, sell, or leak what doesn't exist. There is no dashboard, no analytics pipeline, no billing system correlating your traffic to your identity.
- You own the server. One user, one droplet. No shared infrastructure means no blast radius from someone else's compromise. If your server ever gets popped, the damage is bounded to you — and you can
fourdollarvpn destroyand rebuild in 90 seconds. - You own the jurisdiction. You pick the DigitalOcean region when you run
setup. No hidden parent company in a country you've never heard of, no mystery board of directors, no quiet change of ownership in a press release you'll never read. - Your IP isn't on "known commercial VPN" blocklists. Most sites that block VPNs (banks, paywalled news, Reddit-style rate-limits, fraud-detection walls) target commercial VPN IP ranges specifically — they pull reputation lists that tag "this IP belongs to NordVPN" and block that. A random DigitalOcean IP doesn't show up on those lists. A dedicated IP also means whatever someone else did yesterday can't wreck your reputation today.
Worth being honest about the limit: streaming services (Netflix, Disney+, BBC iPlayer) block nearly all datacenter IPs regardless of source. A personal DO droplet doesn't get you around those. But for the 80% of "blocked on commercial VPN" cases that aren't streaming, self-hosted on DO usually just works where a commercial provider wouldn't.
The downside has always been the setup friction. FourDollarVPN is my attempt to remove that friction without cutting any corners on hardening.
Some Nice-to-Haves Added Along the Way
A few quality-of-life things that shipped between v1.0.0 and v1.0.11 worth calling out:
- Guided menu for no-argument launches. Double-click the Windows .exe (or just run
fourdollarvpnbare) and you get a five-option menu instead of a help screen. Non-CLI users can reach the full feature set without knowing the subcommand names. Options that need SSH access to the droplet check for the local management key first and politely refuse rather than dead-ending with a cryptic error. - Stale-config sweep.
setupandadd-clientscan the working directory (and your home folder) forfourdollarvpn-client-*.conffiles pointing at droplets DO no longer has, and offer to delete them (with matching .svg QR codes). Reduces the compounding clutter problem of "ten half-remembered configs for servers that don't exist anymore." - Conditional auto-reboot. The server reboots itself at 04:00 UTC only on days where
/var/run/reboot-requiredexists — so kernel and glibc updates actually take effect without needing to remember to reboot, and you don't pay the downtime tax on days where nothing needed one. - Uninstall command.
fourdollarvpn uninstallwipes the saved token, known_hosts, and per-droplet keys from your laptop. It'll warn you if you still have droplets running so you don't orphan a paid server.
Once your VPN is running, you don't need the DigitalOcean API token anymore. Revoke it. Or, if you want to keep management access, create a second read-only token for fourdollarvpn status and only use a full-access token when you're actually provisioning.
Try It
You need a DigitalOcean account and an API token. Then grab the prebuilt binary for your OS from the latest release — Windows x64, macOS Apple Silicon, macOS Intel, and Linux x64 are all covered, no Python needed.
The binaries aren't code-signed yet (that's on the roadmap, but the certificates cost real money). Your OS will warn you the first time you run one. That's cosmetic, not a security problem — the binary is exactly what shipped from the GitHub Actions workflow, and you can verify it with the SHA checksums on the release page if you want. To bypass the warning: on Windows, SmartScreen shows "Windows protected your PC" — click More info, then Run anyway. On macOS, the first launch fails silently; right-click the binary in Finder and pick Open, then click Open on the confirmation dialog. After the first run both OSes remember your choice. Linux doesn't prompt.
Prefer to install from source?
pipx install git+https://github.com/SkyzFallin/FourDollarVPN.git@v1.0.11
fourdollarvpn init # save your token once
fourdollarvpn setup # ~90 seconds later you're done
If fourdollarvpn: command not found after installing from source — Python's Scripts/ (Windows) or bin/ (macOS/Linux) directory isn't on your PATH. Every command in this post also works as python -m fourdollarvpn ... with identical behavior. So fourdollarvpn setup becomes python -m fourdollarvpn setup. Prebuilt-binary users don't hit this because the binary is invoked directly.
"Stop renting privacy from people you don't know. Own the server, own the keys, own the silence."
Source code, full docs, and the CLI reference live at github.com/SkyzFallin/FourDollarVPN. MIT licensed. If you hit a bug or want a feature, open an issue — I read every one.