# Tailscale

Connect your Toes appliance to your Tailscale network for secure access from anywhere.

Tailscale is pre-installed on the appliance but not configured. The user authenticates through the dashboard or CLI — no SSH required.

## how it works

1. User clicks "Connect to Tailscale" in the dashboard (or runs `toes tailscale connect`)
2. Toes runs `tailscale login` and captures the auth URL
3. Dashboard shows the URL and a QR code
4. User visits the URL and authenticates with Tailscale
5. Toes detects the connection, runs `tailscale serve --bg 80`
6. Appliance is now accessible at `https://<hostname>.<tailnet>.ts.net`

## dashboard

Settings area shows one of three states:

**Not connected:**
- "Connect to Tailscale" button

**Connecting:**
- Auth URL as a clickable link
- QR code for mobile
- Polls `tailscale status` until authenticated

**Connected:**
- Tailnet URL (clickable)
- Tailnet name
- Device hostname
- `tailscale serve` toggle
- "Disconnect" button

## cli

```bash
toes tailscale              # show status
toes tailscale connect      # start auth flow, print URL, wait
toes tailscale disconnect   # log out of tailnet
toes tailscale serve        # toggle tailscale serve on/off
```

### `toes tailscale`

```
Tailscale: connected
Tailnet:   user@github
Hostname:  toes.tail1234.ts.net
IP:        100.64.0.1
Serve:     on (port 80)
```

Or when not connected:

```
Tailscale: not connected

Run `toes tailscale connect` to get started.
```

### `toes tailscale connect`

```
Visit this URL to authenticate:
https://login.tailscale.com/a/abc123

Waiting for authentication... done!
Connected to tailnet user@github
https://toes.tail1234.ts.net
```

## server api

All endpoints shell out to the `tailscale` CLI and parse output.

### `GET /api/tailscale`

Returns current status.

```json
{
  "installed": true,
  "connected": true,
  "hostname": "toes",
  "tailnetName": "user@github",
  "url": "https://toes.tail1234.ts.net",
  "ip": "100.64.0.1",
  "serving": true
}
```

When not connected:

```json
{
  "installed": true,
  "connected": false
}
```

When tailscale isn't installed:

```json
{
  "installed": false
}
```

### `POST /api/tailscale/connect`

Runs `tailscale login`. Returns the auth URL.

```json
{
  "authUrl": "https://login.tailscale.com/a/abc123"
}
```

### `POST /api/tailscale/disconnect`

Runs `tailscale logout`.

### `POST /api/tailscale/serve`

Toggles `tailscale serve`. Body:

```json
{ "enabled": true }
```

## install

`scripts/install.sh` installs tailscale and enables the daemon, but does not authenticate:

```bash
curl -fsSL https://tailscale.com/install.sh | sh
sudo systemctl enable tailscaled
```

## permissions

The `toes` user needs passwordless sudo for tailscale commands. Add to sudoers during install:

```
toes ALL=(ALL) NOPASSWD: /usr/bin/tailscale
```

This lets the server run `sudo tailscale login`, `sudo tailscale serve`, etc. without a password prompt.
