
If port 5900 on your rented Mac answers from the public internet, anyone on the network can attempt a VNC login. The fix is three layers applied in order: block 5900 inbound with pf, reopen Screen Sharing only through an SSH local forward, and remove passwords from sshd entirely. The runbook below ends with an nmap check so you can see the change from outside.
This guide assumes you have a shell on the Mac over inbound SSH. Figment's physical i3 Mac ($49/month) and M-series Mac (from $95/month) are the right fit for this workflow; request them with inbound SSH enabled at /mac-hosting/start. Physical hardware and provisioning timing are confirmed in the quote. The $29 virtual Intel macOS plan runs real macOS but is accessed through a browser console rather than public inbound SSH, so the SSH-tunnel pattern below targets the physical plans. If you only need a desktop to drive Xcode-compatible Intel toolchains (Xcode 26 or earlier), the $29 VM still runs macOS and signs supported Intel targets; it just is not the subject of this hardening recipe.
macOS Screen Sharing listens on TCP 5900. The classic VNC authentication exchange is a short DES challenge-response and the payload itself is not encrypted, so a password alone is not an acceptable defence for a host reachable from arbitrary IPs. An attacker who succeeds gets the logged-in user's graphical session — Finder, Keychain Access, browser cookies, everything. Treat 5900 like you would a database port: never directly public.
macOS ships with pf from OpenBSD. Create a small anchor so your rule is isolated from the default /etc/pf.conf:
sudo mkdir -p /etc/pf.anchors
sudo tee /etc/pf.anchors/vnc-block > /dev/null << 'EOF'
block in quick proto tcp from any to any port 5900
pass in quick on lo0 proto tcp to any port 5900
EOF
Reference the anchor from /etc/pf.conf:
echo 'anchor "vnc-block"' | sudo tee -a /etc/pf.conf
echo 'load anchor "vnc-block" from "/etc/pf.anchors/vnc-block"' | sudo tee -a /etc/pf.conf
Enable pf and load the rules:
sudo pfctl -ef /etc/pf.conf
sudo pfctl -s rules | grep 5900
macOS does not re-enable pf automatically on reboot. Add a LaunchDaemon at /Library/LaunchDaemons/com.example.pf-vnc-block.plist that runs /sbin/pfctl -e -f /etc/pf.conf with RunAtLoad set, then sudo launchctl bootstrap system it. Without that step the block disappears after the next restart and 5900 goes public again.
With 5900 blocked at the firewall, reach it only through an SSH local forward. The OpenBSD ssh(1) manual documents -L as forwarding "connections to the given TCP port or Unix socket on the local (client) host … to the given host and port … on the remote side." That gives you an end-to-end encrypted channel on port 22 and nothing on 5900 from outside.
On your workstation:
ssh -N -L 5901:localhost:5900 you@your-mac-host
Point your VNC client at localhost:5901. Add a reusable entry in ~/.ssh/config:
Host figment-mac
HostName your-mac-host
User you
IdentityFile ~/.ssh/id_ed25519
LocalForward 5901 localhost:5900
ServerAliveInterval 30
Then ssh -N figment-mac and connect VNC to localhost:5901.
Generate a key and install it:
ssh-keygen -t ed25519 -C "mac-remote-desktop"
ssh-copy-id -i ~/.ssh/id_ed25519.pub you@your-mac-host
Drop a hardening file at /etc/ssh/sshd_config.d/10-hardening.conf on the Mac:
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin no
AllowUsers you
Reload sshd and confirm from a second terminal before you close the first:
sudo launchctl kickstart -k system/com.openssh.sshd
ssh -o PreferredAuthentications=password you@your-mac-host # must fail
ssh figment-mac true # must succeed
If the password attempt still prompts, check for an older /etc/ssh/sshd_config directive overriding the drop-in.
Open System Settings > General > Sharing > Screen Sharing > Options, set "Allow access for" to Only these users, and list the two or three accounts that actually need a desktop. Apple's remote-login configuration page documents the same Only these users pattern for Remote Login and makes the point that the default group includes every local account — which is why "All users" is almost never what you want for an exposed host.
Run nmap from a machine not on the Mac's network. Before the pf rule is active:
$ nmap -Pn -p 5900 your-mac-host
PORT STATE SERVICE
5900/tcp open vnc
After the pf rule loads:
$ nmap -Pn -p 5900 your-mac-host
PORT STATE SERVICE
5900/tcp filtered vnc
filtered means pf is dropping packets silently; closed is also acceptable. open means the rule did not take effect — re-check sudo pfctl -s info for Status: Enabled and sudo pfctl -sA for your anchor. Also confirm SSH itself is still reachable:
$ nmap -Pn -p 22 your-mac-host
PORT STATE SERVICE
22/tcp open ssh
If 22 is filtered, a broader block all upstream of your anchor is swallowing SSH; add an explicit pass in quick proto tcp to any port 22 and reload.
Since the whole recipe depends on inbound SSH, compare the two Figment plans that support it against your workload:
| Need | Plan | Monthly | Notes |
|---|---|---|---|
| Intel Mac desktop, light use, SSH + VNC | i3 Mac | $49 | Request-based; confirm SSH in quote |
| M-series ARM execution, Xcode 27, GPU tasks | M-series Mac | from $95 | Entry price; exact chip/RAM confirmed in quote |
| Intel macOS for cross-compile and Xcode 26 toolchains, no public SSH | Virtual Intel macOS | $29 | Browser-console access; not the target of this guide |
If you are shopping around for the hardware comparison alone: MacStadium publishes M2.S at $109/month and M4.S at $149/month with support and a 99.99% uptime claim on its pricing page, and CloudMac publishes an M4/16 GB/256 GB plan at $99.99/month with a $999/year option on cloudmac.org/pricing. Figment's $95 entry is not a verified M4/16 GB configuration, so treat it as a lower entry price into the M-series line, not an equal-hardware swap; and CloudMac's $999/year is $141 less than twelve months of $95 if an annual commitment fits your timeline. Where Figment differs is the Managed Build Mac tier at $249/month (one M-series Mac, CI setup, backups, monitoring, 30 minutes of monthly support) — useful if you want the hardening above plus a managed CI pipeline rather than the raw box.
| Task | When | Command or location |
|---|---|---|
| Rotate the Screen Sharing VNC viewer password | Every 90 days | System Settings > Sharing > Screen Sharing > Options |
| Audit authorized_keys for stale entries | Monthly | cat ~/.ssh/authorized_keys |
| Review sshd auth attempts | Weekly | log show --predicate 'process == "sshd"' --last 7d |
| Confirm pf is loaded after reboots and updates | After macOS updates | sudo pfctl -s info | grep Status |
After a macOS point update, pf anchors occasionally need to be reloaded even with the LaunchDaemon in place. Add the pfctl -s info check to your post-update runbook so you catch a silent regression before it is a silent exposure.
Ready to provision a Mac you can harden this way? Start at /mac-hosting/start or browse plans at /mac-hosting.