looper

Linux over Tailscale

Your Mac and iPhone can reach Looper on the Linux host. The host cannot start connections to other tailnet devices. Internet access still works.

1. Set the policy

Download the policy template. Replace the example addresses: .10 is your Mac, .11 your iPhone, .20 the Linux host, and .21 another host. All use the 100.64.0 prefix.

Merge the template into your existing policy, preserving unrelated settings. It allows only TCP 8765, TCP 8766, and UDP 8766 from your two controllers to tag:looper-bot. Port 8765 also permits pairing; use trusted devices.

This policy grants no SSH access. Use the local or hosting-provider console for setup. On a shared LAN, use a separate VM/VLAN or an egress firewall too: Tailscale policy controls tailnet traffic.

2. Set up Linux

Use an ordinary user with Tailscale authenticated and nftables installed. Download these files into one directory:

Firewall · Firewall service · Looper service override · Environment

Replace the Mac and iPhone addresses in the firewall. It allows loopback and those two devices through tailscale0, then drops other Looper ingress. Keep Looper's wildcard listeners: its local CLI and hooks need loopback.

Linux setup commands

Clear routing roles and disable Tailscale SSH:

sudo tailscale set --accept-routes=false --advertise-routes= \
  --advertise-exit-node=false --advertise-connector=false \
  --exit-node= --ssh=false --webclient=false

Validate and install the firewall. The service expects nft at /usr/sbin/nft.

sudo nft -c -f looper-ingress.nft
sudo install -d -m 755 /etc/nftables.d
sudo install -m 644 looper-ingress.nft /etc/nftables.d/looper-ingress.nft
sudo install -m 644 looper-ingress.service /etc/systemd/system/looper-ingress.service
sudo systemctl daemon-reload
sudo systemctl enable --now looper-ingress.service

Download the Linux archive and checksum, then install without starting the server:

LOOPER_ARCHIVE='replace-with-downloaded-linux-archive.tar.gz'
sha256sum -c "$LOOPER_ARCHIVE.sha256"
tar -xzf "$LOOPER_ARCHIVE"
bash looper-linux/looper-linux.sh install --no-start
export PATH="$HOME/.local/bin:$PATH"
install -d -m 700 "$HOME/.config/looper"
install -d -m 700 "$HOME/.config/systemd/user/looper.service.d"
install -m 644 tailscale.conf "$HOME/.config/systemd/user/looper.service.d/tailscale.conf"

For a new installation, copy server.env.example to ~/.config/looper/server.env with mode 600. For an existing installation, merge its three listener settings; retain the store path and other settings. --no-start leaves an existing process running.

systemctl --user daemon-reload
systemctl --user enable looper.service
systemctl --user restart looper.service
curl --fail --max-time 3 http://127.0.0.1:8765/health

The override runs serve --tailscale. Its user needs access to the local Tailscale daemon. For startup after logout, an administrator can run sudo loginctl enable-linger "$USER".

If your firewall manager flushes nftables on reload, integrate this file with that manager. Check sudo nft list table inet looper_ingress after reload and reboot; an active service alone does not prove the rules exist.

3. Run Grok and pair

Install and authenticate Grok Build as the same user. Back up existing hooks, then run:

looper hooks register grok
# From your project directory:
looper grok

On iPhone, connect Tailscale. In Looper, choose Add Computer, enable Tailscale, and enter the host's IP or full .ts.net name. Choose Open Server Pairing Page and enter the generated four-letter code. For an already paired host, select its Tailscale route.

Check access from your approved Mac, using the host's real address:

curl --fail --max-time 3 http://100.64.0.20:8765/health

Then verify:

Troubleshooting · Linux installation · Docs