Initial commit
This commit is contained in:
466
references/sshsync-guide.md
Normal file
466
references/sshsync-guide.md
Normal file
@@ -0,0 +1,466 @@
|
||||
# sshsync CLI Tool Guide
|
||||
|
||||
Complete reference for using sshsync with Tailscale SSH Sync Agent.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [Installation](#installation)
|
||||
2. [Configuration](#configuration)
|
||||
3. [Core Commands](#core-commands)
|
||||
4. [Advanced Usage](#advanced-usage)
|
||||
5. [Troubleshooting](#troubleshooting)
|
||||
|
||||
## Installation
|
||||
|
||||
### Via pip
|
||||
|
||||
```bash
|
||||
pip install sshsync
|
||||
```
|
||||
|
||||
### Verify Installation
|
||||
|
||||
```bash
|
||||
sshsync --version
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### 1. SSH Config Setup
|
||||
|
||||
sshsync uses your existing SSH configuration. Edit `~/.ssh/config`:
|
||||
|
||||
```
|
||||
# Example host entries
|
||||
Host homelab-1
|
||||
HostName 100.64.1.10
|
||||
User admin
|
||||
IdentityFile ~/.ssh/id_ed25519
|
||||
Port 22
|
||||
|
||||
Host prod-web-01
|
||||
HostName 100.64.1.20
|
||||
User deploy
|
||||
IdentityFile ~/.ssh/id_rsa
|
||||
Port 22
|
||||
|
||||
Host dev-laptop
|
||||
HostName 100.64.1.30
|
||||
User developer
|
||||
```
|
||||
|
||||
**Important Notes**:
|
||||
- sshsync uses the **Host alias** (e.g., "homelab-1"), not the actual hostname
|
||||
- Ensure SSH key authentication is configured
|
||||
- Test each host with `ssh host-alias` before using with sshsync
|
||||
|
||||
### 2. Initialize sshsync Configuration
|
||||
|
||||
First run:
|
||||
|
||||
```bash
|
||||
sshsync sync
|
||||
```
|
||||
|
||||
This will:
|
||||
1. Read all hosts from your SSH config
|
||||
2. Prompt you to assign hosts to groups
|
||||
3. Create `~/.config/sshsync/config.yaml`
|
||||
|
||||
### 3. sshsync Config File
|
||||
|
||||
Location: `~/.config/sshsync/config.yaml`
|
||||
|
||||
Structure:
|
||||
```yaml
|
||||
groups:
|
||||
production:
|
||||
- prod-web-01
|
||||
- prod-web-02
|
||||
- prod-db-01
|
||||
development:
|
||||
- dev-laptop
|
||||
- dev-desktop
|
||||
homelab:
|
||||
- homelab-1
|
||||
- homelab-2
|
||||
```
|
||||
|
||||
**Manual Editing**:
|
||||
- Groups are arbitrary labels (use what makes sense for you)
|
||||
- Hosts can belong to multiple groups
|
||||
- Use consistent host aliases from SSH config
|
||||
|
||||
## Core Commands
|
||||
|
||||
### List Hosts
|
||||
|
||||
```bash
|
||||
# List all configured hosts
|
||||
sshsync ls
|
||||
|
||||
# List with online/offline status
|
||||
sshsync ls --with-status
|
||||
```
|
||||
|
||||
**Output Example**:
|
||||
```
|
||||
Host Status
|
||||
homelab-1 online
|
||||
homelab-2 offline
|
||||
prod-web-01 online
|
||||
dev-laptop online
|
||||
```
|
||||
|
||||
### Execute Commands
|
||||
|
||||
#### On All Hosts
|
||||
|
||||
```bash
|
||||
# Execute on all configured hosts
|
||||
sshsync all "df -h"
|
||||
|
||||
# With custom timeout (default: 10s)
|
||||
sshsync all --timeout 20 "systemctl status nginx"
|
||||
|
||||
# Dry-run (preview without executing)
|
||||
sshsync all --dry-run "reboot"
|
||||
```
|
||||
|
||||
#### On Specific Group
|
||||
|
||||
```bash
|
||||
# Execute on group
|
||||
sshsync group production "uptime"
|
||||
|
||||
# With timeout
|
||||
sshsync group web-servers --timeout 30 "npm run build"
|
||||
|
||||
# Filter with regex
|
||||
sshsync group production --regex "web-.*" "df -h"
|
||||
```
|
||||
|
||||
**Regex Filtering**:
|
||||
- Filters group members by alias matching pattern
|
||||
- Uses Python regex syntax
|
||||
- Example: `--regex "web-0[1-3]"` matches web-01, web-02, web-03
|
||||
|
||||
### File Transfer
|
||||
|
||||
#### Push Files
|
||||
|
||||
```bash
|
||||
# Push to specific host
|
||||
sshsync push --host web-01 ./app /var/www/app
|
||||
|
||||
# Push to group
|
||||
sshsync push --group production ./dist /var/www/app
|
||||
|
||||
# Push to all hosts
|
||||
sshsync push --all ./config.yml /etc/app/config.yml
|
||||
|
||||
# Recursive push (directory with contents)
|
||||
sshsync push --group web --recurse ./app /var/www/app
|
||||
|
||||
# Dry-run
|
||||
sshsync push --group production --dry-run ./dist /var/www/app
|
||||
```
|
||||
|
||||
**Important**:
|
||||
- Local path comes first, remote path second
|
||||
- Use `--recurse` for directories
|
||||
- Dry-run shows what would be transferred without executing
|
||||
|
||||
#### Pull Files
|
||||
|
||||
```bash
|
||||
# Pull from specific host
|
||||
sshsync pull --host db-01 /var/log/mysql/error.log ./logs/
|
||||
|
||||
# Pull from group (creates separate directories per host)
|
||||
sshsync pull --group databases /var/backups ./backups/
|
||||
|
||||
# Recursive pull
|
||||
sshsync pull --host web-01 --recurse /var/www/app ./backup/
|
||||
```
|
||||
|
||||
**Pull Behavior**:
|
||||
- When pulling from groups, creates subdirectory per host
|
||||
- Use `--recurse` to pull entire directory trees
|
||||
- Destination directory created if doesn't exist
|
||||
|
||||
### Group Management
|
||||
|
||||
#### Add Hosts to Group
|
||||
|
||||
```bash
|
||||
# Interactive: prompts to select hosts
|
||||
sshsync gadd production
|
||||
|
||||
# Follow prompts to select which hosts to add
|
||||
```
|
||||
|
||||
#### Add Host to SSH Config
|
||||
|
||||
```bash
|
||||
# Interactive host addition
|
||||
sshsync hadd
|
||||
|
||||
# Follow prompts for:
|
||||
# - Host alias
|
||||
# - Hostname/IP
|
||||
# - Username
|
||||
# - Port (optional)
|
||||
# - Identity file (optional)
|
||||
```
|
||||
|
||||
#### Sync Ungrouped Hosts
|
||||
|
||||
```bash
|
||||
# Assign groups to hosts not yet in any group
|
||||
sshsync sync
|
||||
```
|
||||
|
||||
## Advanced Usage
|
||||
|
||||
### Parallel Execution
|
||||
|
||||
sshsync automatically executes commands in parallel across hosts:
|
||||
|
||||
```bash
|
||||
# This runs simultaneously on all hosts in group
|
||||
sshsync group web-servers "npm run build"
|
||||
```
|
||||
|
||||
**Performance**:
|
||||
- Commands execute concurrently
|
||||
- Results collected as they complete
|
||||
- Timeout applies per-host independently
|
||||
|
||||
### Timeout Strategies
|
||||
|
||||
Different operations need different timeouts:
|
||||
|
||||
```bash
|
||||
# Quick checks (5-10s)
|
||||
sshsync all --timeout 5 "hostname"
|
||||
|
||||
# Moderate operations (30-60s)
|
||||
sshsync group web --timeout 60 "npm install"
|
||||
|
||||
# Long-running tasks (300s+)
|
||||
sshsync group build --timeout 300 "docker build ."
|
||||
```
|
||||
|
||||
**Timeout Best Practices**:
|
||||
- Set timeout 20-30% longer than expected duration
|
||||
- Use dry-run first to estimate timing
|
||||
- Increase timeout for network-intensive operations
|
||||
|
||||
### Combining with Other Tools
|
||||
|
||||
#### With xargs
|
||||
|
||||
```bash
|
||||
# Get list of online hosts
|
||||
sshsync ls --with-status | grep online | awk '{print $1}' | xargs -I {} echo "Host {} is online"
|
||||
```
|
||||
|
||||
#### With jq (if using JSON output)
|
||||
|
||||
```bash
|
||||
# Parse structured output (if sshsync supports --json flag)
|
||||
sshsync ls --json | jq '.hosts[] | select(.status=="online") | .name'
|
||||
```
|
||||
|
||||
#### In Shell Scripts
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
# Deploy script using sshsync
|
||||
echo "Deploying to staging..."
|
||||
sshsync push --group staging --recurse ./dist /var/www/app
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "Staging deployment successful"
|
||||
|
||||
echo "Running tests..."
|
||||
sshsync group staging "cd /var/www/app && npm test"
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "Tests passed, deploying to production..."
|
||||
sshsync push --group production --recurse ./dist /var/www/app
|
||||
fi
|
||||
fi
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
#### 1. "Permission denied (publickey)"
|
||||
|
||||
**Cause**: SSH key not configured or not added to ssh-agent
|
||||
|
||||
**Solution**:
|
||||
```bash
|
||||
# Add SSH key to agent
|
||||
ssh-add ~/.ssh/id_ed25519
|
||||
|
||||
# Verify it's added
|
||||
ssh-add -l
|
||||
|
||||
# Copy public key to remote
|
||||
ssh-copy-id user@host
|
||||
```
|
||||
|
||||
#### 2. "Connection timed out"
|
||||
|
||||
**Cause**: Host is offline or network issue
|
||||
|
||||
**Solution**:
|
||||
```bash
|
||||
# Test connectivity
|
||||
ping hostname
|
||||
|
||||
# Test Tailscale specifically
|
||||
tailscale ping hostname
|
||||
|
||||
# Check Tailscale status
|
||||
tailscale status
|
||||
```
|
||||
|
||||
#### 3. "Host not found in SSH config"
|
||||
|
||||
**Cause**: Host alias not in `~/.ssh/config`
|
||||
|
||||
**Solution**:
|
||||
```bash
|
||||
# Add host to SSH config
|
||||
sshsync hadd
|
||||
|
||||
# Or manually edit ~/.ssh/config
|
||||
vim ~/.ssh/config
|
||||
```
|
||||
|
||||
#### 4. "Group not found"
|
||||
|
||||
**Cause**: Group doesn't exist in sshsync config
|
||||
|
||||
**Solution**:
|
||||
```bash
|
||||
# Add hosts to new group
|
||||
sshsync gadd mygroup
|
||||
|
||||
# Or manually edit config
|
||||
vim ~/.config/sshsync/config.yaml
|
||||
```
|
||||
|
||||
#### 5. File Transfer Fails
|
||||
|
||||
**Cause**: Insufficient permissions, disk space, or path doesn't exist
|
||||
|
||||
**Solution**:
|
||||
```bash
|
||||
# Check remote disk space
|
||||
sshsync group production "df -h"
|
||||
|
||||
# Check remote path exists
|
||||
sshsync group production "ls -ld /target/path"
|
||||
|
||||
# Check permissions
|
||||
sshsync group production "ls -la /target/path"
|
||||
```
|
||||
|
||||
### Debug Mode
|
||||
|
||||
While sshsync doesn't have a built-in verbose mode, you can debug underlying SSH:
|
||||
|
||||
```bash
|
||||
# Increase SSH verbosity
|
||||
SSH_VERBOSE=1 sshsync all "uptime"
|
||||
|
||||
# Or use dry-run to see what would execute
|
||||
sshsync all --dry-run "command"
|
||||
```
|
||||
|
||||
### Performance Issues
|
||||
|
||||
If operations are slow:
|
||||
|
||||
1. **Reduce parallelism** (run on fewer hosts at once)
|
||||
2. **Increase timeout** for network-bound operations
|
||||
3. **Check network latency**:
|
||||
```bash
|
||||
sshsync all "echo $HOSTNAME" --timeout 5
|
||||
```
|
||||
|
||||
### Configuration Validation
|
||||
|
||||
```bash
|
||||
# Verify SSH config is readable
|
||||
cat ~/.ssh/config
|
||||
|
||||
# Verify sshsync config
|
||||
cat ~/.config/sshsync/config.yaml
|
||||
|
||||
# Test hosts individually
|
||||
for host in $(sshsync ls | awk '{print $1}'); do
|
||||
echo "Testing $host..."
|
||||
ssh $host "echo OK" || echo "FAILED: $host"
|
||||
done
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Use meaningful host aliases** in SSH config
|
||||
2. **Organize groups logically** (by function, environment, location)
|
||||
3. **Always dry-run first** for destructive operations
|
||||
4. **Set appropriate timeouts** based on operation type
|
||||
5. **Test SSH keys** before using sshsync
|
||||
6. **Keep groups updated** as infrastructure changes
|
||||
7. **Use --with-status** to check availability before operations
|
||||
|
||||
## Integration with Tailscale
|
||||
|
||||
sshsync works seamlessly with Tailscale SSH:
|
||||
|
||||
```bash
|
||||
# SSH config using Tailscale hostname
|
||||
Host homelab-1
|
||||
HostName homelab-1.tailnet.ts.net
|
||||
User admin
|
||||
|
||||
# Or using Tailscale IP directly
|
||||
Host homelab-1
|
||||
HostName 100.64.1.10
|
||||
User admin
|
||||
```
|
||||
|
||||
**Tailscale Advantages**:
|
||||
- No need for port forwarding
|
||||
- Encrypted connections
|
||||
- MagicDNS for easy hostnames
|
||||
- Works across NATs
|
||||
|
||||
**Verify Tailscale**:
|
||||
```bash
|
||||
# Check Tailscale network
|
||||
tailscale status
|
||||
|
||||
# Ping host via Tailscale
|
||||
tailscale ping homelab-1
|
||||
```
|
||||
|
||||
## Summary
|
||||
|
||||
sshsync simplifies multi-host SSH operations:
|
||||
- ✅ Execute commands across host groups
|
||||
- ✅ Transfer files to/from multiple hosts
|
||||
- ✅ Organize hosts into logical groups
|
||||
- ✅ Parallel execution for speed
|
||||
- ✅ Dry-run mode for safety
|
||||
- ✅ Works great with Tailscale
|
||||
|
||||
For more help: `sshsync --help`
|
||||
468
references/tailscale-integration.md
Normal file
468
references/tailscale-integration.md
Normal file
@@ -0,0 +1,468 @@
|
||||
# Tailscale Integration Guide
|
||||
|
||||
How to use Tailscale SSH with sshsync for secure, zero-config remote access.
|
||||
|
||||
## What is Tailscale?
|
||||
|
||||
Tailscale is a zero-config VPN that creates a secure network between your devices using WireGuard. It provides:
|
||||
|
||||
- **Peer-to-peer encrypted connections**
|
||||
- **No port forwarding required**
|
||||
- **Works across NATs and firewalls**
|
||||
- **MagicDNS for easy device addressing**
|
||||
- **Built-in SSH functionality**
|
||||
- **Access control lists (ACLs)**
|
||||
|
||||
## Why Tailscale + sshsync?
|
||||
|
||||
Combining Tailscale with sshsync gives you:
|
||||
|
||||
1. **Secure connections** everywhere (Tailscale encryption)
|
||||
2. **Simple addressing** (MagicDNS hostnames)
|
||||
3. **Multi-host operations** (sshsync groups and execution)
|
||||
4. **No firewall configuration** needed
|
||||
5. **Works from anywhere** (coffee shop, home, office)
|
||||
|
||||
## Setup
|
||||
|
||||
### 1. Install Tailscale
|
||||
|
||||
**macOS**:
|
||||
```bash
|
||||
brew install tailscale
|
||||
```
|
||||
|
||||
**Linux**:
|
||||
```bash
|
||||
curl -fsSL https://tailscale.com/install.sh | sh
|
||||
```
|
||||
|
||||
**Verify Installation**:
|
||||
```bash
|
||||
tailscale version
|
||||
```
|
||||
|
||||
### 2. Connect to Tailscale
|
||||
|
||||
```bash
|
||||
# Start Tailscale
|
||||
sudo tailscale up
|
||||
|
||||
# Follow the authentication link
|
||||
# This opens browser to authenticate
|
||||
|
||||
# Verify connection
|
||||
tailscale status
|
||||
```
|
||||
|
||||
### 3. Configure SSH via Tailscale
|
||||
|
||||
Tailscale provides two SSH options:
|
||||
|
||||
#### Option A: Tailscale SSH (Built-in)
|
||||
|
||||
**Enable on each machine**:
|
||||
```bash
|
||||
sudo tailscale up --ssh
|
||||
```
|
||||
|
||||
**Use**:
|
||||
```bash
|
||||
tailscale ssh user@machine-name
|
||||
```
|
||||
|
||||
**Advantages**:
|
||||
- No SSH server configuration needed
|
||||
- Uses Tailscale authentication
|
||||
- Automatic key management
|
||||
|
||||
#### Option B: Standard SSH over Tailscale (Recommended for sshsync)
|
||||
|
||||
**Configure SSH config** to use Tailscale hostnames:
|
||||
|
||||
```bash
|
||||
# ~/.ssh/config
|
||||
|
||||
Host homelab-1
|
||||
HostName homelab-1.tailnet-name.ts.net
|
||||
User admin
|
||||
IdentityFile ~/.ssh/id_ed25519
|
||||
|
||||
# Or use Tailscale IP directly
|
||||
Host homelab-2
|
||||
HostName 100.64.1.10
|
||||
User admin
|
||||
IdentityFile ~/.ssh/id_ed25519
|
||||
```
|
||||
|
||||
**Advantages**:
|
||||
- Works with all SSH tools (including sshsync)
|
||||
- Standard SSH key authentication
|
||||
- More flexibility
|
||||
|
||||
## Getting Tailscale Hostnames and IPs
|
||||
|
||||
### View All Machines
|
||||
|
||||
```bash
|
||||
tailscale status
|
||||
```
|
||||
|
||||
**Output**:
|
||||
```
|
||||
100.64.1.10 homelab-1 user@ linux -
|
||||
100.64.1.11 homelab-2 user@ linux -
|
||||
100.64.1.20 laptop user@ macOS -
|
||||
100.64.1.30 phone user@ iOS offline
|
||||
```
|
||||
|
||||
### Get MagicDNS Hostname
|
||||
|
||||
**Format**: `machine-name.tailnet-name.ts.net`
|
||||
|
||||
**Find your tailnet name**:
|
||||
```bash
|
||||
tailscale status --json | grep -i tailnet
|
||||
```
|
||||
|
||||
Or check in Tailscale admin console: https://login.tailscale.com/admin/machines
|
||||
|
||||
### Get Tailscale IP
|
||||
|
||||
```bash
|
||||
# Your own IP
|
||||
tailscale ip -4
|
||||
|
||||
# Another machine's IP (from status output)
|
||||
tailscale status | grep machine-name
|
||||
```
|
||||
|
||||
## Testing Connectivity
|
||||
|
||||
### Ping via Tailscale
|
||||
|
||||
```bash
|
||||
# Ping by hostname
|
||||
tailscale ping homelab-1
|
||||
|
||||
# Ping by IP
|
||||
tailscale ping 100.64.1.10
|
||||
```
|
||||
|
||||
**Successful output**:
|
||||
```
|
||||
pong from homelab-1 (100.64.1.10) via DERP(nyc) in 45ms
|
||||
pong from homelab-1 (100.64.1.10) via DERP(nyc) in 43ms
|
||||
```
|
||||
|
||||
**Failed output**:
|
||||
```
|
||||
timeout waiting for pong
|
||||
```
|
||||
|
||||
### SSH Test
|
||||
|
||||
```bash
|
||||
# Test SSH connection
|
||||
ssh user@homelab-1.tailnet.ts.net
|
||||
|
||||
# Or with IP
|
||||
ssh user@100.64.1.10
|
||||
```
|
||||
|
||||
## Configuring sshsync with Tailscale
|
||||
|
||||
### Step 1: Add Tailscale Hosts to SSH Config
|
||||
|
||||
```bash
|
||||
vim ~/.ssh/config
|
||||
```
|
||||
|
||||
**Example configuration**:
|
||||
```
|
||||
# Production servers
|
||||
Host prod-web-01
|
||||
HostName prod-web-01.tailnet.ts.net
|
||||
User deploy
|
||||
IdentityFile ~/.ssh/id_ed25519
|
||||
|
||||
Host prod-web-02
|
||||
HostName prod-web-02.tailnet.ts.net
|
||||
User deploy
|
||||
IdentityFile ~/.ssh/id_ed25519
|
||||
|
||||
Host prod-db-01
|
||||
HostName prod-db-01.tailnet.ts.net
|
||||
User deploy
|
||||
IdentityFile ~/.ssh/id_ed25519
|
||||
|
||||
# Homelab
|
||||
Host homelab-1
|
||||
HostName 100.64.1.10
|
||||
User admin
|
||||
IdentityFile ~/.ssh/id_ed25519
|
||||
|
||||
Host homelab-2
|
||||
HostName 100.64.1.11
|
||||
User admin
|
||||
IdentityFile ~/.ssh/id_ed25519
|
||||
|
||||
# Development
|
||||
Host dev-laptop
|
||||
HostName dev-laptop.tailnet.ts.net
|
||||
User developer
|
||||
IdentityFile ~/.ssh/id_ed25519
|
||||
```
|
||||
|
||||
### Step 2: Test Each Host
|
||||
|
||||
```bash
|
||||
# Test connectivity to each host
|
||||
ssh prod-web-01 "hostname"
|
||||
ssh homelab-1 "hostname"
|
||||
ssh dev-laptop "hostname"
|
||||
```
|
||||
|
||||
### Step 3: Initialize sshsync
|
||||
|
||||
```bash
|
||||
# Sync hosts and create groups
|
||||
sshsync sync
|
||||
|
||||
# Add hosts to groups
|
||||
sshsync gadd production
|
||||
# Select: prod-web-01, prod-web-02, prod-db-01
|
||||
|
||||
sshsync gadd homelab
|
||||
# Select: homelab-1, homelab-2
|
||||
|
||||
sshsync gadd development
|
||||
# Select: dev-laptop
|
||||
```
|
||||
|
||||
### Step 4: Verify Configuration
|
||||
|
||||
```bash
|
||||
# List all hosts with status
|
||||
sshsync ls --with-status
|
||||
|
||||
# Test command execution
|
||||
sshsync all "uptime"
|
||||
|
||||
# Test group execution
|
||||
sshsync group production "df -h"
|
||||
```
|
||||
|
||||
## Advanced Tailscale Features
|
||||
|
||||
### Tailnet Lock
|
||||
|
||||
Prevents unauthorized device additions:
|
||||
|
||||
```bash
|
||||
tailscale lock status
|
||||
```
|
||||
|
||||
### Exit Nodes
|
||||
|
||||
Route all traffic through a specific machine:
|
||||
|
||||
```bash
|
||||
# Enable exit node on a machine
|
||||
sudo tailscale up --advertise-exit-node
|
||||
|
||||
# Use exit node from another machine
|
||||
sudo tailscale set --exit-node=exit-node-name
|
||||
```
|
||||
|
||||
### Subnet Routing
|
||||
|
||||
Access networks behind Tailscale machines:
|
||||
|
||||
```bash
|
||||
# Advertise subnet routes
|
||||
sudo tailscale up --advertise-routes=192.168.1.0/24
|
||||
```
|
||||
|
||||
### ACLs (Access Control Lists)
|
||||
|
||||
Control who can access what: https://login.tailscale.com/admin/acls
|
||||
|
||||
**Example ACL**:
|
||||
```json
|
||||
{
|
||||
"acls": [
|
||||
{
|
||||
"action": "accept",
|
||||
"src": ["group:admins"],
|
||||
"dst": ["*:22", "*:80", "*:443"]
|
||||
},
|
||||
{
|
||||
"action": "accept",
|
||||
"src": ["group:developers"],
|
||||
"dst": ["tag:development:*"]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Machine Shows Offline
|
||||
|
||||
**Check Tailscale status**:
|
||||
```bash
|
||||
tailscale status
|
||||
```
|
||||
|
||||
**Restart Tailscale**:
|
||||
```bash
|
||||
# macOS
|
||||
brew services restart tailscale
|
||||
|
||||
# Linux
|
||||
sudo systemctl restart tailscaled
|
||||
```
|
||||
|
||||
**Re-authenticate**:
|
||||
```bash
|
||||
sudo tailscale up
|
||||
```
|
||||
|
||||
### Cannot Connect via SSH
|
||||
|
||||
1. **Verify Tailscale connectivity**:
|
||||
```bash
|
||||
tailscale ping machine-name
|
||||
```
|
||||
|
||||
2. **Check SSH is running** on remote:
|
||||
```bash
|
||||
tailscale ssh machine-name "systemctl status sshd"
|
||||
```
|
||||
|
||||
3. **Verify SSH keys**:
|
||||
```bash
|
||||
ssh-add -l
|
||||
```
|
||||
|
||||
4. **Test SSH directly**:
|
||||
```bash
|
||||
ssh -v user@machine-name.tailnet.ts.net
|
||||
```
|
||||
|
||||
### High Latency
|
||||
|
||||
**Check connection method**:
|
||||
```bash
|
||||
tailscale status
|
||||
```
|
||||
|
||||
Look for "direct" vs "DERP relay":
|
||||
- **Direct**: Low latency (< 50ms)
|
||||
- **DERP relay**: Higher latency (100-200ms)
|
||||
|
||||
**Force direct connection**:
|
||||
```bash
|
||||
# Ensure both machines can establish P2P
|
||||
# May require NAT traversal
|
||||
```
|
||||
|
||||
### MagicDNS Not Working
|
||||
|
||||
**Enable MagicDNS**:
|
||||
1. Go to https://login.tailscale.com/admin/dns
|
||||
2. Enable MagicDNS
|
||||
|
||||
**Verify**:
|
||||
```bash
|
||||
nslookup machine-name.tailnet.ts.net
|
||||
```
|
||||
|
||||
## Security Best Practices
|
||||
|
||||
1. **Use SSH keys**, not passwords
|
||||
2. **Enable Tailnet Lock** to prevent unauthorized devices
|
||||
3. **Use ACLs** to restrict access
|
||||
4. **Regularly review** connected devices
|
||||
5. **Set up key expiry** for team members who leave
|
||||
6. **Use tags** for machine roles
|
||||
7. **Enable two-factor auth** for Tailscale account
|
||||
|
||||
## Monitoring
|
||||
|
||||
### Check Network Status
|
||||
|
||||
```bash
|
||||
# All machines
|
||||
tailscale status
|
||||
|
||||
# Self status
|
||||
tailscale status --self
|
||||
|
||||
# JSON format for parsing
|
||||
tailscale status --json
|
||||
```
|
||||
|
||||
### View Logs
|
||||
|
||||
```bash
|
||||
# macOS
|
||||
tail -f /var/log/tailscaled.log
|
||||
|
||||
# Linux
|
||||
journalctl -u tailscaled -f
|
||||
```
|
||||
|
||||
## Use Cases with sshsync
|
||||
|
||||
### 1. Deploy to All Production Servers
|
||||
|
||||
```bash
|
||||
sshsync push --group production --recurse ./dist /var/www/app
|
||||
sshsync group production "cd /var/www/app && pm2 restart all"
|
||||
```
|
||||
|
||||
### 2. Collect Logs from All Servers
|
||||
|
||||
```bash
|
||||
sshsync pull --group production /var/log/app/error.log ./logs/
|
||||
```
|
||||
|
||||
### 3. Update All Homelab Machines
|
||||
|
||||
```bash
|
||||
sshsync group homelab "sudo apt update && sudo apt upgrade -y"
|
||||
```
|
||||
|
||||
### 4. Check Disk Space Everywhere
|
||||
|
||||
```bash
|
||||
sshsync all "df -h /"
|
||||
```
|
||||
|
||||
### 5. Sync Configuration Across Machines
|
||||
|
||||
```bash
|
||||
sshsync push --all ~/dotfiles/.bashrc ~/.bashrc
|
||||
sshsync push --all ~/dotfiles/.vimrc ~/.vimrc
|
||||
```
|
||||
|
||||
## Summary
|
||||
|
||||
Tailscale + sshsync = **Powerful Remote Management**
|
||||
|
||||
- ✅ Secure connections everywhere (WireGuard encryption)
|
||||
- ✅ No firewall configuration needed
|
||||
- ✅ Easy addressing (MagicDNS)
|
||||
- ✅ Multi-host operations (sshsync groups)
|
||||
- ✅ Works from anywhere
|
||||
|
||||
**Quick Start**:
|
||||
1. Install Tailscale: `brew install tailscale`
|
||||
2. Connect: `sudo tailscale up`
|
||||
3. Configure SSH config with Tailscale hostnames
|
||||
4. Initialize sshsync: `sshsync sync`
|
||||
5. Start managing: `sshsync all "uptime"`
|
||||
|
||||
For more: https://tailscale.com/kb/
|
||||
Reference in New Issue
Block a user