saltylab-firmware/jetson/docs/headscale-vpn-setup.md
sl-jetson 062c05cac0 feat: Add Issue #502 - Headscale VPN auto-connect on Orin
Configure Jetson Orin with Tailscale client connecting to Headscale
coordination server at tailscale.vayrette.com:8180. Device registers
as 'saltylab-orin' with persistent auth key for unattended login.

Features:
- systemd auto-start and restart on WiFi drops
- Persistent auth key storage at /opt/saltybot/tailscale-auth.key
- SSH + HTTP access over Tailscale tailnet (encrypted WireGuard)
- IP forwarding enabled for relay/exit node capability
- WiFi resilience with aggressive restart policy
- MQTT reporting of VPN status, IP, and connection type

Components added:
- jetson/scripts/setup-tailscale.sh: Tailscale package installation
- jetson/scripts/headscale-auth-helper.sh: Auth key management utility
- jetson/systemd/tailscale-vpn.service: systemd service unit
- jetson/docs/headscale-vpn-setup.md: Comprehensive setup documentation
- saltybot_cellular/vpn_status_node.py: ROS2 node for MQTT reporting

Updated:
- jetson/systemd/install_systemd.sh: Include tailscale-vpn.service
- jetson/scripts/setup-jetson.sh: Add Tailscale setup steps

Access patterns:
- SSH: ssh user@saltylab-orin.tail12345.ts.net
- HTTP: http://saltylab-orin.tail12345.ts.net:port
- Direct IP: 100.x.x.x (Tailscale allocated address)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-03-06 10:25:04 -05:00

155 lines
3.1 KiB
Markdown

# Headscale VPN Auto-Connect Setup — Jetson Orin
This document describes the auto-connect VPN setup for the Jetson Orin using Tailscale client connecting to the Headscale server at `tailscale.vayrette.com:8180`.
## Overview
**Device Name**: `saltylab-orin`
**Headscale Server**: `https://tailscale.vayrette.com:8180`
**Primary Features**:
- Auto-connect on system boot
- Persistent auth key for unattended login
- SSH + HTTP over Tailscale (tailnet)
- WiFi resilience and fallback
- systemd auto-restart on failure
## Architecture
### Components
1. **Tailscale Client** (`/usr/sbin/tailscaled`)
- VPN daemon running on Jetson
- Manages WireGuard tunnels
- Connects to Headscale coordination server
2. **systemd Service** (`tailscale-vpn.service`)
- Auto-starts on boot
- Restarts on failure
- Manages lifecycle of tailscaled daemon
- Logs to journald
3. **Auth Key Manager** (`headscale-auth-helper.sh`)
- Generates and validates auth keys
- Stores keys securely at `/opt/saltybot/tailscale-auth.key`
- Manages revocation
4. **Setup Script** (`setup-tailscale.sh`)
- One-time installation of Tailscale package
- Configures IP forwarding
- Sets up persistent state directories
## Installation
### 1. Run Jetson Setup
```bash
sudo bash jetson/scripts/setup-jetson.sh
```
### 2. Install Tailscale
```bash
sudo bash jetson/scripts/setup-tailscale.sh
```
### 3. Generate Auth Key
```bash
sudo bash jetson/scripts/headscale-auth-helper.sh generate
```
### 4. Install systemd Services
```bash
sudo bash jetson/systemd/install_systemd.sh
```
### 5. Start the VPN Service
```bash
sudo systemctl start tailscale-vpn
```
## Usage
### Check VPN Status
```bash
sudo tailscale status
```
### Access via SSH
```bash
ssh <username>@saltylab-orin.tail12345.ts.net
```
### View Logs
```bash
sudo journalctl -fu tailscale-vpn
```
## WiFi Resilience
Automatic restart after WiFi drops with aggressive restart policies:
```ini
Restart=always
RestartSec=5s
StartLimitInterval=60s
StartLimitBurst=10
```
## Persistent Storage
**Auth Key**: `/opt/saltybot/tailscale-auth.key`
**State Directory**: `/var/lib/tailscale/`
## Troubleshooting
### Service Won't Start
```bash
sudo systemctl status tailscale-vpn
sudo journalctl -u tailscale-vpn -n 30
```
### Can't Connect to Headscale
```bash
ping 8.8.8.8
nslookup tailscale.vayrette.com
```
### Auth Key Expired
```bash
sudo bash jetson/scripts/headscale-auth-helper.sh revoke
sudo bash jetson/scripts/headscale-auth-helper.sh generate
sudo systemctl restart tailscale-vpn
```
## Security
- Auth key stored in plaintext at `/opt/saltybot/tailscale-auth.key`
- File permissions: `600` (readable only by root)
- State directory restricted: `700` (only root)
- SSH over tailnet with no ACL restrictions by default
## MQTT Reporting
VPN status reported to MQTT:
```
saltylab/jetson/vpn/status -> online|offline|connecting
saltylab/jetson/vpn/ip -> 100.x.x.x
saltylab/jetson/vpn/hostname -> saltylab-orin.tail12345.ts.net
```
## References
- [Headscale Documentation](https://headscale.net/)
- [Tailscale Documentation](https://tailscale.com/kb)
- [Tailscale CLI Reference](https://tailscale.com/kb/1080/cli)