Initial commit

This commit is contained in:
Zhongwei Li
2025-11-29 18:47:40 +08:00
commit 14c678ceac
22 changed files with 7501 additions and 0 deletions

466
references/sshsync-guide.md Normal file
View 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`

View 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/