SSH to a Machine Behind NAT
Reach a machine that has no public IP and no open inbound port: a box at home, a lab machine, a cloud VM with a closed firewall. The machine connects out to nfltr.xyz; your laptop's ssh goes through that connection.
Goal
ssh build-box from your laptop opens a shell on a machine called build-box behind NAT.
Prerequisites
- On both machines: the
nfltrCLI and an API key of the same account, saved withnfltr config add-api-key(orNFLTR_API_KEYset). - On the laptop: an OpenSSH client (
ssh). - On build-box: nothing else.
nfltr shellis its own SSH server, so nosshdis needed. If build-box already runssshd, you can use it instead (step 3b).
1. Make a key pair on the laptop
Skip this if you already have one. The key is how build-box knows it is you.
$ mkdir -p ~/.ssh && chmod 700 ~/.ssh
$ [ -f ~/.ssh/id_ed25519 ] || ssh-keygen -q -t ed25519 -N '' -f ~/.ssh/id_ed25519
$ cat ~/.ssh/id_ed25519.pub
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI… you@laptop
2. Allow that key on build-box
On build-box, add the line cat printed to ~/.ssh/authorized_keys (paste it with an editor, or copy it over any channel you trust). When you try this tutorial with both ends on one machine, this does it:
$ cat ~/.ssh/id_ed25519.pub >> ~/.ssh/authorized_keys
3a. Start the SSH server on build-box
Give it a host key of its own, so ssh on your laptop can recognise build-box across restarts (without --host-key, nfltr shell makes a new key each time it starts):
$ [ -f ~/.ssh/nfltr_host_key ] || ssh-keygen -q -t ed25519 -N '' -f ~/.ssh/nfltr_host_key
$ nfltr shell --name build-box --authorized-keys ~/.ssh/authorized_keys --host-key ~/.ssh/nfltr_host_key
nfltr dev starting embedded SSH shell
agent-id: build-box
e2ee: enabled (TLS termination on agent)
ssh: 127.0.0.1:51709 (embedded, no sshd required)
auth: public key (/home/you/.ssh/authorized_keys)
Connected — embedded SSH shell active
Leave it running (tmux, screen or a service manager). It listens only on build-box's loopback; the only way in is through nfltr, and only for keys in authorized_keys. --password (or NFLTR_SHELL_PASSWORD) enables password login instead; prefer keys.
3b. Or expose an existing sshd
If build-box already runs OpenSSH on port 22, forward that port instead of starting nfltr shell. Everything on the laptop side stays the same.
$ nfltr tcp 22 --name build-box
4. Add build-box to your laptop's ssh config
$ nfltr ssh-config build-box --identity ~/.ssh/id_ed25519
Added SSH config for "build-box" in /home/you/.ssh/config
Now you can: ssh build-box
It adds this block to ~/.ssh/config (--print shows it without writing; --user sets the login name, default your local user):
$ nfltr ssh-config build-box --identity ~/.ssh/id_ed25519 --print
# nfltr-managed: build-box
Host build-box
ProxyCommand /usr/local/bin/nfltr ssh-proxy --peer %h --port %p
User you
IdentityFile /home/you/.ssh/id_ed25519
HostKeyAlias nfltr-build-box
# end nfltr-managed: build-box
ssh asks you to accept build-box's host key on the first connection and remembers it under nfltr-build-box, kept apart from any LAN host that is also called build-box. If a different key answers later, ssh refuses to connect, so a machine that registered the name build-box with a key of your account cannot impersonate it.
--insecure-skip-host-key-check writes StrictHostKeyChecking no and UserKnownHostsFile /dev/null instead, and prints a warning. Avoid it: ssh then accepts whatever answers, and a password or anything you type in its shell goes to it.
5. Connect
$ ssh build-box 'echo hello from $(hostname)'
The authenticity of host 'nfltr-build-box' can't be established.
ED25519 key fingerprint is SHA256:….
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'nfltr-build-box' (ED25519) to the list of known hosts.
hello from build-box
Answer yes once; later connections check the key silently. Drop the quoted command for an interactive shell; scp, rsync -e ssh, sftp and VS Code Remote-SSH use the same build-box entry.
Alternative: a local port with nfltr tcp-connect
For tools that want a host and a port instead of an ssh config entry, forward a local port to build-box's SSH port:
$ nfltr tcp-connect build-box 22 --listen 127.0.0.1:2222
nfltr tcp-connect dev
agent: build-box
remote: port 22
local: 127.0.0.1:2222
Listening — connect with your TCP client to 127.0.0.1:2222
Check that SSH answers on the local port (this prints build-box's host key), then connect with ssh (it asks you to accept that key the first time):
$ ssh-keyscan -T 10 -p 2222 127.0.0.1
[127.0.0.1]:2222 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI…
$ ssh -p 2222 -i ~/.ssh/id_ed25519 localhost
The same works for any TCP service on build-box: nfltr tcp 5432 there and nfltr tcp-connect build-box 5432 --listen 127.0.0.1:5432 here gives you psql -h 127.0.0.1.
6. Clean up
Stop nfltr tcp-connect with Ctrl+C, remove the ssh config block, then stop nfltr shell on build-box with Ctrl+C.
$ nfltr ssh-config build-box --remove
Removed SSH config for "build-box" from /home/you/.ssh/config
# Ctrl+C in the nfltr shell terminal on build-box
If it goes wrong
| You see | Meaning and fix |
|---|---|
nfltr ssh-proxy: server returned 503: agent temporarily unavailable then Connection closed by UNKNOWN port 65535 | No machine called build-box is connected for your account: nfltr shell is not running there, it runs under another name, or it uses a key of a different account. Check the name in its agent-id: line. |
Permission denied (publickey) | build-box does not have your public key in the file passed to --authorized-keys, or ssh offers a different key: pass --identity to nfltr ssh-config. |
kex_exchange_identification: read: Connection reset by peer through tcp-connect | The tunnel reached nfltr but not an SSH server: build-box is not connected under that name, or nothing listens on the remote port. |
WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! | Something with a different host key answered as build-box: nfltr shell restarted without --host-key, or another machine uses the name. If you know it was a restart, forget the old key with ssh-keygen -R nfltr-build-box and connect again. |
ssh: Could not resolve hostname build-box | The config block is missing. Run nfltr ssh-config build-box again (with --config if you keep your ssh config elsewhere). |
Next
- Reach a whole private LAN through one machine on it
- TCP and SSH tunneling
- Diagnose connection problems