Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

EasyPN

Tiny Linux VPN. One TUN device, one TLS stream, one small frame format.

EasyPN is built for people who want a private network that is easy to inspect, easy to run, and hard to leave messy after it exits. It supports IPv4, IPv6, mTLS, PSK authentication, route cleanup, DNS leak protection, NAT/NAT66, MSS clamping, structured logs, and network namespace integration tests — without a large dependency stack or a custom crypto layer.

IP packet from TUN -> 2 byte length -> TLS HTTP/2 stream -> TUN

That is the protocol. Everything else is careful Linux plumbing.

Highlights

  • Small protocol: uint16 length + raw TUN packet
  • Secure transport: TLS 1.3, optional mTLS, mandatory strong PSK
  • IPv4 + IPv6: same tunnel, same frame, separate Linux routes
  • Clean exit: routes, DNS, NAT, NAT66, MSS and sysctl changes are rolled back
  • DNS control: opt-in systemd-resolved per-link DNS for route-all mode
  • MSS handling: TCPMSS clamp-to-PMTU for forwarded traffic
  • Safe defaults: no proxy-from-env unless explicitly enabled, no weak PSK
  • Real tests: Linux network namespace integration suite
  • No Go dependencies: standard library only
  • MIT licensed: small project, friendly license

Status

EasyPN is a minimal production candidate for small self-hosted deployments. It is not trying to replace WireGuard, become a VPN platform, or manage many clients. The goal is narrower: a readable, testable, single-client private link that behaves predictably on Linux.

Build

make test
make build

Binaries appear in bin/:

./bin/easypn-server -version
./bin/easypn-client -version

Build metadata can be embedded at compile time:

make build VERSION=0.1.0 COMMIT=$(git rev-parse --short HEAD)

Certificates

Generate a local CA plus server/client certificates:

./scripts/gen-certs.sh certs

The script refuses to overwrite existing keys. To regenerate deliberately:

EASYPN_CERT_FORCE=1 ./scripts/gen-certs.sh certs

For a real server name or IP:

EASYPN_CERT_SERVER_NAME=vpn.example.com \
EASYPN_CERT_SERVER_IP=203.0.113.10 \
EASYPN_CERT_CLIENT_NAME=laptop \
./scripts/gen-certs.sh certs

Files created:

certs/ca.crt
certs/ca.key
certs/server.crt
certs/server.key
certs/client.crt
certs/client.key

Keep ca.key private. Copy only the needed cert/key files to each machine.

Quick run

Use a long random PSK. EasyPN rejects PSKs shorter than 32 characters. Prefer an environment variable; command-line arguments can be visible in process lists.

export EASYPN_PSK='replace-with-at-least-32-random-characters'

Start the server:

sudo -E ./bin/easypn-server \
  -listen :443 \
  -cert certs/server.crt \
  -key certs/server.key \
  -client-ca certs/ca.crt \
  -nat=true

Start the client:

sudo -E ./bin/easypn-client \
  -server vpn.example.com \
  -ca certs/ca.crt \
  -cert certs/client.crt \
  -key certs/client.key \
  -route-all

-server accepts either a host or the full stream URL:

vpn.example.com
https://vpn.example.com/api/v1/stream

DNS leak protection

EasyPN does not change DNS silently. For full-tunnel mode, pass DNS servers explicitly:

sudo -E ./bin/easypn-client \
  -server vpn.example.com \
  -ca certs/ca.crt \
  -cert certs/client.crt \
  -key certs/client.key \
  -route-all \
  -dns 1.1.1.1,9.9.9.9 \
  -dns6 2606:4700:4700::1111

This uses resolvectl to bind DNS to the TUN interface and reverts it on exit. DNS options require -route-all.

MTU and MSS

Default MTU is 1400:

-mtu 1400

For difficult networks, use the conservative fallback:

-mtu 1280

The server enables MSS clamping by default:

-mss-clamp=true

It adds cleanup-tracked TCPMSS --clamp-mss-to-pmtu rules for forwarded TCP traffic leaving the EasyPN TUN interface.

Useful flags

Server:

-listen :443
-tun easypn0
-tun-addr 10.0.0.1/24
-tun-addr6 fd00:4550::1/64
-mtu 1400
-cert server.crt
-key server.key
-client-ca ca.crt
-nat=true
-nat6=false
-mss-clamp=true
-out-iface eth0
-version

Client:

-server vpn.example.com
-tun easypn0
-tun-addr 10.0.0.2/24
-tun-addr6 fd00:4550::2/64
-mtu 1400
-ca ca.crt
-cert client.crt
-key client.key
-route-all
-dns 1.1.1.1,9.9.9.9
-dns6 2606:4700:4700::1111
-insecure-skip-verify
-proxy-from-env=false
-version

Logs

Logs are single-line key=value records:

ts=2026-07-08T20:26:41Z level=info component=server event=server_ready listen=:443 tun=easypn0 mtu=1400 nat=true nat6=false
ts=2026-07-08T20:26:42Z level=info component=client event=tunnel_established server_version=1

They are readable in a terminal and friendly to journald, grep, Loki, Vector, or other collectors.

Tests

Fast checks:

make test

Real tunnel tests:

sudo make integration-test

The integration suite creates temporary Linux network namespaces, veth links, certificates, server/client processes, and checks IPv4, IPv6, mTLS, wrong PSK rejection, route cleanup, NAT/NAT66 cleanup, MSS cleanup, and the audit-critical stream path.

Release

make release VERSION=0.1.0 COMMIT=$(git rev-parse --short HEAD)
cat dist/SHA256SUMS

The release archive contains:

bin/easypn-server
bin/easypn-client
README.md
LICENSE
go.mod
scripts/gen-certs.sh

What is still missing

The short list before a stronger production label:

/healthz and /metrics
heartbeat / idle stream watchdog
systemd units with hardening

License

MIT. See LICENSE.

About

A small, self-hosted TUN VPN with IPv4/IPv6, mTLS, cleanup-safe routing, and a deliberately tiny packet protocol.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages