Skip to content

Repository files navigation

LiteVPN

Rust QUIC/TUN VPN for one Mac client and one small Oracle Ubuntu server.

Local setup

cargo run -p litevpn-keygen -- --out-dir config --server-name litevpn.local
cp config/server.example.toml config/server.toml
cp config/client.example.toml config/client.toml

Copy these to the server:

scp -i ~/.ssh/your_oci_key \
  config/server.toml config/server.crt config/server.key config/client.token \
  ubuntu@YOUR_SERVER_IP:/tmp/

Install them on the server:

ssh -i ~/.ssh/your_oci_key ubuntu@YOUR_SERVER_IP
sudo mkdir -p /etc/litevpn
sudo install -m 0644 /tmp/server.toml /etc/litevpn/server.toml
sudo install -m 0644 /tmp/server.crt /etc/litevpn/server.crt
sudo install -m 0600 /tmp/server.key /etc/litevpn/server.key
sudo install -m 0600 /tmp/client.token /etc/litevpn/client.token

Build

cargo build --release
scripts/build-server.sh

Server

HOST=ubuntu@YOUR_SERVER_IP KEY=~/.ssh/your_oci_key scripts/install-server.sh

Oracle Cloud Security List or NSG must allow the selected UDP port:

source: 0.0.0.0/0
protocol: UDP
destination port: 443

After the first install, deploy only a rebuilt server binary:

HOST=ubuntu@YOUR_SERVER_IP KEY=~/.ssh/your_oci_key scripts/deploy-server.sh

Client

./target/release/litevpn-client --config config/client.toml --probe --connect-timeout-secs 10 --connect-retries 3
sudo ./target/release/litevpn-client --config config/client.toml --connect-retries 3

Use --no-routes to test the tunnel without changing macOS routes.

On macOS the client removes stale LiteVPN split-default routes before connecting. If a previous run was killed and the next probe/client run times out, clean them manually:

sudo ./target/release/litevpn-client --config config/client.toml --cleanup-routes

If the probe times out while the server service is active, open 443/udp in the Oracle Cloud Security List or NSG for the instance subnet.

--connect-retries rebuilds the local QUIC endpoint for each attempt. This is useful after route cleanup, Wi-Fi path changes, or transient OCI path loss.

Benchmarks

./target/release/litevpn-client --config config/client.toml --bench download --bench-duration-secs 10 --bench-target-mbps 36 --bench-payload-bytes 1300 --bench-runs 3
./target/release/litevpn-client --config config/client.toml --bench upload --bench-duration-secs 10 --bench-target-mbps 13 --bench-payload-bytes 1300 --bench-runs 3

Repeated benchmark output includes local send/receive aggregate stats and parsed server-side aggregate stats. Upload server Mbps uses measured_elapsed_ms, excluding the extra drain window.

scripts/bench-sweep.sh reports both the clean candidate and the delivery-ok candidate with the highest server-observed average Mbps. For DATAGRAM benchmarks, delivery-ok means payload delivery checks passed; clean additionally requires zero client/server QUIC loss and congestion events. For stream diagnostics, delivery-ok means local and server bytes match; clean additionally requires zero client/server QUIC loss and congestion events, so retransmission-heavy runs are not mistaken for the safest target.

datagram_backlog_packets caps queued QUIC DATAGRAMs that have not reached Quinn's transmit stats yet. 64 is the selected default for this path; 0 disables the cap.

vpn_transport = "datagram" is the selected VPN data plane. vpn_transport = "stream" enables the experimental reliable QUIC stream packet mode; it is useful for diagnostics and may improve delivery under loss, but can introduce head-of-line blocking.

Switch the client and server transport mode together:

MODE=stream HOST=ubuntu@YOUR_SERVER_IP KEY=~/.ssh/your_oci_key scripts/set-vpn-transport.sh
MODE=datagram HOST=ubuntu@YOUR_SERVER_IP KEY=~/.ssh/your_oci_key scripts/set-vpn-transport.sh

By default this also applies the tested pacing presets: DATAGRAM uses client 13 Mbps and server 36 Mbps; stream uses client 40 Mbps and server 36 Mbps. Set APPLY_PRESETS=0 to change only vpn_transport.

For an interactive macOS TUN smoke test, use the wrapper below. It switches the client and server, starts the local client with sudo, and restores DATAGRAM when the client exits:

MODE=stream HOST=ubuntu@YOUR_SERVER_IP KEY=~/.ssh/your_oci_key scripts/run-tun-smoke.sh

WireGuard baseline

WireGuard is an open-source VPN protocol and implementation. In this project it is not the LiteVPN data plane; it is a practical baseline and fallback for the same MacBook, same OCI Osaka server, and same network path. Comparing against it answers: "what can this fixed hardware and route do with a mature VPN?"

WireGuard baseline files are generated under config/wireguard/, which is ignored by git because it contains private keys.

Install and configure the same OCI server as a WireGuard baseline:

HOST=ubuntu@YOUR_SERVER_IP KEY=~/.ssh/your_oci_key scripts/setup-wireguard-baseline.sh

