Use your VPS as a Tailscale exit node
Turn your VPS into a Tailscale exit node: install, advertise, enable IP forwarding, approve the route in the admin console, then fix DNS and IPv6.
What a Tailscale exit node does
A Tailscale exit node is a machine on your tailnet that carries all internet traffic for your other devices, and a VPS (virtual private server) makes a good one because it has a fixed public address and it stays online. Setting one up takes five steps: install Tailscale on the server, advertise the exit node, enable IP forwarding, approve the route in the admin console, then select the node on your laptop. The fourth step is a toggle in a web page and not a command, and that is where most people stall.
Once it is on, your laptop encrypts every packet and sends it to the VPS. The VPS applies source NAT (network address translation) and sends the packet on with its own public IP address. Websites see the VPS. The café Wi-Fi sees one encrypted UDP flow to the VPS and nothing else.
Tailscale is WireGuard for the data path plus a coordination server that distributes keys and helps two machines find each other through NAT. That coordination server is the reason there is no key copying anywhere below. For the trade-offs written out properly, read how Tailscale and plain WireGuard compare. If you would rather own every part of the tunnel yourself, self-host a plain WireGuard VPN on your VPS instead.
The steps below assume Tailscale already runs on your laptop, and that both machines sign in to the same tailnet. A tailnet is your private Tailscale network, and every device in it gets a stable address inside 100.64.0.0/10.
Install Tailscale on your VPS
curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale upThe install script picks the package repository for your distribution and installs the tailscaled daemon. tailscale up then prints an authentication URL. Open it in a browser and sign in with the same account your laptop uses, because a VPS signed into a different tailnet cannot serve your laptop at all.
tailscale status
tailscale ip -4tailscale status should now list both machines. tailscale ip -4 prints the VPS's tailnet address, which is what you hand to the client later.
Tailscale needs a TUN device to build the tunnel. On a KVM VPS the device is there. On plans built with container virtualisation that share the host kernel, /dev/net/tun is sometimes missing, and tailscaled cannot create the tailscale0 interface. Run ls -l /dev/net/tun before you go further.
Enable IP forwarding, or the VPS drops every packet
A Linux machine drops any packet that is not addressed to itself, because net.ipv4.ip_forward is 0 by default. The exit node would accept your traffic, decrypt it, then throw it away. Write the setting to a file so it survives a reboot.
echo 'net.ipv4.ip_forward = 1' | sudo tee -a /etc/sysctl.d/99-tailscale.conf
echo 'net.ipv6.conf.all.forwarding = 1' | sudo tee -a /etc/sysctl.d/99-tailscale.conf
sudo sysctl -p /etc/sysctl.d/99-tailscale.conftee -a appends, so running these lines a second time writes both settings twice. The result still works, and cat /etc/sysctl.d/99-tailscale.conf will look strange. Confirm the live value instead of trusting the file:
sysctl net.ipv4.ip_forwardIt must print net.ipv4.ip_forward = 1. If you skip this and use tailscale up --advertise-exit-node, the client tells you:
Warning: IP forwarding is disabled, subnet routing/exit nodes will not work.tailscale set --advertise-exit-node does not run that check, so silence from set is not proof that forwarding is on. Read the sysctl value yourself.
You do not need to write a masquerade rule by hand. tailscaled installs its own firewall chains, named ts-input, ts-forward and ts-postrouting, and the NAT rule for exit node traffic lives in ts-postrouting. Look at them with sudo iptables-save | grep ts-, or sudo nft list ruleset on an nftables box.
Advertise the VPS as an exit node
sudo tailscale set --advertise-exit-nodetailscale set changes one preference and leaves the others alone. tailscale up --advertise-exit-node advertises the node too, and it carries a side effect: up treats the flags on its command line as the complete set of non-default settings, so a later bare sudo tailscale up refuses to run and prints
changing settings via 'tailscale up' requires mentioning all
non-default flags. To proceed, either re-run your command with --reset or
use the command below to explicitly mention the current value of
all non-default settings:Use set for ongoing changes and you never meet that message.
Advertising is an offer. The VPS is now telling the coordination server that it is willing to be an exit node. No client can use it yet.
Approve the Tailscale exit node in the admin console
This is the step with no command behind it. Open the Machines page in the admin console, find the VPS, open the three dot menu at the end of its row, choose Edit route settings, and turn on Use as exit node.
Until that toggle is on, the control plane holds the offer and gives it to nobody. tailscale exit-node list on your laptop shows nothing, and your traffic keeps its normal route. There is no error message on either machine. The exit node simply never appears.
You can approve exit nodes automatically with an entry in the tailnet policy file:
"autoApprovers": {
"exitNode": ["tag:exit"],
}A device brought up with --advertise-tags=tag:exit is then approved on its own, as long as tag:exit is defined under tagOwners in the same policy file. Tagging changes ownership: a tagged device belongs to the tailnet rather than to your user account, and the access rules that apply to it change with it. For a single VPS, the toggle is simpler.
Select the exit node on your laptop
On a Linux client:
tailscale exit-node list
sudo tailscale set --exit-node=vps.your-tailnet.ts.netexit-node list prints the approved exit nodes in your tailnet with their addresses. An empty list means the approval step did not happen. On macOS, Windows, iOS and Android the same choice is a menu item under Exit Node in the Tailscale app.
Verify from the client, never from the server:
curl -4 https://ifconfig.meRun it once before you select the exit node and once after. The address must change from your local one to the VPS's public IP. To stop using the exit node:
sudo tailscale set --exit-node=One more flag matters on day one. With an exit node selected, the client sends everything into the tunnel, including packets addressed to 192.168.1.50, so your printer and your network storage stop answering. Keep the local network on the local route:
sudo tailscale set --exit-node=<name> --exit-node-allow-lan-access=trueWhy your DNS changes the moment the exit node is on
By default, a device using an exit node also uses that exit node as its DNS (domain name system) resolver for every domain, and this overrides the global and split DNS nameservers configured for your tailnet. The behaviour is deliberate. If queries kept going to the local network's resolver, the café router would still see the name of every site you visit while the traffic itself was private. Names and packets should leave from the same place.
One consequence bites people running an internal resolver: a tailnet nameserver you depend on stops being used while the exit node is on. Turn on Use with exit node for that nameserver on the DNS page of the admin console to bring it back.
MagicDNS names keep working, because the Tailscale client answers them locally at 100.100.100.100 before anything reaches the exit node. Check it with dig @100.100.100.100 your-vps.your-tailnet.ts.net, or on a systemd-resolved client with resolvectl status, where the Tailscale interface lists 100.100.100.100 as its DNS server.
If you disable Tailscale's DNS handling with --accept-dns=false, the client keeps the resolver it learned from the local network. The traffic is tunnelled and the queries are not, which is the same DNS leak that catches hand built WireGuard tunnels. Leave --accept-dns alone unless you have a specific reason to change it.
IPv6 through the exit node
An exit node advertises both default routes, 0.0.0.0/0 and ::/0. If the VPS has no working IPv6 path to the internet, IPv6 packets arrive over the tunnel and stop there. Test on the VPS before you trust it:
ip -6 addr show
curl -6 https://ifconfig.meA failed request means the VPS has no IPv6 upstream. Dual stack websites usually still load, because the client gives up on IPv6 and retries over IPv4, though that retry adds a delay on the first connection to each site. IPv6-only destinations stay unreachable.
The other half is forwarding. net.ipv4.ip_forward = 1 with net.ipv6.conf.all.forwarding left at 0 gives you a working IPv4 path and a black hole for IPv6, which the reader experiences as "some sites are slow" rather than as an error anyone can search for. Both lines belong in the sysctl file.
Should the VPS advertise subnet routes too?
An exit node carries all internet traffic. A subnet route carries one private range that sits behind the machine advertising it. They are separate features with separate approvals, and one machine can do both.
sudo tailscale set --advertise-routes=10.0.0.0/24Advertise a subnet when the VPS shares a private network with other servers you want to reach by their private addresses. Approve it in the same Edit route settings panel, on its own toggle.
Pick the range carefully. An advertised route is more specific than your laptop's default route, so advertising 192.168.1.0/24 from the VPS takes over the addresses of a home network that uses the same range, and the devices on your desk go quiet. Use a range you chose, not the range your home router chose for you.
Make the exit node fast with UDP GRO forwarding
Tailscale 1.54 and later, on a Linux 6.2 or later kernel, can use a receive offload that raises throughput for forwarded traffic. GRO (generic receive offload) merges incoming packets before the kernel processes them one by one. As of August 2026 this is still a manual step on the exit node.
sudo apt install -y ethtool
NETDEV=$(ip -o route get 8.8.8.8 | cut -f 5 -d " ")
sudo ethtool -K $NETDEV rx-udp-gro-forwarding on rx-gro-list offip -o route get 8.8.8.8 reports the interface that actually reaches the internet, so you never have to guess between eth0, ens3 and enp1s0. Confirm with ethtool -k $NETDEV | grep udp-gro-forwarding, which should now read on.
The setting is lost at reboot. On a system running networkd-dispatcher, make it automatic:
printf '#!/bin/sh\n\nethtool -K %s rx-udp-gro-forwarding on rx-gro-list off \n' "$(ip -o route get 8.8.8.8 | cut -f 5 -d " ")" | sudo tee /etc/networkd-dispatcher/routable.d/50-tailscale
sudo chmod 755 /etc/networkd-dispatcher/routable.d/50-tailscaleCheck that /etc/networkd-dispatcher/routable.d/ exists first. If it does not, the machine is not running networkd-dispatcher, and a small systemd unit that runs the ethtool line at boot does the same job.
What your provider's acceptable use policy means for exit traffic
Every packet a client sends through the exit node leaves with the VPS's public IP address, so it is attributed to your account. Abuse reports land in your inbox: copyright notices, port scan complaints. Read your provider's AUP (acceptable use policy) before you route a household or a team through one server, and do not open an exit node to people you cannot vouch for.
Bandwidth counts twice. Traffic arrives at the VPS over the tunnel and then leaves again for the internet, and both directions usually count against the transfer allowance on the plan. A video stream watched through an exit node is a bigger line item than most people expect.
Datacenter address ranges also carry a reputation. Some sites show more CAPTCHAs to them, and some streaming services refuse them outright. Nothing in your configuration changes that, because it is a property of the address block your provider owns.
Why traffic still leaves through your local connection
The exit node is advertised but not approved. tailscale exit-node list on the client prints nothing, and neither machine logs an error. Go to the Machines page and turn on Use as exit node.
The client never selected it. Approval makes the node available to the tailnet. Selection is a separate action on each device. Re-run sudo tailscale set --exit-node=<name>, then check curl -4 https://ifconfig.me again.
Forwarding is off. The symptom is specific: tailscale ping <vps> succeeds, the tunnel is clearly up, and every outside address times out. sysctl net.ipv4.ip_forward reads 0. Fix the sysctl file, then run sudo sysctl -p /etc/sysctl.d/99-tailscale.conf.
A firewall drops the forwarded packets. tailscaled inserts its own ts-forward chain, and on a clean VPS that is enough. A box already running ufw or Docker can end up with a FORWARD policy of DROP and rules ordered ahead of Tailscale's. Do not guess which one: run sudo iptables -L FORWARD -n -v while the client tries to load a page, and watch which counters move. On a ufw box the usual fix is DEFAULT_FORWARD_POLICY="ACCEPT" in /etc/default/ufw followed by sudo ufw reload. Check your provider's network firewall in the control panel as well, since that is a separate control from anything running on the server.
It works, but it is slow. Run tailscale netcheck on both machines. If it reports UDP as blocked, the two devices cannot build a direct path and fall back to a DERP relay, which adds latency to every connection. Allowing inbound UDP on port 41641 to the VPS in the provider's network firewall usually restores the direct path.
When to leave Tailscale's coordination server
Everything above depends on Tailscale's hosted coordination server for key exchange and for the approval you clicked. Your traffic still goes straight from laptop to VPS, and the coordination server never carries it, though it does decide who may join the tailnet and what each device may reach. If that dependency is the thing you want to remove, run Headscale as your own Tailscale control server and point both clients at it. The exit node steps are the same afterwards, with the route approval done through Headscale's command line instead of the hosted console.
FAQ
Why does my traffic still use my local connection after I select the exit node?
There are two common causes. The exit node was advertised but never approved: open the Machines page in the admin console, find the VPS, choose Edit route settings, and turn on Use as exit node. Approval is a console toggle, and no command on the server performs it. The second cause looks different: IP forwarding is off, so the tunnel comes up, tailscale ping to the VPS works, and every outside address times out. Check with sysctl net.ipv4.ip_forward, which must read 1.
Do I have to approve the exit node by hand every time?
The toggle is a one time action for each machine. If you rebuild the VPS often, add an autoApprovers block to your tailnet policy file containing "exitNode": ["tag:exit"], define tag:exit under tagOwners, and bring the node up with --advertise-tags=tag:exit. A tagged device is owned by the tailnet rather than by your user account, so the access rules that apply to it change too.
Which DNS server does my laptop use while an exit node is on?
The exit node itself. A device using an exit node sends all DNS queries there, and that overrides the global and split DNS nameservers set for the tailnet. It stops the local network from seeing the names you look up. To keep one tailnet nameserver applying, enable Use with exit node for it on the DNS page of the admin console. MagicDNS names still resolve, because the Tailscale client answers them locally at 100.100.100.100.
Can one VPS be an exit node and a subnet router at the same time?
Yes. sudo tailscale set --advertise-exit-node and sudo tailscale set --advertise-routes=10.0.0.0/24 are independent, and each gets its own approval toggle under Edit route settings. Both need IP forwarding enabled on the VPS. Avoid advertising a range that matches your laptop's home network, because the advertised route is more specific than the default route and your local devices become unreachable.
Does an exit node hide my traffic from my VPS provider?
No. The tunnel ends at the VPS, so traffic leaves the server in whatever form the destination expects, and your provider carries it in the clear wherever the site itself is not encrypted. An exit node moves the point where your traffic joins the internet, from the network you are sitting on to the server you rent. It hides your browsing from café Wi-Fi and from your home ISP, and it shows that same browsing to your VPS provider with your account name attached.