# Implementation Plan ## Prerequisites - SSH access to both VDS servers (RU: 176.124.216.197, DE: 194.31.173.178) - Root or sudo privileges on both servers - Basic firewall rules allowing SSH access --- ## Phase 1: DE VDS Setup (Exit Node) The simpler node - just accepts traffic from RU VDS and NATs it to the internet. ### Step 1.1: Install packages ```bash apt update && apt install -y wireguard nftables ``` ### Step 1.2: Enable IP forwarding ```bash echo 'net.ipv4.ip_forward = 1' >> /etc/sysctl.d/99-vpn.conf sysctl -p /etc/sysctl.d/99-vpn.conf ``` ### Step 1.3: Generate WireGuard keys ```bash mkdir -p /etc/wireguard/keys chmod 700 /etc/wireguard/keys wg genkey | tee /etc/wireguard/keys/server.key | wg pubkey > /etc/wireguard/keys/server.pub chmod 600 /etc/wireguard/keys/* ``` ### Step 1.4: Create WireGuard config Create `/etc/wireguard/wg0.conf`: ```ini [Interface] Address = 10.20.0.2/30 ListenPort = 51821 PrivateKey = PostUp = nft -f /etc/nftables.conf PostDown = nft flush ruleset [Peer] # RU VDS PublicKey = AllowedIPs = 10.20.0.1/32, 10.10.0.0/24 ``` ### Step 1.5: Configure nftables Create `/etc/nftables.conf`: ```nft #!/usr/sbin/nft -f flush ruleset table inet filter { chain input { type filter hook input priority 0; policy drop; # Allow established connections ct state established,related accept # Allow loopback iif lo accept # Allow SSH (adjust port if needed) tcp dport 22 accept # Allow WireGuard from RU VDS only ip saddr 176.124.216.197 udp dport 51821 accept # Allow ICMP icmp type echo-request accept } chain forward { type filter hook forward priority 0; policy drop; # Allow forwarding from VPN iifname "wg0" accept # Allow established connections back ct state established,related accept } chain output { type filter hook output priority 0; policy accept; } } table inet nat { chain postrouting { type nat hook postrouting priority 100; # NAT traffic from VPN to internet oifname != "wg0" ip saddr { 10.10.0.0/24, 10.20.0.0/30 } masquerade } } ``` ### Step 1.6: Enable and start services ```bash systemctl enable --now nftables systemctl enable --now wg-quick@wg0 ``` ### Step 1.7: Verify ```bash wg show ip addr show wg0 ``` --- ## Phase 2: RU VDS Setup (Gateway) The main node - handles user connections, IP-based routing decisions. ### Step 2.1: Install packages ```bash apt update && apt install -y wireguard dnsmasq nftables qrencode curl bc ``` ### Step 2.2: Enable IP forwarding ```bash echo 'net.ipv4.ip_forward = 1' >> /etc/sysctl.d/99-vpn.conf sysctl -p /etc/sysctl.d/99-vpn.conf ``` ### Step 2.3: Generate WireGuard keys ```bash mkdir -p /etc/wireguard/keys chmod 700 /etc/wireguard/keys # Server key for user-facing interface wg genkey | tee /etc/wireguard/keys/server.key | wg pubkey > /etc/wireguard/keys/server.pub # Key for DE tunnel wg genkey | tee /etc/wireguard/keys/de-tunnel.key | wg pubkey > /etc/wireguard/keys/de-tunnel.pub chmod 600 /etc/wireguard/keys/* ``` ### Step 2.4: Create routing tables Add to `/etc/iproute2/rt_tables`: ``` 200 proxy ``` ### Step 2.5: Create WireGuard configs Create `/etc/wireguard/wg0.conf` (user-facing): ```ini [Interface] Address = 10.10.0.1/24 ListenPort = 51820 PrivateKey = PostUp = /etc/wireguard/postup.sh PostDown = /etc/wireguard/postdown.sh # Users will be added here as [Peer] sections ``` Create `/etc/wireguard/wg1.conf` (DE tunnel): ```ini [Interface] Address = 10.20.0.1/30 PrivateKey = [Peer] # DE VDS PublicKey = Endpoint = 194.31.173.178:51821 AllowedIPs = 0.0.0.0/0 PersistentKeepalive = 25 ``` ### Step 2.6: Create PostUp script Create `/etc/wireguard/postup.sh`: ```bash #!/bin/bash set -e # Load nftables rules (includes the 'direct' set and packet marking) nft -f /etc/nftables.conf # Add default route via DE tunnel for 'proxy' table ip route add default via 10.20.0.2 dev wg1 table proxy 2>/dev/null || true # Policy routing: packets with fwmark 0x1 use 'proxy' table ip rule add from 10.10.0.0/24 fwmark 0x1 table proxy priority 100 2>/dev/null || true echo "PostUp script completed successfully" ``` Make executable: ```bash chmod +x /etc/wireguard/postup.sh ``` ### Step 2.7: Create PostDown script Create `/etc/wireguard/postdown.sh`: ```bash #!/bin/bash # Remove policy routing rule ip rule del from 10.10.0.0/24 fwmark 0x1 table proxy priority 100 2>/dev/null || true # Flush routing table ip route flush table proxy 2>/dev/null || true # Flush nftables vpn-routing table nft flush table ip vpn-routing 2>/dev/null || true echo "PostDown script completed" ``` Make executable: ```bash chmod +x /etc/wireguard/postdown.sh ``` ### Step 2.8: Configure nftables Create `/etc/nftables.conf`: ```nft #!/usr/sbin/nft -f # # RU VDS nftables configuration # Pure nftables - no iptables/ipset dependencies # flush ruleset table inet filter { chain input { type filter hook input priority 0; policy drop; ct state established,related accept iif lo accept tcp dport 22 accept udp dport 51820 accept iifname "wg0" udp dport 53 accept iifname "wg0" tcp dport 53 accept icmp type echo-request accept } chain forward { type filter hook forward priority 0; policy drop; iifname "wg0" accept iifname "wg1" accept ct state established,related accept } chain output { type filter hook output priority 0; policy accept; } } table ip vpn-routing { # Set for Russian IPs (direct routing, no proxy) # Populated by update-direct-routes.sh script set direct { type ipv4_addr flags interval, timeout timeout 6h } # Packet marking for policy routing chain prerouting { type filter hook prerouting priority mangle; policy accept; # Only process traffic from VPN clients ip saddr != 10.10.0.0/24 return # Destinations in 'direct' set: no mark (direct routing) ip daddr @direct return # Everything else: mark for proxy routing meta mark set 0x1 } } table inet nat { chain postrouting { type nat hook postrouting priority 100; oifname != "wg0" oifname != "wg1" ip saddr 10.10.0.0/24 masquerade } } ``` ### Step 2.9: Configure dnsmasq Disable systemd-resolved if running: ```bash systemctl disable --now systemd-resolved rm /etc/resolv.conf echo "nameserver 8.8.8.8" > /etc/resolv.conf ``` Create `/etc/dnsmasq.d/vpn-routing.conf`: ```conf # dnsmasq configuration for VPN # Routing is handled by nftables based on IP ranges, not DNS # Listen only on VPN interface interface=wg0 bind-interfaces # Upstream DNS server=8.8.8.8 server=8.8.4.4 server=1.1.1.1 # Don't read /etc/resolv.conf no-resolv # Cache size cache-size=10000 ``` ### Step 2.10: Create Russian IP ranges update script Create `/etc/wireguard/update-direct-routes.sh`: ```bash #!/bin/bash # # Downloads Russian IP ranges from RIPE and loads them into nftables # Run after services are started, and weekly via cron # set -e RIPE_URL="https://ftp.ripe.net/pub/stats/ripencc/delegated-ripencc-extended-latest" TEMP_FILE="/tmp/ripe-delegated.txt" echo "Downloading RIPE delegation data..." curl -s "$RIPE_URL" -o "$TEMP_FILE" echo "Parsing Russian IP allocations..." RU_RANGES=$(grep '|RU|ipv4|' "$TEMP_FILE" | while IFS='|' read -r _ _ _ start count _ _ _; do if [[ "$count" =~ ^[0-9]+$ ]] && [ "$count" -gt 0 ]; then prefix=$(echo "32 - l($count)/l(2)" | bc -l | cut -d. -f1) echo "$start/$prefix" fi done) echo "Flushing existing 'direct' set..." nft flush set ip vpn-routing direct 2>/dev/null || true echo "Adding ranges to nftables..." echo "$RU_RANGES" | while read -r cidr; do [[ -n "$cidr" ]] && nft add element ip vpn-routing direct { "$cidr" } 2>/dev/null || true done rm -f "$TEMP_FILE" echo "Done. Russian IP ranges loaded." ``` Make executable and set up cron: ```bash chmod +x /etc/wireguard/update-direct-routes.sh # Weekly updates cat > /etc/cron.weekly/update-vpn-routes << 'EOF' #!/bin/bash /etc/wireguard/update-direct-routes.sh >> /var/log/vpn-routes-update.log 2>&1 EOF chmod +x /etc/cron.weekly/update-vpn-routes ``` ### Step 2.11: Enable and start services ```bash systemctl enable nftables dnsmasq wg-quick@wg0 wg-quick@wg1 systemctl start dnsmasq systemctl start wg-quick@wg1 systemctl start wg-quick@wg0 ``` ### Step 2.12: Load Russian IP ranges After the tunnel is up: ```bash /etc/wireguard/update-direct-routes.sh ``` ### Step 2.13: Verify ```bash wg show ip route show table proxy ip rule show nft list set ip vpn-routing direct | head -20 ``` --- ## Phase 3: Key Exchange After generating keys on both servers, exchange public keys: ### On DE VDS: ```bash cat /etc/wireguard/keys/server.pub # Copy this value ``` ### On RU VDS: ```bash cat /etc/wireguard/keys/server.pub cat /etc/wireguard/keys/de-tunnel.pub # Copy these values ``` ### Update configs: 1. **DE VDS** `/etc/wireguard/wg0.conf`: Replace `` with RU's `de-tunnel.pub` 2. **RU VDS** `/etc/wireguard/wg1.conf`: Replace `` with DE's `server.pub` ### Restart WireGuard: ```bash # On DE VDS systemctl restart wg-quick@wg0 # On RU VDS systemctl restart wg-quick@wg1 ``` ### Verify tunnel: ```bash # On RU VDS ping 10.20.0.2 wg show wg1 ``` --- ## Phase 4: Add First Client ### Step 4.1: Generate client keys (on RU VDS) ```bash CLIENT_NAME="phone" wg genkey | tee /etc/wireguard/keys/client_${CLIENT_NAME}.key | wg pubkey > /etc/wireguard/keys/client_${CLIENT_NAME}.pub chmod 600 /etc/wireguard/keys/client_${CLIENT_NAME}.* ``` ### Step 4.2: Add peer to server ```bash CLIENT_IP="10.10.0.2" CLIENT_PUBKEY=$(cat /etc/wireguard/keys/client_${CLIENT_NAME}.pub) wg set wg0 peer ${CLIENT_PUBKEY} allowed-ips ${CLIENT_IP}/32 wg-quick save wg0 ``` ### Step 4.3: Create client config ```bash CLIENT_NAME="phone" CLIENT_IP="10.10.0.2" SERVER_PUBKEY=$(cat /etc/wireguard/keys/server.pub) CLIENT_PRIVKEY=$(cat /etc/wireguard/keys/client_${CLIENT_NAME}.key) cat > /etc/wireguard/clients/${CLIENT_NAME}.conf << EOF [Interface] PrivateKey = ${CLIENT_PRIVKEY} Address = ${CLIENT_IP}/32 DNS = 10.10.0.1 [Peer] PublicKey = ${SERVER_PUBKEY} Endpoint = 176.124.216.197:51820 AllowedIPs = 0.0.0.0/0 PersistentKeepalive = 25 EOF mkdir -p /etc/wireguard/clients chmod 600 /etc/wireguard/clients/${CLIENT_NAME}.conf ``` ### Step 4.4: Transfer to client Display as QR code (for mobile): ```bash apt install -y qrencode qrencode -t ansiutf8 < /etc/wireguard/clients/${CLIENT_NAME}.conf ``` Or copy the file contents manually. --- ## Phase 5: Testing ### Test 1: Basic connectivity ```bash # From client ping 10.10.0.1 # Should work - RU VDS ping 10.20.0.2 # Should work - DE VDS ``` ### Test 2: DNS resolution ```bash # From client nslookup google.com 10.10.0.1 nslookup yandex.ru 10.10.0.1 ``` ### Test 3: Routing verification ```bash # On RU VDS - check ipset after client visits some .ru sites ipset list direct # From client - check external IP curl ifconfig.me # Should show DE VDS IP (194.31.173.178) curl ifconfig.me --resolve ifconfig.me:80:$(dig +short yandex.ru | head -1) # Won't work, but... # Better test - check where traffic goes curl https://2ip.ru # Russian service, should go direct, show RU VDS IP curl https://ifconfig.me # Should show DE VDS IP ``` ### Test 4: Check that .ru domains go direct ```bash # From client traceroute yandex.ru # Should not go through DE traceroute google.com # Should go through DE (you'll see 10.20.0.x hop) ``` --- ## Troubleshooting ### WireGuard not connecting ```bash # Check if service is running systemctl status wg-quick@wg0 # Check for errors journalctl -u wg-quick@wg0 -e # Verify port is open ss -ulnp | grep 51820 ``` ### DNS not working ```bash # Check dnsmasq systemctl status dnsmasq journalctl -u dnsmasq -e # Test locally dig @127.0.0.1 google.com ``` ### Routing not working ```bash # Check nftables set nft list set ip vpn-routing direct # Check routing table ip route show table proxy ip rule show # Check nftables rules nft list chain ip vpn-routing prerouting # Test packet marking (watch counters) nft list ruleset | grep -A5 "chain prerouting" ``` ### Traffic not NATed ```bash # Check nftables nft list ruleset # Check forwarding cat /proc/sys/net/ipv4/ip_forward ``` --- ## Summary Checklist - [ ] **DE VDS** - [ ] WireGuard installed - [ ] IP forwarding enabled - [ ] Keys generated - [ ] wg0.conf configured - [ ] nftables configured - [ ] Services enabled and started - [ ] **RU VDS** - [ ] WireGuard installed - [ ] dnsmasq installed - [ ] nftables installed - [ ] IP forwarding enabled - [ ] Keys generated - [ ] Routing table 'proxy' added - [ ] wg0.conf configured (users) - [ ] wg1.conf configured (DE tunnel) - [ ] postup.sh / postdown.sh created - [ ] nftables configured (with vpn-routing table) - [ ] dnsmasq configured - [ ] Services enabled and started - [ ] Russian IP ranges loaded (update-direct-routes.sh) - [ ] **Key Exchange** - [ ] DE public key → RU wg1.conf - [ ] RU de-tunnel public key → DE wg0.conf - [ ] Tunnel verified (ping 10.20.0.2 from RU) - [ ] **First Client** - [ ] Keys generated - [ ] Peer added to wg0 - [ ] Client config created - [ ] Connection tested - [ ] Routing verified