Isomux docs Run a public office with Tailscale Funnel

Run a public office with Tailscale Funnel#

This is the Public Tailscale Funnel guide. To check if this is the right hosting setup for you, check the decision diagram.

Use a Linux computer with systemd, a normal user account with sudo, and an AI provider account. Keep it powered on. Funnel gives the office a public HTTPS address without a domain or router forwarding. Visitors do not need Tailscale, but they still need an Isomux sign-in link.

Install Isomux#

Run these steps on the computer that will run the office, in a terminal under its normal user account.

  1. Install Git. On Ubuntu or Debian:

    sudo apt update
    sudo apt install -y git curl unzip
    

    On macOS, run xcode-select --install and complete the installer.

  2. Install Bun:

    curl -fsSL https://bun.sh/install | bash
    

    Open a new terminal so that the shell can find Bun. Check its version:

    bun --version
    

    Bun must be at least version 1.3.11.

  3. Download Isomux into a new directory and start it:

    git clone https://github.com/nmamano/isomux.git
    cd isomux
    bun install
    bun run dev
    

    Leave this terminal open.

A Chrome-family browser installed on this computer also enables page-preview cards. It is optional for office setup.

Create the first owner#

When Isomux starts with no owner, it prints a setup link in its terminal and log, such as http://localhost:4000/setup#key=.... On the computer running Isomux, open that link in a browser. Enter your display name and submit the form. The office opens.

If the server has no browser, keep its Isomux terminal running. On your laptop, open another terminal and run the following, replacing USER and SERVER with your server login and address:

ssh -L 4000:localhost:4000 USER@SERVER

Keep this connection open and open the setup link in your laptop's browser. Port 4000 on your laptop must be free.

The link carries the setup key, which is also in ~/.isomux/setup-key on the server. The office accepts its first owner only with this key. Set up remote access after you have opened the office as its owner.

Keep the office running#

These steps use Linux with systemd. Turn off sleep in the power settings.

After you have created the owner, press Ctrl+C in the terminal running bun run dev. In that terminal, from the Isomux directory, run:

mkdir -p "$HOME/.config/systemd/user"
cat > "$HOME/.config/systemd/user/isomux.service" <<UNIT
[Unit]
Description=Isomux office
After=network.target
StartLimitIntervalSec=0

[Service]
WorkingDirectory="$PWD"
Environment="PATH=$HOME/.bun/bin:$HOME/.local/bin:/usr/local/bin:/usr/bin:/bin"
ExecStart="$HOME/.bun/bin/bun" run dev
Restart=on-failure
RestartSec=5s
OOMPolicy=continue

[Install]
WantedBy=default.target
UNIT
systemctl --user daemon-reload
systemctl --user enable --now isomux
sudo loginctl enable-linger "$USER"
systemctl --user status isomux --no-pager

The status should show active (running) after the UI builds. Lingering keeps the service running after logout and starts it at boot. If startup fails, read its log with journalctl --user -u isomux -n 50 --no-pager.

Install Tailscale on your devices#

Create a Tailscale account. On the Linux server, run:

curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up

Open the sign-in link printed in the terminal and add the server to your account. Install Tailscale on your laptop and phone, and sign in to the same account on each device. Keep Tailscale connected.

Open the Tailscale DNS settings. Enable MagicDNS and HTTPS Certificates. HTTPS certificates put the server's *.ts.net name in public certificate records, even when access stays private.

On the server, allow your Linux user to manage Tailscale:

sudo tailscale set --operator="$USER"

Make the office public#

Funnel depends on Tailscale's service and its bandwidth limits. Sign in as a Tailscale owner, admin, or network admin for the authorization step below.

On the server, inspect the current mappings:

tailscale serve status
tailscale funnel status

A port is all-private Serve or all-public Funnel. If port 443 has mappings besides Isomux at localhost:4000, stop. Decide whether to remove each mapping or move it to another port before you continue. Do not expose another service by accident.

Run this yourself in the server terminal. Agents refuse tunnel commands:

tailscale funnel --bg http://localhost:4000

If the command prints an authorization link, open it in your browser and approve enabling Funnel. Tailscale adds the required funnel attribute to the tailnet policy. The default permits tailnet members to use Funnel. To enable it through the admin console instead, open Access controls, expand Funnel, and select Add Funnel to policy. Preserve any existing access policy.

Copy the public HTTPS address from the output. You can read it again with tailscale funnel status. Tailscale relays the connection; TLS terminates on your computer. The *.ts.net name is public and appears in certificate records. See the Funnel reference for custom policy and service limits.

Sign in at the new address#

In the local office, open Settings → Office → Access. Enable External access, paste the HTTPS office address into Public URL, and save. Copy the sign-in link that the pane gives you before restarting.

On the server, run:

systemctl --user restart isomux

Open the copied sign-in link in the browser where you will use the office. Keep the HTTPS office address as your bookmark; sign-in links work only once.

Test the address on a phone with Wi-Fi and Tailscale turned off. A request from the server itself does not prove that public access works.

Connect a provider and send a message#

In the office, open Integrations → Model providers.

  • For Claude or Codex, select the provider's sign-in control and follow the steps. Both ship bundled with Isomux.
  • For OpenCode, open or create an OpenCode agent and choose a model. Its model picker offers Free, Pay-as-you-go, and Subscription options. Free models need no paid account.
  • For a provider API key, add its environment variable on the Variables tab: ANTHROPIC_API_KEY, OPENAI_API_KEY, or OPENCODE_API_KEY, as applicable.

Open an agent that uses the connected provider and send a short message. A reply confirms that the office can use your provider account. Provider charges and subscription limits are separate from hosting.

For Claude through Amazon Bedrock or another connection method, use the provider reference.

Add people and devices#

For another device of your own, open Settings → You → Sign-in links and create a device link. Open it on that device.

To invite another person, first create them: in Settings, select New member at the end of the Members list, fill in the form and select Create member. Then open Settings → Office → Invites, select them and create a sign-in link. Send the link privately. Only invite people you trust: members and their agents can run commands on the server with the office's operating-system permissions.

On iPhone, open the office in Safari and select Share → Add to Home Screen. On Android, open the HTTPS office address in Chrome and use its install option.

App addresses#

Funnel exposes the office port only. Tailscale names do not provide wildcard app hostnames, so this setup does not give each app a public address. App port links remain usable from devices with direct or private Tailscale access to the server. Choose the domain setup if each app needs its own public HTTPS address.

Updates and logs#

To update, finish active agent work first. On the server, from the Isomux checkout, run:

systemctl --user stop isomux
git pull --ff-only
bun install
systemctl --user start isomux

The service rebuilds the UI when it starts. Reload the browser after it starts. A stop or restart interrupts active agent turns.

Read office logs with:

journalctl --user -u isomux -n 50 --no-pager

For memory protection, browser control, and deployment boundaries, see the hosting reference.

Backups#

Isomux stores seven daily backups of ~/.isomux/ in the server's backup directory on the same disk as the office, so copy them elsewhere if you need protection from server loss. Current backup health and the exact directory are at GET /api/backup/status.