All checks were successful
Reindex Knowledge Base / reindex (push) Successful in 3s
Adds title, description, type, domain, and tags frontmatter to every doc for improved KB semantic search. The description field is prepended to every search chunk, and domain/type/tags enable filtered queries. Type values: context, guide, runbook, reference, troubleshooting Domain values match directory structure (networking, docker, etc.) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
376 lines
9.8 KiB
Markdown
376 lines
9.8 KiB
Markdown
---
|
|
title: "SSH Homelab Setup Implementation"
|
|
description: "Complete working SSH key-based auth setup with key generation scripts, SSH config, deployment commands, emergency keys, NAS backup, and mobile device access via Termius."
|
|
type: guide
|
|
domain: networking
|
|
tags: [ssh, keys, setup, deployment, backup, termius, mobile]
|
|
---
|
|
|
|
# SSH Home Lab Setup - Complete Implementation
|
|
|
|
## Overview
|
|
|
|
Complete working implementation for setting up secure SSH key-based authentication across a home lab environment with emergency backup keys and NAS storage.
|
|
|
|
## Server Inventory
|
|
|
|
### Home Network (10.10.0.0/24)
|
|
```yaml
|
|
servers:
|
|
database_apis: 10.10.0.42 # Database and API services
|
|
discord_bots: 10.10.0.33 # Discord bot hosting
|
|
home_docker: 10.10.0.124 # Main Docker container host
|
|
pihole: 10.10.0.16 # Pi-hole DNS and ad blocking
|
|
sba_pd_bots: 10.10.0.88 # SBa and PD bot services
|
|
tdarr: 10.10.0.43 # Media transcoding
|
|
vpn_docker: 10.10.0.121 # VPN and Docker services
|
|
```
|
|
|
|
### Cloud Servers
|
|
```yaml
|
|
remote_servers:
|
|
akamai_nano: 172.237.147.99 # Akamai cloud instance
|
|
vultr_host: 45.76.25.231 # Vultr cloud host
|
|
```
|
|
|
|
## SSH Key Generation Script
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
# SSH Key Setup Script for Home Lab
|
|
# Creates primary + emergency keys with NAS backup
|
|
|
|
set -e
|
|
|
|
echo "🔐 Setting up SSH keys for Home Lab with Emergency Backup..."
|
|
|
|
# Create directories
|
|
mkdir -p ~/.ssh
|
|
chmod 700 ~/.ssh
|
|
|
|
# Create NAS backup directory
|
|
BACKUP_DIR="/mnt/NV2/ssh-keys/backup-$(date +%Y%m%d-%H%M%S)"
|
|
mkdir -p "$BACKUP_DIR"
|
|
chmod 700 "$BACKUP_DIR"
|
|
echo "📁 NAS backup directory created: $BACKUP_DIR"
|
|
|
|
# Generate primary keys
|
|
if [ ! -f ~/.ssh/homelab_rsa ]; then
|
|
ssh-keygen -t rsa -b 4096 -C "homelab-$(whoami)@$(hostname)" -f ~/.ssh/homelab_rsa -N ""
|
|
chmod 600 ~/.ssh/homelab_rsa
|
|
chmod 644 ~/.ssh/homelab_rsa.pub
|
|
echo "✅ Home lab SSH key generated"
|
|
fi
|
|
|
|
if [ ! -f ~/.ssh/cloud_servers_rsa ]; then
|
|
ssh-keygen -t rsa -b 4096 -C "cloud-$(whoami)@$(hostname)" -f ~/.ssh/cloud_servers_rsa -N ""
|
|
chmod 600 ~/.ssh/cloud_servers_rsa
|
|
chmod 644 ~/.ssh/cloud_servers_rsa.pub
|
|
echo "✅ Cloud servers SSH key generated"
|
|
fi
|
|
|
|
# Generate emergency keys
|
|
if [ ! -f ~/.ssh/emergency_homelab_rsa ]; then
|
|
ssh-keygen -t rsa -b 4096 -C "emergency-homelab-$(whoami)@$(hostname)" -f ~/.ssh/emergency_homelab_rsa -N ""
|
|
chmod 600 ~/.ssh/emergency_homelab_rsa
|
|
chmod 644 ~/.ssh/emergency_homelab_rsa.pub
|
|
echo "✅ Emergency home lab key generated"
|
|
fi
|
|
|
|
if [ ! -f ~/.ssh/emergency_cloud_rsa ]; then
|
|
ssh-keygen -t rsa -b 4096 -C "emergency-cloud-$(whoami)@$(hostname)" -f ~/.ssh/emergency_cloud_rsa -N ""
|
|
chmod 600 ~/.ssh/emergency_cloud_rsa
|
|
chmod 644 ~/.ssh/emergency_cloud_rsa.pub
|
|
echo "✅ Emergency cloud key generated"
|
|
fi
|
|
|
|
# Backup all keys to NAS
|
|
echo "💾 Backing up keys to NAS..."
|
|
cp ~/.ssh/*_rsa* "$BACKUP_DIR/" 2>/dev/null || true
|
|
cp ~/.ssh/config "$BACKUP_DIR/" 2>/dev/null || true
|
|
|
|
# Create recovery documentation
|
|
cat > "$BACKUP_DIR/RECOVERY_INSTRUCTIONS.md" << EOF
|
|
# SSH Key Recovery Instructions
|
|
Generated: $(date)
|
|
Location: $BACKUP_DIR
|
|
|
|
## Emergency Recovery Steps
|
|
|
|
### If you lose access to your primary keys:
|
|
|
|
1. **Copy emergency keys back:**
|
|
\`\`\`bash
|
|
cp $BACKUP_DIR/emergency_*_rsa* ~/.ssh/
|
|
chmod 600 ~/.ssh/emergency_*_rsa
|
|
chmod 644 ~/.ssh/emergency_*_rsa.pub
|
|
\`\`\`
|
|
|
|
2. **Test emergency access:**
|
|
\`\`\`bash
|
|
ssh -i ~/.ssh/emergency_homelab_rsa cal@10.10.0.16
|
|
ssh -i ~/.ssh/emergency_cloud_rsa root@172.237.147.99
|
|
\`\`\`
|
|
|
|
3. **If emergency keys weren't deployed, use console access:**
|
|
- Home servers: Physical console access
|
|
- Cloud servers: Provider web console
|
|
- Add emergency public key to ~/.ssh/authorized_keys
|
|
EOF
|
|
|
|
ls -la "$BACKUP_DIR" >> "$BACKUP_DIR/RECOVERY_INSTRUCTIONS.md"
|
|
echo "✅ Keys backed up to: $BACKUP_DIR"
|
|
|
|
echo "🎉 SSH keys and emergency backups created successfully!"
|
|
```
|
|
|
|
## SSH Configuration
|
|
|
|
```bash
|
|
# SSH Configuration for Home Lab (~/.ssh/config)
|
|
# Global defaults
|
|
Host *
|
|
ServerAliveInterval 60
|
|
ServerAliveCountMax 3
|
|
StrictHostKeyChecking ask
|
|
VerifyHostKeyDNS yes
|
|
ForwardAgent no
|
|
ForwardX11 no
|
|
AddKeysToAgent yes
|
|
|
|
# Home Network Servers
|
|
Host strat-database pd-database sba-database strat-db pd-db sba-db
|
|
HostName 10.10.0.42
|
|
User cal
|
|
Port 22
|
|
IdentityFile ~/.ssh/homelab_rsa
|
|
|
|
Host discord-bots
|
|
HostName 10.10.0.33
|
|
User cal
|
|
Port 22
|
|
IdentityFile ~/.ssh/homelab_rsa
|
|
|
|
Host docker-home docker-main
|
|
HostName 10.10.0.124
|
|
User cal
|
|
Port 22
|
|
IdentityFile ~/.ssh/homelab_rsa
|
|
|
|
Host pihole dns
|
|
HostName 10.10.0.16
|
|
User cal
|
|
Port 22
|
|
IdentityFile ~/.ssh/homelab_rsa
|
|
|
|
Host sba-bots pd-bots
|
|
HostName 10.10.0.88
|
|
User cal
|
|
Port 22
|
|
IdentityFile ~/.ssh/homelab_rsa
|
|
|
|
Host tdarr media
|
|
HostName 10.10.0.43
|
|
User cal
|
|
Port 22
|
|
IdentityFile ~/.ssh/homelab_rsa
|
|
|
|
Host docker-vpn
|
|
HostName 10.10.0.121
|
|
User cal
|
|
Port 22
|
|
IdentityFile ~/.ssh/homelab_rsa
|
|
|
|
# Remote Cloud Servers
|
|
Host akamai-nano akamai
|
|
HostName 172.237.147.99
|
|
User root
|
|
Port 22
|
|
IdentityFile ~/.ssh/cloud_servers_rsa
|
|
|
|
Host vultr-host vultr
|
|
HostName 45.76.25.231
|
|
User root
|
|
Port 22
|
|
IdentityFile ~/.ssh/cloud_servers_rsa
|
|
|
|
# Home network wildcard for easy access
|
|
Host 10.10.0.*
|
|
User cal
|
|
IdentityFile ~/.ssh/homelab_rsa
|
|
StrictHostKeyChecking accept-new
|
|
```
|
|
|
|
## Key Deployment Commands
|
|
|
|
### Primary Keys
|
|
```bash
|
|
# Home lab servers
|
|
for ip in 42 33 124 16 88 43 121; do
|
|
ssh-copy-id -i ~/.ssh/homelab_rsa.pub cal@10.10.0.$ip
|
|
done
|
|
|
|
# Cloud servers
|
|
ssh-copy-id -i ~/.ssh/cloud_servers_rsa.pub root@172.237.147.99
|
|
ssh-copy-id -i ~/.ssh/cloud_servers_rsa.pub root@45.76.25.231
|
|
```
|
|
|
|
### Emergency Keys
|
|
```bash
|
|
# Home lab servers (use -f to force)
|
|
for ip in 42 33 124 16 88 43 121; do
|
|
ssh-copy-id -f -i ~/.ssh/emergency_homelab_rsa.pub cal@10.10.0.$ip
|
|
done
|
|
|
|
# Cloud servers
|
|
ssh-copy-id -f -i ~/.ssh/emergency_cloud_rsa.pub root@172.237.147.99
|
|
ssh-copy-id -f -i ~/.ssh/emergency_cloud_rsa.pub root@45.76.25.231
|
|
```
|
|
|
|
## Maintenance Script
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
# SSH Key Maintenance and Backup Script
|
|
# Location: ~/bin/ssh_key_maintenance.sh
|
|
# Schedule: 0 2 1 * * (monthly at 2 AM)
|
|
|
|
echo "🔧 SSH Key Maintenance and Backup"
|
|
|
|
# Check NAS availability
|
|
if [ ! -d "/mnt/NV2" ]; then
|
|
echo "❌ ERROR: NAS not mounted at /mnt/NV2"
|
|
exit 1
|
|
fi
|
|
|
|
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
|
|
BACKUP_ROOT="/mnt/NV2/ssh-keys"
|
|
BACKUP_DIR="$BACKUP_ROOT/maintenance-$TIMESTAMP"
|
|
|
|
mkdir -p "$BACKUP_DIR"
|
|
chmod 700 "$BACKUP_DIR"
|
|
|
|
# Backup current state
|
|
cp ~/.ssh/*_rsa* "$BACKUP_DIR/" 2>/dev/null || true
|
|
cp ~/.ssh/config "$BACKUP_DIR/" 2>/dev/null || true
|
|
cp ~/.ssh/known_hosts "$BACKUP_DIR/" 2>/dev/null || true
|
|
|
|
# Check key ages and health
|
|
echo "🔍 Key Age Analysis:"
|
|
for key in ~/.ssh/*_rsa; do
|
|
if [ -f "$key" ]; then
|
|
age_days=$(( ($(date +%s) - $(stat -c %Y "$key")) / 86400 ))
|
|
basename_key=$(basename "$key")
|
|
|
|
if [ $age_days -gt 365 ]; then
|
|
echo "⚠️ $basename_key: $age_days days old - ROTATION RECOMMENDED"
|
|
elif [ $age_days -gt 180 ]; then
|
|
echo "⚡ $basename_key: $age_days days old - consider rotation"
|
|
else
|
|
echo "✅ $basename_key: $age_days days old - OK"
|
|
fi
|
|
fi
|
|
done
|
|
|
|
# Clean up old backups (keep last 10)
|
|
cd "$BACKUP_ROOT"
|
|
ls -dt backup-* maintenance-* 2>/dev/null | tail -n +11 | while read old_backup; do
|
|
if [ -d "$old_backup" ]; then
|
|
echo "🗑️ Removing old backup: $old_backup"
|
|
rm -rf "$old_backup"
|
|
fi
|
|
done
|
|
|
|
echo "✅ Maintenance backup completed: $BACKUP_DIR"
|
|
```
|
|
|
|
## Testing Procedures
|
|
|
|
### Test Primary Access
|
|
```bash
|
|
# Test aliases work
|
|
ssh strat-database 'echo "Primary access: $(hostname)"'
|
|
ssh pihole 'echo "Primary access: $(hostname)"'
|
|
ssh akamai 'echo "Primary access: $(hostname)"'
|
|
```
|
|
|
|
### Test Emergency Access
|
|
```bash
|
|
# Test emergency keys work
|
|
ssh -i ~/.ssh/emergency_homelab_rsa cal@10.10.0.16 'echo "Emergency access: $(hostname)"'
|
|
ssh -i ~/.ssh/emergency_cloud_rsa root@172.237.147.99 'echo "Emergency access: $(hostname)"'
|
|
```
|
|
|
|
## Cron Schedule Setup
|
|
|
|
```bash
|
|
# Open crontab editor
|
|
crontab -e
|
|
|
|
# Add monthly maintenance (1st of month at 2 AM)
|
|
0 2 1 * * /home/cal/bin/ssh_key_maintenance.sh
|
|
```
|
|
|
|
## Security Hardening
|
|
|
|
After key deployment, disable password authentication on servers:
|
|
|
|
```bash
|
|
# On each server, edit /etc/ssh/sshd_config:
|
|
PasswordAuthentication no
|
|
PubkeyAuthentication yes
|
|
PermitRootLogin no # Create non-root users first on cloud servers
|
|
AllowUsers cal # Restrict SSH access
|
|
|
|
# Restart SSH service
|
|
sudo systemctl restart sshd
|
|
```
|
|
|
|
## Mobile Device SSH Access
|
|
|
|
### Termius Setup (iPhone/iPad)
|
|
Connect to local development machine using existing homelab keys:
|
|
|
|
```yaml
|
|
Connection Details:
|
|
Host: 10.0.0.206 (or current eno1 IP)
|
|
Username: cal
|
|
Port: 22
|
|
Key: homelab_rsa (same key used for server access)
|
|
```
|
|
|
|
### Prerequisites Checklist
|
|
Before mobile SSH access works, ensure:
|
|
|
|
1. **SSH service is running:**
|
|
```bash
|
|
sudo systemctl start sshd
|
|
sudo systemctl enable sshd
|
|
```
|
|
|
|
2. **Firewall allows SSH:**
|
|
```bash
|
|
sudo firewall-cmd --list-services # Should include 'ssh'
|
|
# If not present, SSH was already allowed in this setup
|
|
```
|
|
|
|
3. **Authorized keys configured:**
|
|
```bash
|
|
# homelab_rsa.pub should be in ~/.ssh/authorized_keys
|
|
cat ~/.ssh/homelab_rsa.pub >> ~/.ssh/authorized_keys
|
|
chmod 600 ~/.ssh/authorized_keys
|
|
```
|
|
|
|
### Key Transfer Process
|
|
1. Copy private key: `cp ~/.ssh/homelab_rsa ./homelab_rsa_for_mobile`
|
|
2. Transfer securely to mobile device (AirDrop, secure file share)
|
|
3. Import into Termius app
|
|
4. Clean up: `rm homelab_rsa_for_mobile`
|
|
|
|
### Network Discovery
|
|
Find local machine IP: `ip addr show eno1 | grep 'inet ' | awk '{print $2}' | cut -d'/' -f1`
|
|
|
|
## Related Documentation
|
|
|
|
- Patterns: `patterns/networking/ssh-key-management.md`
|
|
- Troubleshooting: `reference/networking/ssh-troubleshooting.md` |