Remote dev stack: Mac server + Tailscale + SSH + tmux
Audience: Anyone who wants terminal-first access to an always-on Mac (e.g. Mac mini) from laptop and phone without port forwarding.
What you get: A private path to the Mac over Tailscale (WireGuard mesh), SSH for a real shell, tmux so sessions survive disconnects, and optional mosh on flaky networks.
Status: Engineering how-to. Promote to knowledge/standards/03-knowledge/engineering/setup/ if the org adopts it as the canonical standard.
How the pieces fit together
| Piece | Role |
|---|---|
| Remote Login (SSH) on the Mac | Listens on port 22 so other devices can open a shell. |
| Tailscale on Mac + clients | Puts every device on a 100.x.x.x virtual network so SSH does not need the public internet or router port mapping. |
| SSH client on laptop | Terminal: ssh user@100.x.x.x |
| SSH client on phone | e.g. Termius, Blink, Moshi — same idea as laptop. |
| tmux on the Mac | One persistent session you detach from and reattach to from any client. |
| mosh (optional) | UDP-based shell; often nicer than SSH on cellular or when roaming. |
Traffic flow: Phone or laptop → Tailscale → SSH → shell on the Mac. Code and repos stay on the Mac; the mobile device is just a terminal.
Prerequisites
- Admin access on the server Mac (Sharing, optional kernel / network extensions for Tailscale).
- Homebrew on the server Mac (for
tmux,mosh; Tailscale is usually the cask installer). - Tailscale account — personal or company tailnet. If the org uses Tailscale with admin approval, new users/devices must be approved in the admin console before login completes.
- Laptop: Terminal + Tailscale app (or CLI).
- Phone: Tailscale from the App Store + an SSH app (this guide uses Termius as the example).
1. Server Mac — enable Remote Login (SSH)
- System Settings → General → Sharing → Remote Login → On.
- Under Allow access for, prefer only the users who need SSH (or a dedicated account), not “All users,” unless you intend otherwise.
CLI (optional):
sudo systemsetup -setremotelogin onVerify SSH is accepting connections (any one of these):
nc -z -v 127.0.0.1 22
# expect: Connection succeededsudo lsof -iTCP:22 -sTCP:LISTENOn some macOS versions, systemsetup may report Remote Login On while lsof without sudo looks empty; trust nc or sudo lsof over a bare lsof.
Sanity check from the Mac itself:
ssh -v "$(whoami)@127.0.0.1"2. Server Mac — install CLI tools (Homebrew)
brew install tmux mosh
brew install --cask tailscale-apptmux— session persistence.mosh— optional; install on both server and client if you plan to use it.- Tailscale — the cask runs an installer that may prompt for admin password and Privacy & Security approval for the network extension.
After install, open Tailscale from the menu bar → Log in (or run sudo tailscale up and complete the browser flow).
If you see “admin must approve you”: A tailnet admin must approve the user or device in the Tailscale admin console. Until then, the Mac will not fully join the network.
3. Join the same tailnet on laptop and phone
- Install Tailscale on each device you use to connect.
- Sign in so they appear in the same tailnet as the server Mac (same account, or same org, per your policy).
Finding the server’s address
- In the Tailscale app on any connected device, open Devices and select the server. Note the 100.x.x.x address (Tailscale IP).
- Optionally use MagicDNS (e.g.
hostname.your-tailnet.ts.net) if your tailnet has it enabled — if unsure, the 100.x address is always a reliable target.
Important: Do not use the Mac’s LAN IP (e.g. 192.168.x.x) for “from anywhere” access unless you also control that network. For coffee-shop / cellular use, use the Tailscale IP.
4. Connect from the laptop
Replace YOUR_USER with the macOS short username on the server and 100.x.x.x with the server’s Tailscale IP (or MagicDNS name).
ssh YOUR_USER@100.x.x.x- First connection: accept host key if prompted (
yes). - Authenticate with the server Mac account password, or with an SSH key if already configured (see below).
Optional — persistent coding session
tmux new -s dev
# Detach: Ctrl+b, release, then d
# Later (new SSH):
tmux attach -t dev5. Connect from the phone (Termius)
- Ensure Tailscale on the phone shows Connected to the same tailnet.
- In Termius, create a host:
- Address: the server’s 100.x.x.x (from the Tailscale device list).
- Username: same
YOUR_USERas on the Mac. - Port: 22 (default for SSH).
- Connect. Termius will ask for a password unless you attached an SSH key in Termius.
What password? The macOS login password for that user on the server Mac — not the Apple ID (unless that account literally uses it), not a Termius-specific password.
If the laptop did not ask for a password: The laptop may be using SSH keys. The phone will still ask for a password until you import a key into Termius or add a new key’s public half to ~/.ssh/authorized_keys on the server.
6. tmux quality-of-life (on the server)
~/.tmux.conf example:
set -g mouse on
set -g history-limit 50000Reload config in tmux: Ctrl+b then : then source-file ~/.tmux.conf.
7. SSH keys (recommended for teams)
On the client (laptop):
ssh-keygen -t ed25519 -C "you@company.com" -f ~/.ssh/id_ed25519_remote_devInstall public key on the server (after one successful password login):
ssh-copy-id -i ~/.ssh/id_ed25519_remote_dev.pub YOUR_USER@100.x.x.xTermius: Import the private key (or generate in app and install the public key on the server). Prefer per-user keys, not shared keys.
Hardening (only after keys work): Consider disabling password authentication in sshd_config on the server. Coordinate with whoever manages the machine; lockouts are painful.
8. mosh (optional)
Requires mosh installed on both ends. Then:
mosh YOUR_USER@100.x.x.xStart tmux inside mosh if you want session persistence plus mosh’s transport. Many phone SSH clients do not support mosh; SSH + tmux is the usual phone pattern.
9. Troubleshooting
| Symptom | Likely cause | What to try |
|---|---|---|
Connection timed out | Client not on Tailscale, wrong IP, server asleep/offline, ACL blocking | Confirm Tailscale Connected on both sides; ping or tailscale ping from another device; check server Energy settings if headless. |
Permission denied (publickey,password) | Wrong username/password, or keys only | Verify Users & Groups short name; reset password test; add key or enable password auth temporarily. |
| Tailscale stuck on “approval required” | Org policy | Tailnet admin approves user/device in admin console. |
lsof shows nothing on :22 but Remote Login is On | Permissions / socket activation | Use sudo lsof or nc -z 127.0.0.1 22. |
| Works on Wi‑Fi but not cellular | Not using Tailscale IP, or Tailscale off on phone | Use 100.x address; open Tailscale on phone. |
10. Security notes (team rollout)
- Prefer Tailscale ACLs so only approved identities can reach port 22 on server Macs.
- Avoid exposing SSH to 0.0.0.0 on the public internet; Tailscale is the intended edge.
- Use per-person macOS accounts and per-person SSH keys on shared lab machines.
- Keep macOS patched; Remote Login is a high-value surface.
11. Validation checklist (copy for onboarding)
| # | Check | Pass? |
|---|---|---|
| 1 | Server: Remote Login on; nc -z 127.0.0.1 22 succeeds | |
| 2 | Server: Tailscale connected; appears in admin / app device list | |
| 3 | Laptop: Tailscale connected; ssh user@100.x.x.x works | |
| 4 | Laptop: tmux new -s test → detach → SSH again → tmux attach -t test | |
| 5 | Phone: Tailscale connected; Termius (or equivalent) SSH to same host | |
| 6 | Optional: SSH keys in use; password login disabled only if policy allows |
Related
- Community patterns (Reddit/X/summary): “Tmux + Tailscale + SSH” remote coding workflows, Apr 2026 internal last30days run.
- Optional promotion path:
knowledge/standards/03-knowledge/engineering/setup/once owners sign off.