Servers and containers
Making a server, a VM or a container a device your others reach, with nobody there. Servers need only alto (the command and its server); the app is for the devices people sit at.
One command
Section titled “One command”alto setup --trust "*@example.com"It:
- turns remote access on (over Tailscale only);
- lets in, without pairing, what each
--trustnames: a Tailscale tag (tag:ci), a person (sam@example.com) or a domain (*@example.com). A tagged server belongs to nobody’s account, so it needs one of these, or pairing, before anyone reaches it; - installs the login service, so the server starts with the device (systemd user unit, LaunchAgent, Run key);
- on Linux, turns on lingering, so that service runs with nobody logged in. Turning it on for yourself may need root: setup says so, with the command (
sudo loginctl enable-linger USER); - waits until the server listens on Tailscale, and says how other devices reach it.
Run it again whenever: what’s already so is reported and left alone, and nothing is restarted. Other ways to run it:
--no-autostart: start the server now, but not again after a restart; nothing is installed.--foreground: after setting up, keep running the server as this process, in the foreground: a container’s main process. Nothing is installed.
On the devices that should reach it, if it’s tagged: alto devices trust tag:ci (or Settings → Devices shows it once trusted). Then alto --on NAME new …, or New tab on NAME in the app.
Tailscale
Section titled “Tailscale”See Remote access with Tailscale for how access works.
Tailscale does the networking and says who’s who. For a server, make an auth key in the admin console (Settings → Keys) with the server’s tag, pre-approved, and, for machines that come and go, ephemeral. The tag needs an owner in the access policy:
"tagOwners": { "tag:agents": ["autogroup:admin"] },and, if the policy doesn’t already allow everything, a rule letting people reach it on Alto’s port:
{ "src": ["autogroup:member"], "dst": ["tag:agents"], "ip": ["tcp:7655"] }cloud-init
Section titled “cloud-init”Until there are packages (planned), put a Linux build of alto where the VM can fetch it (ALTO_URL below). The user agent runs the agents; its server starts at boot through its systemd user service.
#cloud-configusers: - name: agent shell: /bin/bashruncmd: - curl -fsSL https://tailscale.com/install.sh | sh - tailscale up --authkey=TS_AUTHKEY --advertise-tags=tag:agents --hostname=gpu-1 - curl -fsSL -o /usr/local/bin/alto ALTO_URL && chmod 755 /usr/local/bin/alto - loginctl enable-linger agent - su - agent -c 'XDG_RUNTIME_DIR=/run/user/$(id -u) alto setup --trust "*@example.com"'XDG_RUNTIME_DIR lets su reach the user’s systemd, which lingering started. Checked 2026-11-08 in a container running systemd: the service installed, and after a restart with nobody logged in the server was running again, with the session from before shown as ended, its screen saved.
A container
Section titled “A container”The server is the main process (--foreground), so the container lives as long as it does. Tailscale runs inside (it needs the TUN device: --cap-add=NET_ADMIN --device /dev/net/tun), and the server listens on its address.
FROM ubuntu:24.04RUN apt-get update && apt-get install -y --no-install-recommends curl ca-certificates iptables \ && curl -fsSL https://tailscale.com/install.sh | sh && rm -rf /var/lib/apt/lists/*COPY alto /usr/local/bin/altoCOPY start.sh /start.shCMD ["sh", "/start.sh"]# start.sh: Tailscale with the key given at run time, then Alto.tailscaled --state=mem: &tailscale up --authkey="$TS_AUTHKEY" --advertise-tags=tag:agents --hostname="${NAME:-agent-box}"exec alto setup --trust "*@example.com" --foregrounddocker run -d --cap-add=NET_ADMIN --device /dev/net/tun -e TS_AUTHKEY=tskey-auth-… my-agent-boxWith --state=mem: and an ephemeral key, the device leaves the tailnet when the container stops. Sessions run inside the container, so they end with it; keep their work in a mounted folder. Checked 2026-11-08: such a container on a real tailnet was reached from a Mac trusting its tag, and setup --foreground runs the server as process 1.
Updating
Section titled “Updating”Replace the alto file; the server notices within seconds and hands over to the new build, its sessions running on. In a container, rebuild the image instead: replacing the file inside works too, but is lost with the container.