SSH into servers behind NAT — through one link you can revoke.
linkport gives you SSH access to Linux machines behind NAT, CGNAT or a firewall. One install command, outbound TLS only — then open the link in a browser terminal, connect with linkport Terminal, or hand it to an AI agent over MCP.
deploy@vps-01:~$ curl -sI http://127.0.0.1/health
HTTP/1.1 502 Bad GatewayServer: nginx/1.24.0 (Ubuntu)deploy@vps-01:~$
linkport Terminal · Interactive preview · Example datalinkport Terminal · Example data
Ask the assistant
deploy@vps-01:~$ curl -sI http://127.0.0.1/health
HTTP/1.1 502 Bad Gateway. Server: nginx/1.24.0 (Ubuntu).
Open Assistant: nginx 502 on vps-01; vps-01 · Change; Hosts: 1.
User: nginx on vps-01 started returning 502 after the deploy. Find out why.
Assistant · Claude Sonnet 5.5: Checking the app service behind nginx and the logs on both sides.
Auto-listed reads run without approval, each Running → Done:
systemctl status app --no-pager
tail -n 20 /var/log/nginx/error.log
journalctl -u app -n 30 --no-pager
df -h /var/log
Cause: app.service exits on start — /var/log is 98% full, so it can't open its log file (ENOSPC).
nginx gets connection refused from 127.0.0.1:8080 and answers 502.
Fix: shrink the systemd journal to 500 MB, then restart the service. Changes run only after you approve them.
Awaiting approval: journalctl --vacuum-size=500M; sudo; Change.
The whole command runs as root. The app passes the sudo password from the connection itself — the assistant never sees it.
deploy@vps-01 · unknown flag, as root, sudo password from the connection.
Model explanation: Frees space in /var/log so the service can open its log file again.
Pending approvals: 1. Run / Reject. User presses Run → Running → Done; pending banner clears.
Assistant: Freed 19.4 GB in /var/log. Restarting the service.
Awaiting approval: systemctl restart app; sudo; Change.
deploy@vps-01 · unknown program, as root, sudo password from the connection.
Model explanation: Starts app.service again now that it can write its log.
Pending approvals: 1. Run / Reject. User presses Run → Running → Done; pending banner clears.
Assistant: app.service is active again and /health answers 200.
User types curl -sI http://127.0.0.1/health in the terminal.
HTTP/1.1 200 OK. Server: nginx/1.24.0 (Ubuntu). Shell prompt ready.
Connect over a link
Host list with Production and Staging groups. vps-01 selected (tagged linkport), Host details open.
Connect opens a tab: Connecting…, Signing in…, Opening the shell…, Connected.
Login banner, last login from 127.0.0.1 (the agent dials sshd locally).
Typed: hostname && uname -r
Output: vps-01, 6.8.0-45-generic
Keep two sessions in view
The pane splits inside the same tab. staging-02 connects on the right.
Typed: cd /srv/app && git status --short
Output: two modified files and one untracked file
Move a file between hosts
SFTP with two remote panes: vps-01:/srv/app and staging-02:/srv/app.
Transfer vps-01 → staging-02 of config.example.json (example data, 4.2 KiB) until done.
Recover the session
Connection lost card over the preserved buffer: attempt 1, next in 2 s, Reconnect now.
Connected again with the same output.
Applies to the browser console and to MCP run_command.
✓
Revoke
Close access for new visitors.
Revoked
New connections are refused. Already-open sessions keep running until they disconnect.
Link revoked. New connections are refused; already-open sessions keep running until they disconnect.
Your machine
linkport-agent proxies only the local addresses you publish.
linkport-agent
ssh:127.0.0.1:22
TLS 443outbound only
linkport edge
Checks the link and enforces read-only and command lists.
TLS 1.3
ALPN linkport/1
WebSocket
HTTPS · WSSto the edge, never the machine
Visitor
A browser tab, linkport Terminal or an MCP client.
/s/<id>
/h/<id>/
POST /mcp
Transport
TLS 1.3 on port 443 — ALPN linkport/1, or WebSocket where only HTTPS gets out.
Multiplexing
One connection carries consoles, tunnels and MCP calls.
Liveness
The agent reconnects with backoff; the link stays the same.
What people reach with linkport
The agent dials out, so it does not matter who owns the router or whether there is a public
IPv4 at all.
A home server or Raspberry Pi behind CGNAT
Your ISP shares one public address across customers, so nothing can dial in. The agent dials out on 443 and you open the link. Raspberry Pi needs a 64-bit OS.
CGNATaarch64homelab
A client’s server — without a VPN or their SSH keys
Hand over a link with a password or a sign-in, an expiry and a revoke button. Nobody joins anybody’s network, and no private key changes hands.
passwordexpiryrevoke
A VPS or cloud box with no public IPv4
An instance in a private subnet reaches the edge through its NAT gateway on 443. No bastion host, no elastic IP, no security-group hole for port 22.
private subnetno bastion
Linux devices on LTE, 5G or Starlink
Carrier networks put devices behind CGNAT and change their address. The link stays the same; the agent reconnects with backoff.
LTE / 5GStarlinkreconnect
The link is the credential.
Share SSH access with a link you can revoke
256 bits of entropy, narrowed further by a password, named accounts, expiry and an IP
allowlist. Rotate or revoke it at any time.
linkport Terminal: a desktop SSH client for Windows, macOS and Linux
SSH over the link or straight to a public host, two-pane SFTP, split panes, a local key
vault and an AI assistant on your own model. Included with Pro and Team.
Read-only mode and command allow/deny lists, enforced at the edge
The browser terminal and MCP pass through the edge, so a disallowed command is stopped on the
way in, not reported after the fact.
What the filter catches
Browser terminal
Each line is checked before it reaches the machine.
MCP run_command
Every call is filtered, even on an E2E machine. Read-only blocks it (403).
File writes under read-only
Reads still work; writes, mkdir, delete and move return 403.
Output redirects under read-only
cat a > /etc/passwd is refused even though cat is allowed.
Where it stops
The filter reads a byte stream, not a parsed shell.
Input inside a full-screen program (an editor, top, less) is not parsed.
A line from history or Tab completion is refused — type the whole command.
A deny list does not see through interpreters (python -c, base64 | sh). Read-only refuses them.
A native ssh client over the link is a raw byte pipe with no filter.
An open console keeps its policy until it reconnects. If the control plane is down, new sessions are refused.
A hard stop on accidents, a speed bump on intent. For a real boundary, give the machine an account that can’t do damage — or don’t publish it. Read the security model
Read only
Only reading commands (ls, cat, df…) in the browser terminal. MCP can read files but not run commands.
Allow and deny lists
Permit some commands or ban others. Lists only narrow, never widen read-only.
Session recording
Off, commands only, or the full session as an asciinema cast (Team). Input is not recorded.
End-to-end encryption
The key never leaves the machine. Browser terminal and HTTP links are off; MCP traffic is not covered.
Scoped API tokens
read, tunnels:write and connect. Stored hashed, revocable any time.
Audit log
Who opened a link, when and from where. Link changes are not logged yet.
Four protocols, one outbound socket.
SSH, TCP, UDP and HTTP over one outbound connection
Publish with --expose proto:host:port;
each protocol reaches the world its own way.
ssh
Browser terminal · ssh via linkport connect (ProxyCommand) · MCP. No raw port is opened for SSH.
http
Its own HTTPS origin at /h/<id>/ (wildcard DNS and TLS). WebSocket upgrade is a per-link flag.
tcp
A dedicated port on the edge. Knock first, then an IP allowlist.
udp
A dedicated port on the edge. Pro and Team plans.
What people do instead, and what it costs them.
linkport vs an SSH bastion, Tailscale, Cloudflare Tunnel and ngrok
A jump box, a VPN mesh and an HTTP tunnel each solve part of this. An SSH client alone needs a
reachable address first.
SSH client alone (Termius, PuTTY)
Inbound ports
Needs a reachable address: an open port, a VPN or a jump host
Protocols
SSH and SFTP
MCP / agents
—
Desktop SSH client
It is the client
E2E tunnel
SSH itself
Command policy
—
Revoking access
Remove the key from the server
SSH bastion / open port 22
Inbound ports
Required
Protocols
SSH
MCP / agents
Hand it your private key
Desktop SSH client
Any ssh client
E2E tunnel
Depends on the host
Command policy
Whatever sshd can do
Revoking access
Edit sshd, rotate keys
Tailscale / WireGuard
Inbound ports
None
Protocols
Mesh IP, then whatever you run
MCP / agents
Once the agent host is enrolled
Desktop SSH client
On every device
E2E tunnel
WireGuard
Command policy
None on the wire
Revoking access
Remove the node
Cloudflare Tunnel / ngrok
Inbound ports
None
Protocols
Mostly HTTP(S)
MCP / agents
HTTP only, no typed shell tools
Desktop SSH client
Not an SSH workstation
E2E tunnel
To the edge, not app-held keys
Command policy
HTTP rules, not commands
Revoking access
Close the tunnel
linkport
Inbound ports
None
Protocols
SSH, TCP, UDP, HTTP
MCP / agents
Native, 15 tools over MCP
Desktop SSH client
linkport Terminal on Pro & Team
E2E tunnel
X25519 + ML-KEM-768, optional
Command policy
Read-only and lists at the edge
Revoking access
Revoke refuses new connects
Approach
Inbound ports
Protocols
MCP / agents
Desktop SSH client
E2E tunnel
Command policy
Revoking access
SSH client alone (Termius, PuTTY)
Needs a reachable address: an open port, a VPN or a jump host
SSH and SFTP
—
It is the client
SSH itself
—
Remove the key from the server
SSH bastion / open port 22
Required
SSH
Hand it your private key
Any ssh client
Depends on the host
Whatever sshd can do
Edit sshd, rotate keys
Tailscale / WireGuard
None
Mesh IP, then whatever you run
Once the agent host is enrolled
On every device
WireGuard
None on the wire
Remove the node
Cloudflare Tunnel / ngrok
None
Mostly HTTP(S)
HTTP only, no typed shell tools
Not an SSH workstation
To the edge, not app-held keys
HTTP rules, not commands
Close the tunnel
linkport
None
SSH, TCP, UDP, HTTP
Native, 15 tools over MCP
linkport Terminal on Pro & Team
X25519 + ML-KEM-768, optional
Read-only and lists at the edge
Revoke refuses new connects
Other products change; check their current docs before you decide.
What you’d want to know before running this on your box.
Do I have to open a port on my firewall?
No. The agent keeps one outbound TLS connection to the edge on port 443. Nothing on your machine listens for the internet.
Does it work behind CGNAT or a corporate NAT?
Yes. Every connection is outbound, so CGNAT, double NAT and strict egress make no difference as long as port 443 is reachable.
Does it work on a Raspberry Pi?
Yes, with a 64-bit OS: linkport-agent runs on Linux x86_64 and aarch64 under systemd. 32-bit Raspberry Pi OS (armv7) is not supported, and neither are macOS and Windows as hosts.
Am I really supposed to pipe your script into sudo?
You do not have to. Fetching the script does not use up the token: curl -fsSL <link> -o install.sh, read it, then sudo sh install.sh. It verifies the agent download, prints the service user before changing anything and leaves sudoers alone. Browser and MCP commands run with that user’s permissions.
How is this different from WireGuard or a VPN mesh?
A VPN joins every device to one network. linkport puts one service on one URL: nobody enrolls, and the person you share with reaches only what you published.
Is SSH exposed as a raw port on the internet?
No. SSH is reached through the browser terminal, a WebSocket tunnel used as an ssh ProxyCommand, or MCP. Only tcp: and udp: publications get a port on the edge, behind a knock and an IP allowlist.
Can I let an AI agent use my servers safely?
Read-only mode and command lists are built for that: the agent gets typed MCP tools instead of your private key, and the edge checks commands before they reach the shell. The filter is a hard stop on accidents and a speed bump on intent, not a security boundary — on a machine that matters, pair it with an account that cannot do damage.
What happens if a link leaks?
A 256-bit id cannot be guessed, and a link can also require a password or a signed-in account and expire. Rotate or revoke it if in doubt. Caveats: the link password is stored in plain text and not rate-limited, and revoking does not close sessions already open.
Can the server read my session?
By default the edge terminates TLS — that is what makes the browser terminal and the command filter possible. With end-to-end encryption the key never leaves the machine and the tunnel is opaque to us, but the browser terminal and HTTP links are off, and MCP commands and file transfers still cross the edge in the clear.
How do I remove the agent?
sudo systemctl disable --now linkport-agent, then delete /etc/systemd/system/linkport-agent.service, /usr/local/bin/linkport, /etc/linkport and /etc/sudoers.d/linkport. Deleting the machine in the dashboard revokes its links.
What happens to my machine if linkport goes down?
Links stop resolving and the agent retries until the edge is back. Nothing on the machine changes — the agent only dials out.
How do paid plans work?
Pro and Team are prepaid for 30 days or a year (30% off), paid in cryptocurrency through Heleket; Stripe card payments are planned. Nothing renews automatically: when the period ends, machines stay connected but new ones need an active plan. No refunds — details are in the public offer.
What is the desktop terminal?
linkport Terminal is a desktop SSH client for Windows, macOS and Linux. It signs in with a short code you confirm in the browser and opens a real SSH session through a linkport tunnel. The download is public; using it needs Pro or Team.
Is linkport Terminal an alternative to Termius?
For desktop SSH, yes: SSH, SFTP, split panes, snippets and a key vault on Windows, macOS and Linux, and it imports your hosts from Termius. It also reaches machines behind NAT through a linkport link, and its AI assistant runs on your own key or a local model. There are no mobile apps, and using it needs Pro or Team.
Can I import my hosts from Termius or PuTTY?
Yes. linkport Terminal imports from ~/.ssh/config, PuTTY (a .reg file or the Windows registry), Termius, MobaXterm, SecureCRT and Royal TS, with a preview before anything is added. Saved passwords are not imported: other clients store them reversibly, so you type them once.
Does linkport Terminal work with servers that are not behind NAT?
Yes. It connects straight to any SSH server you can reach, through a jump-host chain or a proxy, as well as through a linkport link.
Which AI models can the assistant use?
Your own OpenAI, Anthropic or Gemini key, or a local model. Read-only checks run by themselves; anything that changes the machine waits for your Run unless you turn on YOLO for a host with Change access.