Skip to content

TUN Mode (Full-Tunnel VPN)

TUN mode provides a full-tunnel VPN experience where all client traffic is routed through the server. This differs from SOCKS5 relay mode, which requires per-application SOCKS5 configuration.


TUN Mode vs SOCKS5 Mode

Feature TUN Mode SOCKS5 Mode
Traffic routing Full tunnel, all apps Per-app, requires SOCKS5 config
Setup complexity Server-side NAT config Client-side app configuration
Performance Kernel-level packet handling Application-level relay
Use case Complete privacy, all traffic App-specific tunneling

In TUN mode, the client creates a virtual TUN interface and routes all traffic through it. The server receives these packets and NATs them to the internet, similar to a traditional VPN.


NAT Configuration Requirements

TUN mode requires the server to act as a NAT gateway for client traffic. The server must have IP forwarding enabled and proper NAT rules configured.

Linux

Enable IP forwarding:

# Temporary (resets on reboot)
sudo sysctl -w net.ipv4.ip_forward=1

# Permanent
echo "net.ipv4.ip_forward = 1" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

Configure NAT with iptables:

# Assuming your public interface is eth0
sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
sudo iptables -A FORWARD -i tun0 -o eth0 -j ACCEPT
sudo iptables -A FORWARD -i eth0 -o tun0 -m state --state RELATED,ESTABLISHED -j ACCEPT

Using nftables instead:

sudo nft add table ip nat
sudo nft add chain ip nat postrouting { type nat hook postrouting priority 100 \; }
sudo nft add rule ip nat postrouting oifname "eth0" masquerade
sudo nft add chain ip filter forward { type filter hook forward priority 0 \; }
sudo nft add rule ip filter forward iifname "tun0" oifname "eth0" accept
sudo nft add rule ip filter forward iifname "eth0" oifname "tun0" ct state related,established accept

Replace eth0 with your actual network interface name (ip addr or ip link to check).

macOS

macOS does not support server-side TUN mode natively. For macOS servers, use SOCKS5 mode or run rvpn-server inside a FreeBSD/Linux VM with proper NAT configuration.

FreeBSD

Enable IP forwarding:

# Temporary
sudo sysctl -w net.inet.ip.forwarding=1

# Permanent in /etc/rc.conf
echo 'gateway_enable="YES"' | sudo tee -a /etc/rc.conf

Configure NAT with ipfw:

sudo sysctl -w net.inet.ip.fw.enable=1
sudo natd -s -m -u -dynamic -i nat0

# Or using ipfw rules directly
sudo ipfw add 100 nat 1 all from any to any via tun0

For a full ipfw/natd setup, add to /etc/rc.conf:

firewall_enable="YES"
firewall_type="OPEN"
natd_enable="YES"
natd_interface="vtnet0"  # your public interface

Server Configuration for TUN Mode

[server]
bind_address      = "0.0.0.0:443"
tls_cert_file     = "/etc/letsencrypt/live/your-domain.com/fullchain.pem"
tls_key_file      = "/etc/letsencrypt/live/your-domain.com/privkey.pem"
identity_key_file = "/etc/rvpn/server_identity.key"
websocket_path    = "/api/v1/ws"

[server.network]
nat_enabled = true
dhcp_range  = "10.200.0.0/24"
dns_servers = ["1.1.1.1", "8.8.8.8"]

Key settings for TUN mode:

  • websocket_path — Must be /api/v1/ws for TUN mode clients to reach the TUN endpoint at /api/v1/ws/tun
  • nat_enabled — Enables server-side NAT for client traffic
  • dhcp_range — IP range assigned to connected clients
  • dns_servers — DNS servers handed to clients via DHCP

Running the Server in TUN Mode

Direct Execution

sudo rvpn-server -c /etc/rvpn/server.toml

As a systemd Service

The service runs the same binary regardless of mode. Ensure server.toml has TUN-mode settings as shown above.

sudo systemctl restart rvpn-server

Verification Steps

Check server logs:

sudo journalctl -u rvpn-server -f

Look for entries showing the WebSocket path and TUN handler:

INFO  rvpn_server: Listening on 0.0.0.0:443
INFO  rvpn_server: WebSocket path: /api/v1/ws
INFO  rvpn_server: TUN mode enabled

Verify NAT rules are active (Linux):

sudo iptables -t nat -L POSTROUTING -v
sudo iptables -L FORWARD -v

Test connectivity:

Connect a client in TUN mode and verify: 1. Client receives an IP in the dhcp_range (e.g., 10.200.0.x) 2. Client can ping external IPs (e.g., 8.8.8.8) 3. Client DNS queries resolve correctly

Check active connections on server:

sudo ss -tlnp | grep 443
sudo ip addr show tun0  # if interface exists

Troubleshooting

Client Cannot Connect

  • Verify port 443 is open in firewall
  • Check websocket_path is /api/v1/ws (clients append /tun automatically)
  • Review server logs for TLS or WebSocket upgrade errors

Traffic Flows Out But Nothing Returns

  • Verify IP forwarding is enabled: sysctl net.ipv4.ip_forward
  • Check NAT rules: iptables -t nat -L POSTROUTING
  • Ensure the server's security group/firewall allows outbound traffic on all ports

No Internet Access on Client

  • Confirm nat_enabled = true in server.toml
  • Verify DHCP range does not conflict with existing networks
  • Check that dns_servers are reachable from the server

TUN Interface on Server

The server creates a real TUN interface (e.g., tun0 with IP 10.200.0.1) when TUN mode is enabled. This provides true TUN-to-TUN tunneling:

Component Description
Server TUN tun0 with IP 10.200.0.1/24
Client TUN Virtual interface with IP from 10.200.0.x
Routing Kernel routes packets through TUN interface

The server's TUN interface handles: - Writing packets received from clients to the kernel - Reading response packets from the kernel - Forwarding responses back to the appropriate client


Reverse Proxy Considerations

When running behind a reverse proxy (Caddy, nginx, HAProxy), ensure the proxy forwards /api/v1/ws/tun to the server. The proxy configuration for TUN mode is identical to SOCKS5 mode — both use the same WebSocket base path.

See Reverse Proxy Setup for complete proxy configurations.


Quick Reference

Item Value
WebSocket path /api/v1/ws
TUN endpoint /api/v1/ws/tun
Default port 443
DHCP range default 10.200.0.0/24
NAT required Yes