That script:

  • generates a server keypair and a client keypair under ignored config/wireguard/
  • writes the local macOS client config to config/wireguard/wg0.conf
  • installs /etc/wireguard/wg0.conf on the OCI server
  • uses tunnel network 10.77.0.0/24
  • gives the server 10.77.0.1 and the Mac client 10.77.0.2
  • listens on UDP 443, the same public port LiteVPN uses
  • enables Linux IPv4 forwarding and NAT masquerade through ens3
  • inserts WireGuard forwarding rules before the server's catch-all REJECT

Because LiteVPN and WireGuard share UDP 443, only one server mode can be up at a time.

Run either VPN mode from macOS:

HOST=ubuntu@YOUR_SERVER_IP KEY=~/.ssh/your_oci_key scripts/run-vpn-mode.sh --mode wireguard
HOST=ubuntu@YOUR_SERVER_IP KEY=~/.ssh/your_oci_key scripts/run-vpn-mode.sh --mode litevpn
MODE=wireguard HOST=ubuntu@YOUR_SERVER_IP KEY=~/.ssh/your_oci_key scripts/run-vpn-mode.sh
MODE=litevpn HOST=ubuntu@YOUR_SERVER_IP KEY=~/.ssh/your_oci_key scripts/run-vpn-mode.sh
HOST=ubuntu@YOUR_SERVER_IP KEY=~/.ssh/your_oci_key scripts/run-vpn-mode.sh --mode off

MODE=wireguard stops the remote LiteVPN service, starts remote wg0, then starts local wg-quick and restores LiteVPN when the script exits. MODE=litevpn stops remote wg0, starts the LiteVPN service, then starts the local LiteVPN client. MODE=off stops local WireGuard/LiteVPN state, stops remote wg0, and restores the remote LiteVPN service. Both modes check local sudo before changing the remote server state.

After starting a mode, verify the public exit IP:

curl ifconfig.me

It should show the OCI public IP when full-tunnel routing is active.

With either VPN already running, compare tunnel throughput:

MODE=wireguard HOST=ubuntu@YOUR_SERVER_IP KEY=~/.ssh/your_oci_key scripts/bench-vpn-throughput.sh
MODE=litevpn HOST=ubuntu@YOUR_SERVER_IP KEY=~/.ssh/your_oci_key scripts/bench-vpn-throughput.sh

Or run both modes sequentially with one command:

scripts/compare-vpn-modes.sh --preflight
HOST=ubuntu@YOUR_SERVER_IP KEY=~/.ssh/your_oci_key scripts/compare-vpn-modes.sh --mode wireguard --mode litevpn
HOST=ubuntu@YOUR_SERVER_IP KEY=~/.ssh/your_oci_key scripts/compare-vpn-modes.sh

--preflight checks local tools, ignored WireGuard config, remote WireGuard tools/config, and the remote LiteVPN service without asking for local sudo.

To keep each VPN mode up while measuring Fast.com in Chrome, add --fastcom:

HOST=ubuntu@YOUR_SERVER_IP KEY=~/.ssh/your_oci_key scripts/compare-vpn-modes.sh --fastcom

Comparison logs are written under bench-results/vpn-compare-*. Each run also writes per-mode upload.json, download.json, ping.txt, and a combined summary.csv for quick WireGuard vs LiteVPN comparison. With FASTCOM_PAUSE=1, per-mode Fast.com note templates are written as fastcom.md beside the iperf logs.

Generate a Markdown comparison report and recommendation from the latest run:

scripts/summarize-vpn-comparison.sh

Sweep WireGuard MTU candidates before choosing the WireGuard baseline:

MTUS="1280 1380 1420" HOST=ubuntu@YOUR_SERVER_IP KEY=~/.ssh/your_oci_key scripts/sweep-wireguard-mtu.sh

Server runtime/network snapshot:

HOST=ubuntu@YOUR_SERVER_IP KEY=~/.ssh/your_oci_key scripts/server-snapshot.sh

Selected stability benchmark with before/after server snapshots:

HOST=ubuntu@YOUR_SERVER_IP KEY=~/.ssh/your_oci_key scripts/bench-selected.sh

Logs are written under bench-results/, which is intentionally ignored by git.

The performance rationale and next experiment ranking are in PERFORMANCE_THEORY.md.

The short version: WireGuard is faster because it is a small purpose-built VPN data plane with mature kernel/network-stack integration. LiteVPN currently sends TUN packets through a Rust userspace TUN loop and Quinn/QUIC DATAGRAM or stream transport, with extra copies, task wakeups, pacing, backlog accounting, and loss/latency tradeoffs. LiteVPN is the experimental implementation; WireGuard is the baseline to chase, not code we wrote.

Target sweep for comparing candidate pacing limits:

DIRECTION=download TARGETS="30 34 38 40" scripts/bench-sweep.sh
DIRECTION=upload TARGETS="10 12 13" scripts/bench-sweep.sh
DIRECTION=stream-upload TARGETS="13 20 40" scripts/bench-sweep.sh
DIRECTION=stream-download TARGETS="36 50" scripts/bench-sweep.sh
DIRECTION=stream-packet-upload TARGETS="20 40 60" scripts/bench-sweep.sh
DIRECTION=stream-packet-download TARGETS="36 40 50" scripts/bench-sweep.sh

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages