Skip to content

romant094/splitgate

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

193 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

RPi VPN Gateway

Raspberry Pi 4 configured as a split-tunnel VPN gateway — non-RU traffic exits via AmneziaWG VPN, Russian IP ranges exit direct via ISP, transparent to all LAN devices.

Документация на русском | Technical Reference


What This Does

The RPi acts as the default gateway for all LAN devices. Traffic is split into two paths:

  • Non-RU traffic exits through the AmneziaWG VPN tunnel (awg0)
  • Russian IP ranges (updated daily from russia.iplist.opencck.org) exit direct via ISP
  • LAN devices require no individual configuration — the split is fully transparent
Internet
  ↓
Router (192.168.1.1) — ISP uplink
  ↓ eth0
RPi4 (192.168.1.254) — VPN gateway
  ↓
LAN devices (default gateway = 192.168.1.254 via router DHCP)

Non-RU → awg0 → AmneziaWG VPN (endpoint: <VPN_SERVER_IP>:<port>)
RU CIDRs → eth0 → ISP direct (via 192.168.1.1)

Deploy

1. SSH alias

Add to ~/.ssh/config on your Mac:

Host pi4
    HostName 192.168.1.254
    User ar
    IdentityFile ~/.ssh/id_ed25519

Verify: ssh pi4 "echo ok" — must succeed without a password prompt.

2. Configure

VPN keys (.env.secrets):

cp .env.secrets.example .env.secrets
# Fill in AWG_PRIVATE_KEY, AWG_PUBLIC_KEY, AWG_PRESHARED_KEY (44-char base64 each)

AmneziaWG config template (src/configs/amnezia.key.template.txt): holds server-specific obfuscation parameters (Jc, Jmin, Jmax, S1, S2, H1–H4) and the endpoint. Copy the [Interface] and [Peer] blocks from your AmneziaWG server's client config, then replace the key values with {{PrivateKey}}, {{PublicKey}}, {{PresharedKey}} placeholders — deploy.sh substitutes them at deploy time.

Network config (.env): committed to the repo, safe to edit. Update if your network differs from defaults:

SSH_HOST="pi4"              # SSH alias for the RPi (from ~/.ssh/config)
RPI_LAN_IP=192.168.1.254    # RPi LAN IP
KEENETIC_GW=192.168.1.1     # ISP gateway (your router)
VPN_SERVER_IP=<your-server-ip>  # AmneziaWG server IP — set in .env.secrets
CRON_UPDATE_HOUR=5          # Hour (0–23) for daily RU list refresh

Optional — ISP-bypass custom routes (src/configs/isp-routes-custom.txt): CIDRs that bypass VPN and exit via ISP, added on top of the auto-downloaded RU list. Create from example when needed:

cp src/configs/isp-routes-custom.txt.example src/configs/isp-routes-custom.txt

Optional — VPN-force custom routes (src/configs/vpn-routes-custom.txt): CIDRs forced through VPN even if present in the auto-downloaded RU list. Highest-priority override. Create from example when needed:

cp src/configs/vpn-routes-custom.txt.example src/configs/vpn-routes-custom.txt

After editing either custom-route file, use bash src/deploy-routes.sh instead of a full bash src/deploy.sh. It SCPs only the two custom-route files and runs routing.sh --no-update — skipping AmneziaWG install, key validation, and systemd setup. Takes seconds instead of minutes.

Optional — RU list exclusions (src/configs/ru-list-exclude.txt): CIDRs to strip from the downloaded RU list server-side (use when the RU list incorrectly includes a range you want tunneled). Create from example when needed:

cp src/configs/ru-list-exclude.txt.example src/configs/ru-list-exclude.txt

All three files are gitignored. Full workflow: docs/REFERENCE.md.

3. Router setup (Keenetic)

Gateway — set RPi as the LAN default gateway:

  1. http://192.168.1.1 → Home network → Segments → Default → IP parameters
  2. Set Gateway address to 192.168.1.254 → Save
  3. LAN devices apply on next DHCP renewal (or disconnect/reconnect Wi-Fi)

DNS — required for domain names in splitgate status:

  1. Home network → Segments → Default → DNS server → set to 192.168.1.254 → Save

Rollback: clear Gateway address in router (set back to 192.168.1.1).

4. Run deploy

bash src/deploy.sh            # deploy all files + activate routing
bash src/deploy.sh --no-run   # deploy files only (use before tunnel is up)
bash src/deploy-routes.sh     # fast push of custom-route files only (after editing isp-routes-custom.txt or vpn-routes-custom.txt)

5. Bring up the tunnel

ssh pi4 "sudo awg-quick up awg0"   # bring up VPN tunnel (manual — not idempotent)
ssh pi4 "sudo awg show"            # verify peer handshake

Commands

Run on RPi via SSH. splitgate is the dispatcher CLI at /usr/local/bin/splitgate.

Command What it does
splitgate status Recent connections with VPN/ISP routing and org info
splitgate watch Real-time traffic stream
splitgate rollback Undo VPN gateway entirely
splitgate routing Rebuild split-tunnel routes
splitgate update Refresh RU IP list now
# Show recent connections
ssh pi4 "splitgate status"
ssh pi4 "splitgate status --via=vpn --last=100"
ssh pi4 "splitgate status --summary"                        # top-20 orgs by connection count

# Watch real-time traffic
ssh pi4 "splitgate watch"
ssh pi4 "splitgate watch --src 192.168.1.x --tag VPN"

# Rollback
ssh pi4 "splitgate rollback"

Full CLI reference, verify routing, troubleshooting →


Route Monitoring Daemon

splitgate-watch.service runs watch-routes.py --daemon as a persistent systemd service, writing connection logs to /etc/splitgate/logs/watch-YYYY-MM-DD.log (a new file each day, 14-day rotation). Deployed by deploy.sh Stage 28.

# Service control
ssh pi4 "systemctl status splitgate-watch"
ssh pi4 "sudo systemctl restart splitgate-watch"

# Check today's log
ssh pi4 "tail -f /etc/splitgate/logs/watch-$(date +%F).log"

# Find ISP routes that failed to connect (✗ = not found in conntrack)
ssh pi4 "grep '[ISP] ✗' /etc/splitgate/logs/watch-$(date +%F).log"

Each log line shows routing tag, connection status, source/destination, protocol:port, and org:

2026-05-29T10:14:00 [ISP] ✓ 192.168.1.237 → yandex.ru TCP:443 | TELETECH, RU
2026-05-29T10:14:05 [ISP] ✗ 192.168.1.237 → github.com TCP:443 | FASTLY, US

= connection found in conntrack (ESTABLISHED/TIME_WAIT); = not found (UDP connections always show ).

Tuning workflow — if [ISP] ✗ lines point to RU CIDRs going via ISP that actually should go via VPN, uncomment the candidate block in src/configs/vpn-routes-custom.txt and re-run routing.sh.


Log Files

File Location on RPi Purpose
install.log /etc/splitgate/logs/install.log Output from routing.sh and update-vpn-routes — download source, excluded CIDRs, route counts
watch-YYYY-MM-DD.log /etc/splitgate/logs/watch-2026-05-29.log Daily connection log written by splitgate-watch.service in daemon mode
watch-error.log /etc/splitgate/logs/watch-error.log stderr from watch-routes.py --daemon (startup errors, Python exceptions)
# View install/routing log
ssh pi4 "sudo tail -20 /etc/splitgate/logs/install.log"
ssh pi4 "sudo grep vpn-routes /etc/splitgate/logs/install.log | tail -10"

# View today's watch log
ssh pi4 "sudo tail -f /etc/splitgate/logs/watch-$(date +%F).log"

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors