A computer has no address of its own, and nothing outside can reach it until you ask. The ways in: a shell from your own terminal, SSH (for VS Code, Cursor, scp and rsync too), files copied in and out, a port you share on the web, a TCP port on the internet, and the project's private network from your laptop.
Three ways in go through Alf, with nothing open on the internet. A shell: alf shell (or the dashboard) goes through Alf to the computer's server and opens a shell as dev. SSH: alf ssh goes the same way to the computer's SSH server on port 22. A shared port: anyone with the address, like …--5173.smartalfred.com, goes through Alf to the server and to localhost:5173 inside the computer. Two go straight to the computer's server. A public port: any client connects to the server's IP on a port between 20000 and 29999, and only the addresses on the allowlist get through to the port. Network access: alf connect joins your laptop to the project's network over WireGuard (UDP 51820), and every port of the computer is reachable.
With the command-line tool, it's one command, which the computer's page shows along the bottom (Connect from your own terminal) with its name filled in:
alf shell shop/computer
Without installing anything, Or a one-time line, nothing to install there gives you a line to paste instead:
curl -fsSL https://runalf.com/connect.sh | sh -s -- 'wss://api.runalf.com/api/v1/sessions/attach?token=…'
It opens a shell in the same container as the one on the computer's page, so what you start in one is there in the other. The window follows your terminal's size, and the shell's exit code is the command's.
python3 on your machine, which does the talking. Nothing is installed and nothing is left behind.Closing the terminal — here or on the computer's page — ends that shell and what it was running in the foreground. The computer carries on, and so does anything you started to outlive the shell.
A shell is where you build the thing you then want somebody to look at. Start it on a port — npm run dev, say — and share that port: it gets an https address of its own.
alf share 5173
prints the address, https://<computer>-<project>-<organization>--5173.smartalfred.com. It answers within about 15 seconds, for as long as something listens on the port.
localhost. A shared port is reached from inside the computer, so that's fine as it is: no --host 0.0.0.0 needed.Host: localhost:<port>, which Vite, webpack's dev server and Angular's accept, with the address the visitor used in X-Forwarded-Host. Hot reload over WebSockets works.alf ports shows the same in the terminal; alf unshare 5173 takes a port off again.alf share, so asking an agent to "show me" ends in an address you can open.Anyone with the address can reach the port. Nothing is shared until you or something in the computer asks. Share every port automatically, under Ports, shares each port as something starts listening on it, except debuggers' (9229, 9222), databases' (5432, 3306, 6379, 27017) and SSH's — a debugger's port lets whoever finds it run code in the computer. Those can still be shared by name.
What you build in a computer goes to production as a service in the project, with its own domain there.
Every computer has an SSH server, reached through Alf — nothing is open to the internet, and whoever may open a shell in it may SSH into it. With the command-line tool:
alf ssh shop/computer
logs you in as dev, the computer's user, with sudo. Anything after the name goes to ssh: alf ssh shop/computer -L 3000:localhost:3000 forwards your port 3000 to the computer's, -A forwards your SSH agent (for git push from the computer with your own key), and alf ssh shop/computer uptime runs one command.
For everything else that speaks SSH, make the computer an SSH host once:
alf ssh-config shop/computer --add
It goes into ~/.ssh/config as computer.shop.smartalfred, and then ssh computer.shop.smartalfred, scp notes.txt computer.shop.smartalfred:, rsync -a site/ computer.shop.smartalfred:site/ work, and so does Remote-SSH: Connect to Host… in VS Code or Cursor, with the editor's server running in the computer. Without --add it prints the entry for you to put there yourself.
~/.ssh/authorized_keys in the computer.ssh (or VS Code, scp, rsync) runs alf as its ProxyCommand. The tool puts its own key in the computer's authorized_keys, then opens a stream signed in as you: a WebSocket over HTTPS to Alf, and on from there over the connection the computer's server keeps open. In the computer, alf pipe 22 connects that stream to the computer's SSH server on port 22, which is never on the internet, and it logs you in as dev. SSH runs end to end inside the stream, from your ssh to the computer's SSH server: Alf only carries the bytes. Whoever may open a shell in the computer may SSH into it.
alf cp ./site shop/computer: # into /workspace
alf cp ./notes.txt shop/computer:/tmp/
alf cp shop/computer:report.pdf . # out
One side is the computer and a path in it, as with scp; a path that isn't absolute is in /workspace, and a folder goes with everything in it. In the dashboard, drop files on the computer's shell to copy them into /workspace, or use Files at the top of its page for another folder, and to download a file (a folder comes as a .tar).
For something that isn't HTTP — a database you're trying out, a game server, an SSH server of a different kind — Settings → Public ports opens a TCP or UDP port on the computer's server to the addresses you allow, as for any service. It reaches the computer's port even if what listens there only listens on localhost.
With network access, your laptop joins the computer's project network, and every port of the computer is reachable at its own name while it runs, without sharing anything on the web:
alf connect shop --all
Then any program at computer.shop.internal (computer being the computer's name, shop its project's) — ssh dev@computer.shop.internal included, with a key in its ~/.ssh/authorized_keys. Making the network interface needs sudo; the names go into /etc/hosts and come out again when you leave.