Section: Overview
Documentation
Overview
linkport publishes SSH, TCP, UDP and HTTP from a machine behind NAT. The connector only dials out on port 443 — no inbound ports, no public IP.
- Connector.
linkport-agentproxies only the local addresses you publish. - Console links. A 256-bit link opens a browser terminal, a raw tunnel or an HTTP origin.
- linkport Terminal. A desktop SSH client over the same tunnel. Pro and Team.
- MCP server.
linkport-mcp: 15 typed tools, hosted or local--stdio.
Quick start
In the dashboard, click Connect a machine and run the one-time command (valid for 30 minutes) on a Linux host, x86_64 or aarch64:
curl -fsSL https://linkport.cloud/i/<token> | sudo shRead it first
Fetching the script doesn’t use up the token, so you can inspect it before running. It checks the agent’s SHA-256 and leaves sshd, sudoers and the firewall alone.
curl -fsSL https://linkport.cloud/i/<token> -o install.sh && cat install.shCustom publications
Repeat --expose proto:host:port[:name] for ssh, tcp, udp or http. The default
is ssh:127.0.0.1:22.
linkport run --edge tls://edge.linkport.cloud:443 --expose ssh:127.0.0.1:22:ssh --expose tcp:127.0.0.1:5432:postgres --expose http:127.0.0.1:3000:grafanaRemoving the agent
sudo systemctl disable --now linkport-agent && sudo rm -rf /etc/systemd/system/linkport-agent.service /etc/linkport /usr/local/bin/linkport /etc/sudoers.d/linkportConnector
linkport-agent runs on Linux x86_64 and aarch64; there is no Mac or Windows
agent. It opens no inbound listener. CONNECT-only proxies are not supported.
Transport
- WebSocket
GET /agent/wsover TLS 443. The token travels in a Hello frame, not the URL. - Or direct TLS with ALPN
linkport/1(tls://host:443) — lighter, but fails behind a CDN or WAF that drops that ALPN. - The edge terminates 443 itself, with no extra reverse proxy.
Service user
Shown before the installer changes anything: LP_RUN_AS if set, otherwise SUDO_USER or the current user — possibly root. No system user is created;
console commands and MCP run_command run with that account’s permissions.
Files
/etc/linkport/agent.env(0600):LP_EDGE_ADDR,LP_AGENT_TOKEN,LP_EXPOSE,LP_API_URL./etc/systemd/system/linkport-agent.servicewithRestart=always,RestartSec=3.- A
.sigcheck runs only when/etc/linkport/release.puborLP_AGENT_VERIFY_KEYis set.
Console links
Each publication gets its own 256-bit link. It can require a password, specific emails, a TTL or a use count.
- SSH in the browser. xterm.js over WebSocket. Off in E2E mode.
- HTTP. Origin
https://p-<link>.apps.<domain>/, WebSocket upgrade withws_enabled. Needs wildcard DNS and TLS. - TCP and UDP. Knock first; the caller IP is then allowlisted.
- Rotate. The old URL dies at once; the tunnel stays.
- Revoke. New connections are refused; open sessions run until the client disconnects.
- Password. Stored in plain text and not rate-limited — a speed bump, not a secret.
- Access channels.
web,web_public,mcp,from_admin, set per machine. Withmcpoff, MCP tools return 403.
linkport Terminal
Desktop SSH client for Windows, macOS and Linux, included with Pro and Team: SSH over the
link, split panes, two-pane SFTP, a local vault (Argon2id + OS keychain), import from ~/.ssh/config, PuTTY, Termius and MobaXterm.
Device-code sign-in
On first launch the app shows an 8-character code. Approve it at linkport.cloud/device while signed in. The app never sees your password.
Edge command policy does not apply here: native SSH over the tunnel is a raw byte pipe.
Recordings stay on the device as .cast.
MCP integration
linkport-mcp speaks MCP 2024-11-05. Hosted: POST /mcp with Authorization: Bearer lp_…. Local: linkport-mcp --stdio with LP_TOKEN, launched by your client — no listening socket.
Cursor (hosted)
In .cursor/mcp.json, with a key from API & MCP keys:
{
"mcpServers": {
"linkport": {
"url": "https://linkport.cloud/mcp",
"headers": {
"Authorization": "Bearer lp_…"
}
}
}
}Claude Desktop and local stdio
For claude_desktop_config.json or any client that spawns a stdio server. Only
local mode can upload your own files with local_path; set LP_MCP_LOCAL_FILES=1 only on a machine you trust.
{
"mcpServers": {
"linkport": {
"command": "linkport-mcp",
"args": [
"--stdio"
],
"env": {
"LP_TOKEN": "lp_…",
"LP_API_URL": "https://linkport.cloud",
"LP_EDGE_URL": "https://linkport.cloud",
"LP_LINK_BASE": "https://linkport.cloud",
"LP_MCP_LOCAL_FILES": "1"
}
}
}
}All 15 tools
The last column shows what a read-only machine allows. Control-plane tools such as list_machines and rotate_link ignore the flag.
| Tool | Group | Arguments | Read-only |
|---|---|---|---|
| list_machines | Machines | — | n/a |
| list_tunnels | Links | agent_id | n/a |
| create_tunnel | Links | agent_id, name, proto, local_addr, … | n/a |
| revoke_link | Links | tunnel_id | n/a |
| rotate_link | Links | tunnel_id | n/a |
| get_connection_info | Links | link_id | n/a |
| run_command | Commands | agent_id or link_id, command, timeout_secs? | 403 |
| list_files | Files | agent_id or link_id, path? | allowed |
| stat_file | Files | agent_id or link_id, path | allowed |
| read_file | Files | path, offset?, max_bytes? (≤ 8 MiB) | allowed |
| write_file | Files | path, content? / local_path? | 403 |
| make_dir | Files | path, parents? | 403 |
| delete_file | Files | path, recursive? | 403 |
| move_file | Files | path, to | 403 |
| install_command | Machines | access[]?, e2e? | n/a |
Access control & guardrails
Read-only mode, command allow/deny lists and session recording. The filter runs at the
edge for the browser terminal and MCP run_command.
Read-only
- Browser terminal: only reading commands run (
ls,cat,grep…). Shells, editors,sudo,curland output redirects are refused. - Raw and WebSocket tunnels to non-HTTP publications are blocked.
- MCP:
run_command,write_file,make_dir,delete_fileandmove_filereturn 403; list, stat and read still work. - HTTP apps keep their own auth; the flag does not make their filesystem read-only.
What the filter can’t catch
It reads a byte stream, not a parsed shell — a hard stop on accidents, a speed bump on intent.
- Input inside a full-screen program (an editor, top, less) is not parsed.
- A line recalled from history or completed with Tab is refused — type the whole command.
- A deny list doesn’t see through interpreters (
python -c,base64 | sh, an uploaded script). Read-only refuses interpreters. - A native ssh client over the link is a raw byte pipe with no filter.
- An open console keeps its policy until it reconnects. With the control plane unreachable, new sessions, commands and file changes are refused.
Session recording
Off, commands only, or full session (asciinema v2, Team plan). Input is never recorded. Files live on a local volume, not object storage.
End-to-end encryption
Enable at install with LP_E2E=1. The key is generated on the machine and never
leaves it; the server keeps only a SHA-256 fingerprint. X25519 + ML-KEM-768, HKDF-SHA256,
ChaCha20-Poly1305. Keys look like lpe2e1_….
ssh -o ProxyCommand='linkport connect https://linkport.cloud/s/<link_id> --e2e' deploy@hostThe edge can’t filter what it can’t read, so E2E turns off the browser terminal and HTTP links. MCP commands and file transfers still cross the edge in the clear — they use the agent control channel, not the tunnel.
Troubleshooting
Machine never appears
sudo systemctl status linkport-agent && journalctl -u linkport-agent -n 50 --no-pagerInstall tokens expire after 30 minutes — generate a new command in the dashboard.
Machine shows offline
The agent reconnects with backoff. If it stays offline, check that outbound TCP 443 is allowed; CONNECT-only proxies are not supported.
Publication refused
New publications apply on the next agent connect. Restart to apply now:
sudo systemctl restart linkport-agentA command is refused in the console
Check read-only mode and the allow/deny lists. Lines from history or Tab completion are refused too — type the full command.
Still stuck? Write to [email protected] with the machine name and the output of the first command above. Security issues: [email protected].