Remote Access Guides
SSH into Devices Behind NAT, CGNAT or Firewalls
SSH into a machine you cannot reach directly, such as a gateway on a cellular link, with no port forwarding, public IP address or VPN.
Summary
ssh command through localport access. The device connects outward on port 443, so NAT, carrier-grade NAT and firewalls that block inbound traffic are not in the way. Only people you grant can reach it, and every session is recorded in an access log. Available on the Pro, Business and Enterprise plans, see pricing.What you will have at the end#
A remote gateway named gw-0042 sits on a cellular link behind carrier-grade NAT. From your laptop, this command opens a shell on it:
ssh gw-0042
The same entry works for scp, rsync, sftp and SSH port forwarding. Nothing on the gateway's network accepts an inbound connection, and the gateway has no public address. Your sign-in decides whether the connection reaches the gateway at all, and the gateway's own SSH server then checks your account as usual.
The guide uses one gateway as the running example. The steps are the same for a server on a customer's LAN, a kiosk, a charger or a single-board computer.
Before you start#
You need:
- A team on the Pro, Business or Enterprise plan. Remote Access is not available on other plans.
- The owner or admin role, or an admin who sets up the device and grants you access. A developer connects once granted and cannot write grants.
- An SSH server running on the device, and an account on it you can log in to.
- The Localport agent on the device and on your own computer, both from Installation. This guide covers macOS and Linux clients.
Why SSH fails behind NAT, CGNAT or a firewall#
SSH needs your computer to open a connection to the device on port 22. A device behind a home or office router has a private address, so it cannot be reached from outside unless someone forwards a port on that router. A device on a cellular or fibre connection behind carrier-grade NAT (CGNAT) shares a public address with other subscribers, and the carrier will not forward a port for you. A firewall you do not administer refuses the connection outright.
All three block connections coming in. None of them blocks connections going out. The Localport agent on the device opens an outbound connection to Localport on port 443 and keeps it open. Your SSH session travels back along that connection.
How the connection reaches the device#
ssh → localport access --stdio 22 → Localport edge → agent on the device → localhost:22
(your computer) (checks your (outbound on 443)
certificate and
your grant)
localport access on your computer presents a client certificate to the Localport edge. The edge checks three things before any byte reaches the device:
- The certificate belongs to your team, has not expired and has not been revoked.
- An access grant on the fleet covers you and this device.
- Port 22 is allowed on the device.
A connection that fails any check is refused. A refusal for a missing grant, a revoked certificate or a port that is not allowed is recorded in the access log. A certificate that has expired or was not issued by your team is rejected during the TLS handshake and is not logged. When all three pass, the edge hands the connection to the agent on the device, which delivers it to the SSH server on port 22. SSH then runs end to end between your client and the device, with its own encryption, host key check and login. Detailed explanation: Remote Access.
Make the device reachable#
These three steps put one device online and give you access to it. For many devices, follow Set Up Remote Access to a Device Fleet, which adds naming, auto-join and role-based grants.
Step 1: Create the device with port 22#
A device lives in a fleet. In the dashboard, go to Fleets and click Create fleet. Name it Gateways, choose a Region, and click Create Fleet.
The sheet moves to Create device & Connect. Enter the device name gw-0042, add port 22 with protocol TCP, and click Create device. TCP carries the SSH stream as it is.
To give the fleet a readable address, open its Settings and enter acme-gateways in Subdomain, then save. The subdomain is at least 12 characters. The device's address is its name joined to the subdomain:
gw-0042-acme-gateways.eu.localport.dev
This is the address you connect to. It is not reachable from the internet without a certificate and a grant. Detailed guide: Fleets.
Step 2: Start the agent on the device#
The Create device & Connect sheet ends with the command for this device. Type 22 in Allowed ports first. The field is optional and sets a limit on the device itself: the agent then serves port 22 only, whatever the dashboard allows later.
localport connect --token tok_YOUR_FLEET_TOKEN --region eu --name gw-0042 --allow-ports 22
--tokenis the fleet token. Every device in the fleet uses it, so treat it like a password.--region euis the region you chose for the fleet.--name gw-0042is the device this machine connects as. It must match the name in the dashboard.--allow-ports 22is the device's own limit on what it serves.
Run it on the device to check that the device comes online. The device row on the Devices tab turns online within seconds.
For a device that must stay reachable, run the agent as a service so it starts at boot and restarts after a failure. The service reads the token from a file, so it never appears in the process list. Follow Run the agent as a background service and use the localport connect line above, without --token, as its ExecStart=.
Step 3: Grant yourself access#
A fleet is private from the moment it exists. An online device reaches nobody until a grant names who may connect.
Open the fleet's Access tab and click Give access. Under Type, choose Member. Under Who, choose yourself. Under Access, type gw-0042 in the search field and pick the device. Then click the button that reads Give access to and your name.
To give a whole team every gateway, choose Role and the pattern gw-* instead. A grant covers every port allowed on the device it names. Detailed guide: Grants and Access.
Connect from your computer#
Step 4: Sign in from the terminal#
On your own computer, sign in once:
localport login
The agent prints a link and a code, then waits. Open the link in any browser, sign in to the dashboard, choose the team if asked, check that the code matches the one in your terminal and click Sign in. The terminal prints signed in.
The private key is generated on your computer and stays there. The certificate lasts 8 hours and does not renew. Run localport login again when it expires. The browser can be on another device, such as your phone. Signing in on a remote jump box works the same way. Detailed guide: Member Access.
Step 5: Connect once with ProxyCommand#
SSH's ProxyCommand option runs a program and uses its input and output as the connection. localport access --stdio 22 is that program:
ssh -o ProxyCommand="localport access gw-0042-acme-gateways.eu.localport.dev --stdio 22" ops@gw-0042
localport access <address>connects to the device with your certificate.--stdio 22carries one connection to the device's port 22 over standard input and output. No local port is opened.ops@gw-0042is the account on the device and the name SSH uses for this host.
The agent prints three lines first: who you are signed in as, when the sign-in expires, and a reminder that it does not renew. On the first connection, SSH shows the device's host key fingerprint and asks whether to trust it. Compare it with the fingerprint on the device, from ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub, before you answer yes. SSH stores the key under gw-0042 in ~/.ssh/known_hosts and checks it on every later connection.
Step 6: Add the device to your SSH config#
Typing the proxy command each time is not needed. Add an entry to ~/.ssh/config:
Host gw-*
User ops
ProxyCommand localport access %h-acme-gateways.eu.localport.dev --stdio 22
%h is replaced by the name you type after ssh. ssh gw-0042 reaches gw-0042-acme-gateways.eu.localport.dev, and ssh gw-0107 reaches gw-0107-acme-gateways.eu.localport.dev. One entry covers every device whose name starts with gw-, including devices added later.
ssh gw-0042
For a single device with a name that matches no pattern, write it out in full:
Host plant-server
User ops
ProxyCommand localport access plant-server-acme-gateways.eu.localport.dev --stdio 22
Step 7: Copy files and forward ports#
Every tool that reads ~/.ssh/config now reaches the device through the same entry:
scp ./firmware.bin gw-0042:/tmp/
rsync -av ./config/ gw-0042:/etc/acme/
sftp gw-0042
To reach a web interface on the device, such as a status page on port 8080, use SSH's own port forwarding:
ssh -L 8080:localhost:8080 gw-0042
Then open http://localhost:8080 on your computer. The forward runs inside the SSH session, so port 8080 does not need to be allowed on the device. To reach that port without SSH, allow it on the device and use localport access gw-0042-acme-gateways.eu.localport.dev -L 8080:8080. The Access button on the device row in the dashboard shows that command ready to copy. Detailed guide: Fleets.
How long a session lasts#
An SSH session through Localport stays open while all of these hold:
- Your certificate is valid. A sign-in lasts 8 hours, and the edge closes the connection when it expires. A session opened 7 hours after
localport loginends an hour later. Sign in again before a long job. - The device's agent stays connected. If the agent restarts, the device loses its link, the fleet token is rotated or the Localport service carrying the session restarts, the session ends. Reconnect once the device is back online.
- Your access stands. Removing or narrowing your grant, revoking your certificate, removing the device or removing you from the team closes the session at once. SSH reports that the connection closed, and a new attempt is refused with
refused this certificate.
An open session is never closed for being idle.
A machine identity from a setup key renews its certificate in the background, so a deploy server's sessions are not cut at a fixed hour.
Troubleshooting#
The agent writes its errors to the terminal, above SSH's own message that the connection closed.
| Message | Cause | Fix |
|---|---|---|
refused this certificate: check that the identity has access to the device | No grant covers you and this device, your certificate was revoked, or the credential belongs to another team. | Check the fleet's Access tab, then run localport identity list. |
not allowed: check this identity's access to the device, and that port 22 is open on it | Port 22 is not allowed on the device in the dashboard, or --allow-ports on the device leaves it out. | Check the device's ports on the Devices tab and the agent's --allow-ports. |
nothing is listening on port 22 on the device | The connection reached the device, and no SSH server answered. | Start the SSH server on the device, for example sudo systemctl start ssh. |
cannot reach <address>: device offline or unknown address | The agent on the device is not running, the address is wrong, or your computer cannot reach Localport on port 443. | Check the device is online on the Devices tab, compare the address, and check your own network allows outbound port 443. |
rejected the certificate as expired | Your 8-hour sign-in ended. | Run localport login. |
device is busy, retry | The device, or your identity, already has as many connections open as Localport allows at once. | Close sessions you no longer use, then connect again. |
several credentials on this machine; choose one with --identity: | You hold credentials for more than one team or identity. | Add the --identity value it prints to the ProxyCommand line. |
A refusal for a missing grant, a revoked certificate or a closed port is recorded in the Access log with the reason, so an admin can see why it failed. An expired sign-in is rejected during the TLS handshake and does not appear there. Detailed guide: Access Log.
Keep the device secure#
- Leave SSH authentication on. Localport checks who you are before the connection reaches the device. The SSH server still checks the account. Use key-based logins and turn password logins off in
sshd_config. - Limit ports on the device.
--allow-ports 22keeps the device to SSH, even if more ports are allowed in the dashboard later. - Grant the narrowest reach. A grant for one device, or one name pattern, keeps each person to the machines they work on.
- Review the access log. Every session records the identity, the device and port, the source address and the duration.
Limitations#
- TCP only. UDP is not carried, so
moshdoes not work. Usessh. - The agent runs on both ends.
localport accessruns on the computer you connect from. - Sign-in sessions end at 8 hours. Use a setup key for a machine that holds sessions open longer.
- A grant covers every port allowed on the device. To give different people different ports on one machine, run it as two devices with different names.
Frequently asked questions#
How do I SSH into a device behind CGNAT without port forwarding?
Run the Localport agent on the device with localport connect, grant yourself access, and connect with ssh -o ProxyCommand="localport access <device-address> --stdio 22" user@device. The agent on the device connects outward on port 443, so carrier-grade NAT does not block it. No port forwarding, public IP address or VPN is needed.
Why not open a TCP tunnel to port 22?
A TCP tunnel gives port 22 a public address. Without an IP allowlist, anyone can connect to it, and the SSH server is the only check. Remote Access gives the device no public address. The edge refuses every connection without a valid certificate and a grant, before it reaches the SSH server.
Can Localport read my SSH session?
No. SSH encrypts the session between your client and the device's SSH server, and Localport carries the encrypted stream. The access log records connection metadata only: the identity, the device and port, the source address, the duration and the bytes transferred.
Does it work with VS Code Remote-SSH, scp and rsync?
Yes, when the tool uses OpenSSH and reads ~/.ssh/config. Add the Host entry from Step 6 and connect to the host name, such as gw-0042. scp, sftp, rsync and ssh -L use the entry directly.
Does mosh work?
No. Mosh sends its traffic over UDP, and Localport carries TCP only. Plain ssh works.
I belong to two teams. Which credential does ssh use?
With one credential on your computer, that one. With several, localport access does not prompt inside ProxyCommand. It stops and lists the --identity value for each credential. Add the value for the right credential to the ProxyCommand line, or set it in LOCALPORT_IDENTITY.
Can I reach a machine that cannot run the agent?
Yes. Run the agent on another machine on the same network and start it with --host, for example --host 192.168.1.20. Connections to that device are delivered to the address you give. See Fleets.
Can a CI job SSH into a device?
Yes, with no stored secret. A pipeline proves its identity with OIDC and reaches the devices you grant it. See CI/CD with OIDC.
What to read next#
- Set Up Remote Access to a Device Fleet. Many devices, auto-join, role grants and a deploy server.
- Member Access. Signing in with
localport login. - Grants and Access. Who reaches which devices.
- Fleets. Devices, ports,
--hostand--allow-ports. - Access Log. Every session and every refusal.