Egress through a separate exit node
Route internet traffic from some clients through another Linux client's physical WAN without making the Qeli server the exit point.
Consumer → server → exit client → internet
The server forwards packets between clients in the profile. The exit client applies source NAT and sends the packets through its physical WAN. Replies return along the same path.
| Role | Key setting | Purpose |
|---|---|---|
| Qeli server | routing.client_to_client=true | Allows forwarding between clients |
| Exit client | gateway=false + exit_node=true | Sends tunnel traffic out through its WAN |
| Consumer client | gateway=true | Sends public IPv4 traffic into Qeli |
gateway_nat brings a LAN behind a client into the tunnel, while exit_node sends traffic from the tunnel out through the client's physical WAN.Server and two-client configuration
The exit node must be a separate Linux client. It stays in split-tunnel mode, otherwise its own default route may loop through Qeli.
routing.client_to_client = true
# user used by the exit client
[user:exit]
profiles = main
client_subnet = 0.0.0.0/0
# regular consumer user; route=0/0 is not needed here
[user:consumer]
profiles = main
gateway = false
exit_node = true
gateway = true
kill_switch = true
0.0.0.0/0 as the switch. The shared client core filters overly broad pushed prefixes. Full tunnel is selected locally with gateway=true; client_subnet=0.0.0.0/0 on the exit user serves a different purpose: registering the path on the server.exit_node=true and gateway=true, Qeli logs a warning but continues startup. The WAN path is then lost, so forwarding fails; fix the configuration before starting.What Qeli configures on the exit client
On connection Qeli enables forwarding, relaxes reverse-path filtering on TUN/WAN and creates tagged rules. The WAN is selected from the lowest-metric default route, with the route to 1.1.1.1 as a fallback.
| Layer | Action |
|---|---|
| sysctl | net.ipv4.ip_forward=1 and rp_filter=0 on TUN and WAN |
| mangle | Marks TUN → WAN packets |
| nat | Source-address translation (MASQUERADE) only for marked packets leaving through the WAN |
| filter | Allows FORWARD in both directions and installs TCPMSS clamping |
Rules are idempotent, persist across reconnects and are removed on a clean client stop. Every rule has the qeli-exit-node comment.
Verify the path and NAT
journalctl -u qeli-client -b | grep 'Exit-node engaged'confirms that exit mode is activecurl -s https://api.ipify.org ; echoon the consumer, should show the exit node's public IPsudo iptables -t nat -L POSTROUTING -v -n | grep MASQUERADEcounters should grow with consumer trafficsudo iptables -t mangle -S | grep qeli-exit-nodeshows packet-marking rulessudo iptables -S | grep qeli-exit-nodeshows FORWARD and TCPMSS rulesRemove only Qeli-tagged rules
After a crash the process cannot run cleanup. First list rules with the qeli-exit-node comment, then replace -A with -D for each exact rule and run it in the same table. Do not flush entire chains.
sudo iptables -t mangle -S | grep qeli-exit-node
sudo iptables -t nat -S | grep qeli-exit-node
sudo iptables -S | grep qeli-exit-node
net.ipv4.ip_forward=0 and the previous rp_filter value only if they were actually different before Qeli; the host may serve other routing roles.Platform, cost and responsibility
| Exit platform | A Linux client with iptables and network privileges only; consumers may use any current client |
|---|---|
| Path | The extra network hop increases latency and consumes bandwidth on both the server and exit node |
| Public IP | External services see the exit node's address; its owner is responsible for outgoing traffic |
| The server itself | To egress through the server's public IP, use normal full tunnel and server NAT; exit_node is unnecessary |