Public SSH is convenient, but a login port exposed to the internet receives constant scanning even when passwords are disabled. A Tailscale SSH VPS setup gives the server a private address inside a tailnet, so an operator can test management access there and then remove public port 22 from the normal internet path.
The safe result is not simply “install a VPN and close a port.” It is a staged change with a working provider console, a second verified session, explicit identity rules and a recovery procedure. This guide shows that sequence and clarifies when to use normal OpenSSH over Tailscale versus Tailscale SSH.
Install Tailscale on both the administrator device and the VPS, verify SSH over the server’s private Tailscale address, and keep the original public session open while testing. Decide whether Linux SSH keys should remain responsible for login or Tailscale should manage SSH identity. Only after a reboot test and console-recovery check should the public firewall rule for port 22 be removed. A private VPS instance still needs updates, non-root administration and a documented rollback path after Tailscale is added.
Moving SSH behind a tailnet reduces the number of systems that can even reach the login service. That cuts scanner noise and removes public password guessing from the ordinary path. It also avoids maintaining changing home or office IP allowlists when administrators travel.
This change improves exposure control; it does not make OpenSSH obsolete or turn the VPS into a trusted device automatically. A stolen administrator laptop, a compromised identity-provider account or an overly broad tailnet policy can still create access. Private reachability and login authorization are separate decisions, and both need review.
Tailscale supports two useful patterns that are often described as if they were the same.
| Mode | Who authenticates the Linux login? | Good fit | Main caution |
|---|---|---|---|
| OpenSSH over Tailscale | The VPS’s normal sshd, SSH keys and local settings |
Operators that want a private network while keeping an existing key workflow | Key rotation and sshd hardening remain your responsibility |
| Tailscale SSH | Tailscale identity and tailnet SSH policy for connections arriving over Tailscale | Small teams that want centralized authorization and optional reauthentication | Policy and identity-provider security become part of the login boundary |
| Public SSH with IP allowlisting | OpenSSH plus a public firewall rule | Temporary bootstrap or a tightly controlled fixed-source environment | Mobile and changing IPs make rules brittle; the port remains public to allowed ranges |
With ordinary SSH over Tailscale, connect to the Tailscale IP but keep using an SSH key as usual. With Tailscale SSH, tailscaled intercepts port 22 traffic addressed to the server’s Tailscale IP. According to the official Tailscale SSH documentation, enabling that mode does not rewrite /etc/ssh/sshd_config or ~/.ssh/authorized_keys. Non-tailnet SSH continues to reach OpenSSH until a host or provider firewall blocks it.
That distinction matters during rollback. You can adopt the private network first, confirm it works with existing SSH keys, and enable Tailscale-managed SSH in a later change window.
Private mesh access is useful when administrators move between networks, a team manages several servers, or an internal dashboard should not share the public application surface.
| Situation | Fit | Guardrail |
|---|---|---|
| Solo operator with a tested VPS web console | Strong | Keep a non-root sudo account and record the console recovery steps |
| Agency or small operations team | Strong | Use named identities, groups and least-privilege rules rather than shared accounts |
| Automation that can join the tailnet | Conditional | Give the machine a narrow identity and avoid reusable interactive credentials |
| Server with no out-of-band console or rescue path | Poor until fixed | Do not remove public SSH before a recovery method exists |
| Organization that must self-host every control-plane component | Conditional | Review Tailscale’s service dependency or evaluate a maintained alternative such as Headscale |
| One-off public file or web service | Not the main use case | Keep the application on HTTPS and use the tailnet for administration only |
Tailscale is also not a substitute for an initial SSH and firewall baseline. Complete the Linux account, update and firewall work first, then change the management path.
Open the VPS provider’s browser console or rescue console and verify that it reaches the correct machine. Keep the current public SSH session open. Record the Linux username that has sudo access and make sure it can log in locally from the console.
Do not treat an untested console button as a recovery plan. A useful test ends with a shell prompt and a known way to restart networking or tailscaled.
Install Tailscale from its current official Linux instructions rather than copying an old package command from a random tutorial. Once installed, enable the service and join the server:
sudo systemctl enable --now tailscaled
sudo tailscale up
tailscale status
tailscale ip -4
The last command returns the VPS’s private Tailscale IPv4 address. It is not the server’s public IP. On the administrator device, confirm that the VPS appears in tailscale status, then test the network path:
tailscale ping vps-name
ssh [email protected]
Replace the example hostname, user and address. Keep this second session open alongside the original public session.
If existing OpenSSH keys and local configuration are the desired authentication layer, no Tailscale SSH switch is required. Continue using ssh admin@<tailscale-ip> and restrict reachability with tailnet and firewall policy.
If centralized Tailscale identity should authorize the login, enable the feature on the VPS:
sudo tailscale set --ssh
Tailscale warns that enabling this can hang an SSH session already connected to the Tailscale IP, which is another reason to keep the separate bootstrap session and console available. Test a fresh Tailscale SSH connection before continuing.
Network permission to reach port 22 and permission to start a Tailscale SSH session are separate controls. The current official Linux VM guide shows both a network grant and an SSH rule.
The following is a structural example for one owner-managed VPS. Replace the identity and address in the Tailscale policy editor, use its validation, and adapt groups or tags for a team:
{
"grants": [
{
"src": ["[email protected]"],
"dst": ["100.64.65.66"],
"ip": ["22"]
}
],
"ssh": [
{
"action": "check",
"src": ["[email protected]"],
"dst": ["autogroup:self"],
"users": ["admin"]
}
]
}
check can require the user to reauthenticate before a higher-risk session. The explicit admin target binds this rule to one intended Unix account and keeps daily administration away from direct root login. autogroup:nonroot is broader because it permits every existing non-root account; use it only when that is genuinely intended. Team environments should use maintained groups and server tags, then remove access when a person or device leaves.
A successful connection immediately after setup is not enough. Confirm the daemon starts after reboot and that policy still permits the intended user:
sudo systemctl is-enabled tailscaled
sudo systemctl is-active tailscaled
tailscale status
tailscale ping vps-name
Reboot only during a change window with console access available. After the VPS returns, open a new private SSH session rather than trusting the session that survived from before the test.
For ordinary OpenSSH over the tailnet, a narrow UFW rule can permit the private interface:
sudo ufw allow in on tailscale0 to any port 22 proto tcp
sudo ufw status numbered
sudo ss -ltnp | grep ':22'
Review both the host firewall and any provider firewall. Remove the public allow rule only when all of these checks pass:
| Required check | Passing evidence |
|---|---|
| Provider console works | A real shell opens without SSH |
| Private session works | A new terminal reaches the non-root account over the Tailscale IP |
| Policy is narrow | Only the intended user or group can reach and start SSH |
| Reboot path works | tailscaled is active and a fresh private login succeeds after reboot |
| Public path is tested | Connection to the public IP on port 22 fails from outside the tailnet |
Do not paste a firewall-delete command blindly: rule names and ordering differ across VPS images. Removing the wrong numbered rule can expose another service or cut off the recovery path. Inspect the active rules, make one change, and test from a separate terminal.
When the private connection fails, the failure usually belongs to one of four layers: the daemon, network path, tailnet policy or Linux account.
| Symptom | Check | Safer response |
|---|---|---|
| VPS appears offline in the tailnet | systemctl status tailscaled |
Use the provider console, restart the service and inspect logs |
| Private IP works but MagicDNS name does not | tailscale status and the private IP |
Repair DNS settings without changing the firewall again |
| Policy denies the session | Tailnet policy validator and user identity | Restore the narrow intended rule; do not switch to allow-all |
| Connection uses a relay and feels slow | tailscale ping and tailscale netcheck |
Review firewall/NAT behavior; do not open broad inbound ranges casually |
| SSH reaches the VPS but rejects the account | Local user, shell and sudo configuration | Fix the Linux account from console; Tailscale does not create Unix users |
Useful evidence commands are deliberately read-only:
sudo journalctl -u tailscaled --since "15 minutes ago"
tailscale netcheck
tailscale status
Tailscale normally attempts a direct encrypted peer connection and can fall back to a DERP relay when a direct path is unavailable. The official firewall guidance notes that relayed connections may be slower. That is a performance clue, not a reason to weaken the firewall without understanding the tradeoff.
A private management plane reduces exposure, but the server still needs ordinary operational controls:
sudo rights.The honest limitation is that Tailscale adds a control-plane and identity dependency. It can simplify revocation and private routing, but a compromised administrator identity or device remains powerful. Teams that cannot own access reviews, console recovery and patching may be better served by managed server operations.
Start with ordinary SSH over the Tailscale address and leave public SSH unchanged for one controlled test. Verify the provider console, private login, daemon startup and policy from a second device. Then choose Tailscale SSH if centralized identity improves the operating model, and restrict public port 22 only as the final, independently verified step.
No. Ordinary SSH over Tailscale uses the private network path but keeps OpenSSH keys and server authentication. Tailscale SSH also lets Tailscale manage authentication and authorization for tailnet SSH sessions.
Yes, but only after a fresh private login, reboot test and provider-console recovery test all succeed. Restrict the host and provider firewalls carefully, then verify the public path from outside the tailnet.
It can affect the private management path, which is why the VPS should retain a tested provider console or rescue route. Do not make every recovery method depend on the same identity and network control plane.
Only when Tailscale SSH is enabled for the tailnet connection. If you use ordinary OpenSSH over Tailscale, SSH keys and local sshd policy still authenticate the login.