Files
homelab-optimized/docs/networking/SSH_MESH.md
Gitea Mirror Bot 9b3ce31e0d
Some checks failed
Documentation / Deploy to GitHub Pages (push) Has been cancelled
Documentation / Build Docusaurus (push) Has started running
Sanitized mirror from private repository - 2026-03-25 08:41:40 UTC
2026-03-25 08:41:40 +00:00

3.7 KiB

SSH Mesh — Key-Based Authentication Across All Hosts

All Tailscale-connected hosts can SSH to each other using ed25519 key authentication. No passwords needed.

Participating Hosts

Host User Tailscale IP SSH Port Key
homelab-vm homelab 100.67.40.126 22 admin@thevish.io
atlantis vish 100.83.230.112 60000 vish@atlantis
calypso Vish 100.103.48.78 62000 calypso access
guava vish 100.75.252.64 22 vish@guava
setillo vish 100.125.0.20 22 setillo-key
pi-5 vish 100.77.151.40 22 vish@pi-5
nuc vish 100.72.55.21 22 vish@nuc
moon vish 100.64.0.6 22 vish@moon
seattle root 100.82.197.124 22 root@seattle
matrix-ubuntu test 100.85.21.51 22 test@matrix-ubuntu
jellyfish lulu 100.69.121.120 22 lulu@jellyfish
pve root 100.87.12.28 22 root@pve (RSA)
gl-mt3000 root 100.126.243.15 22 (admin key only)
gl-be3600 root 100.105.59.123 22 root@gl-be3600

The admin key (admin@thevish.io from homelab-vm) is present on every host.

Ansible Playbook

Manage the mesh with ansible/playbooks/ssh_mesh.yml:

# Distribute keys to all hosts (collect + push)
ansible-playbook -i inventory.yml playbooks/ssh_mesh.yml --tags distribute

# Verify connectivity from localhost
ansible-playbook -i inventory.yml playbooks/ssh_mesh.yml --tags verify

# Generate missing keys + distribute
ansible-playbook -i inventory.yml playbooks/ssh_mesh.yml -e "generate_missing=true"

The ssh_mesh group in inventory.yml defines which hosts participate.

Adding a New Host

  1. Add the host to ansible/inventory.yml under the appropriate group and to the ssh_mesh children
  2. Run the playbook with key generation:
    ansible-playbook -i inventory.yml playbooks/ssh_mesh.yml -e "generate_missing=true"
    
  3. This will generate a key on the new host if needed, collect all keys, and distribute them everywhere

Notes

  • Synology NAS (Atlantis/Calypso/Setillo): Home directory must be chmod 755 or stricter — SSH refuses key auth if home is world-writable. DSM can reset permissions on reboot.
  • OpenWrt routers (MT3000/BE3600): Use dropbear SSH, not OpenSSH. Keys must be in both /etc/dropbear/authorized_keys AND /root/.ssh/authorized_keys. Key auth works but ssh -o flags differ slightly.
  • GL-BE3600 in repeater mode: SSH port 22 is accessible via Tailscale only — LAN SSH is blocked by the repeater firewall. Use 100.105.59.123 not 192.168.68.1.
  • TrueNAS (Guava): Home directory is at /mnt/data/vish-home/vish/, not /home/vish/.
  • pi-5-kevin: Frequently offline — will fail verification but has keys distributed.
  • homelab-vm: SSH config historically uses password auth to itself; key auth works to all other hosts.
  • rsync to Atlantis: rsync from homelab-vm to Atlantis fails (Synology SSH subsystem issue). Use scp -O -r -P 60000 instead, or pull from Atlantis.

Router Tailscale Auto-Start

Both GL.iNet routers have init scripts to auto-connect to Headscale on boot:

GL-MT3000 (/etc/init.d/tailscale-up, START=81):

tailscale up --accept-routes --login-server=https://headscale.vish.gg:8443 --accept-dns=false --advertise-routes=192.168.12.0/24

GL-BE3600 (/etc/init.d/tailscale-up, START=99):

  • Waits for network connectivity (repeater mode needs WiFi first)
  • Polls every 2s for up to 120s before running tailscale up
  • Advertises 192.168.68.0/22,192.168.8.0/24

Update script on both: /root/update-tailscale.sh (Admon's GL.iNet updater, use --force for non-interactive).

Established 2026-03-23, updated 2026-03-24