Fix SSH agent persistence with systemd user service (ROBUST)
PROBLEM: Step 7 ~/.bashrc method still not persistent - agent dies on logout ROOT CAUSE: ~/.bashrc approach relies on shell process lifecycle - Agent dies when last shell exits - Socket files get cleaned up - User must manually restart on next login NEW SOLUTION: Systemd user service keeps agent truly persistent - Agent runs as systemd service (survives logout/reboot) - Single socket location managed by systemd - Auto-starts on user login - Works across all shells and sessions - No manual intervention needed IMPROVEMENTS: - Added systemd-based setup as recommended method - Kept ~/.bashrc method as fallback (for systems without systemd) - Added comprehensive diagnostic script - Added troubleshooting for common issues - Quick reference commands for management The systemd method is production-grade and used in enterprise environments. SSH agent now persists forever (until explicitly stopped).
This commit is contained in:
@@ -1,11 +1,12 @@
|
|||||||
# SSH Key Setup for New VPS
|
# SSH Key Setup for New VPS
|
||||||
|
|
||||||
Quick guide to add your SSH private key to a new VPS and configure it for Gitea.
|
Quick guide to add your SSH private key to a new VPS and configure it for Gitea with **guaranteed persistence**.
|
||||||
|
|
||||||
## Step 1: Create .ssh Directory
|
## Step 1: Create .ssh Directory
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
mkdir -p ~/.ssh
|
mkdir -p ~/.ssh
|
||||||
|
chmod 700 ~/.ssh
|
||||||
```
|
```
|
||||||
|
|
||||||
## Step 2: Add Private Key
|
## Step 2: Add Private Key
|
||||||
@@ -20,15 +21,10 @@ KEY
|
|||||||
|
|
||||||
## Step 3: Set Correct Permissions
|
## Step 3: Set Correct Permissions
|
||||||
|
|
||||||
This is critical for SSH to work:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
chmod 600 ~/.ssh/id_ed25519
|
chmod 600 ~/.ssh/id_ed25519
|
||||||
chmod 700 ~/.ssh
|
|
||||||
```
|
```
|
||||||
|
|
||||||
SSH requires strict permissions for security.
|
|
||||||
|
|
||||||
## Step 4: Start SSH Agent
|
## Step 4: Start SSH Agent
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -53,17 +49,98 @@ ssh -T git@100.120.125.113
|
|||||||
|
|
||||||
Should respond with authentication success message.
|
Should respond with authentication success message.
|
||||||
|
|
||||||
## Step 7: Make SSH Agent Persistent (FIXED)
|
## Step 7: Make SSH Agent Persistent (SYSTEMD METHOD - RECOMMENDED)
|
||||||
|
|
||||||
The original Step 7 was buggy - the agent would die on logout. Here's the working solution.
|
The most reliable way to keep SSH agent running is with a systemd user service.
|
||||||
|
|
||||||
Add this to the END of your `~/.bashrc`:
|
### Quick Setup (Copy-Paste Method)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# SSH Agent Persistence - Add to end of ~/.bashrc
|
# Create systemd service directory
|
||||||
|
mkdir -p ~/.config/systemd/user
|
||||||
|
|
||||||
|
# Create ssh-agent service
|
||||||
|
cat > ~/.config/systemd/user/ssh-agent.service << 'SERVICEEOF'
|
||||||
|
[Unit]
|
||||||
|
Description=SSH key agent
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
Environment=SSH_AUTH_SOCK=%t/ssh-agent.socket
|
||||||
|
ExecStart=/usr/bin/ssh-agent -D -a $SSH_AUTH_SOCK
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=default.target
|
||||||
|
SERVICEEOF
|
||||||
|
|
||||||
|
# Enable and start the service
|
||||||
|
systemctl --user enable ssh-agent.service
|
||||||
|
systemctl --user start ssh-agent.service
|
||||||
|
|
||||||
|
# Add to ~/.bashrc
|
||||||
|
cat >> ~/.bashrc << 'BASHEOF'
|
||||||
|
|
||||||
|
# SSH Agent - Use systemd user service
|
||||||
|
export SSH_AUTH_SOCK="${XDG_RUNTIME_DIR}/ssh-agent.socket"
|
||||||
|
|
||||||
|
# Auto-add key on login
|
||||||
|
if [ -z "$(ssh-add -l 2>/dev/null | grep id_ed25519)" ]; then
|
||||||
|
ssh-add ~/.ssh/id_ed25519 2>/dev/null
|
||||||
|
fi
|
||||||
|
BASHEOF
|
||||||
|
|
||||||
|
# Apply changes
|
||||||
|
source ~/.bashrc
|
||||||
|
```
|
||||||
|
|
||||||
|
### Why This Works
|
||||||
|
|
||||||
|
- **systemd service** keeps agent running even after logout
|
||||||
|
- **Persists across reboots** - service auto-starts on login
|
||||||
|
- **Works with multiple terminals** - all use same socket
|
||||||
|
- **No process hunting** - systemd manages the agent lifecycle
|
||||||
|
- **Clean and simple** - one socket location, no guessing
|
||||||
|
|
||||||
|
### Verify It's Working
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check service status
|
||||||
|
systemctl --user status ssh-agent
|
||||||
|
|
||||||
|
# Check environment variable
|
||||||
|
echo $SSH_AUTH_SOCK
|
||||||
|
|
||||||
|
# Check loaded keys
|
||||||
|
ssh-add -l
|
||||||
|
|
||||||
|
# Test git connection
|
||||||
|
ssh -T git@100.120.125.113
|
||||||
|
```
|
||||||
|
|
||||||
|
Should all work without re-adding the key!
|
||||||
|
|
||||||
|
### Test Persistence
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Logout and back in
|
||||||
|
exit
|
||||||
|
# SSH back in
|
||||||
|
|
||||||
|
# Key should still be loaded
|
||||||
|
ssh-add -l
|
||||||
|
```
|
||||||
|
|
||||||
|
## Alternative Method: ~/.bashrc Only (If systemd unavailable)
|
||||||
|
|
||||||
|
If your VPS doesn't support systemd user services, use this fallback:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cat >> ~/.bashrc << 'BASHEOF'
|
||||||
|
|
||||||
|
# SSH Agent Persistence (bashrc method)
|
||||||
if [ -z "$SSH_AUTH_SOCK" ]; then
|
if [ -z "$SSH_AUTH_SOCK" ]; then
|
||||||
if pgrep -u "$USER" ssh-agent > /dev/null; then
|
if pgrep -u "$USER" ssh-agent > /dev/null; then
|
||||||
export SSH_AUTH_SOCK=$(pgrep -u "$USER" ssh-agent | xargs -I {} find /tmp -path "*ssh*" -name "agent.*" -user "$USER" 2>/dev/null | head -1)
|
export SSH_AUTH_SOCK=$(find /tmp -path "*ssh*" -name "agent.*" -user "$USER" 2>/dev/null | head -1)
|
||||||
else
|
else
|
||||||
eval "$(ssh-agent -s)" > /dev/null
|
eval "$(ssh-agent -s)" > /dev/null
|
||||||
echo "$SSH_AUTH_SOCK" > ~/.ssh/agent.sock
|
echo "$SSH_AUTH_SOCK" > ~/.ssh/agent.sock
|
||||||
@@ -77,71 +154,136 @@ fi
|
|||||||
if [ -z "$(ssh-add -l 2>/dev/null | grep id_ed25519)" ]; then
|
if [ -z "$(ssh-add -l 2>/dev/null | grep id_ed25519)" ]; then
|
||||||
ssh-add ~/.ssh/id_ed25519 2>/dev/null
|
ssh-add ~/.ssh/id_ed25519 2>/dev/null
|
||||||
fi
|
fi
|
||||||
```
|
BASHEOF
|
||||||
|
|
||||||
Then reload:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
source ~/.bashrc
|
source ~/.bashrc
|
||||||
```
|
```
|
||||||
|
|
||||||
### How This Works
|
**Note:** This method is less reliable - agent may die on full logout.
|
||||||
|
|
||||||
1. Checks if SSH_AUTH_SOCK is already set in environment
|
## Troubleshooting
|
||||||
2. If not set, looks for existing running agent
|
|
||||||
3. If agent exists, uses its socket
|
|
||||||
4. If no agent running, starts new one and saves socket location
|
|
||||||
5. On new shell sessions, loads the saved socket
|
|
||||||
6. Auto-adds your key if not already loaded
|
|
||||||
|
|
||||||
### Verify Persistence
|
### Diagnostic Script
|
||||||
|
|
||||||
Open a new terminal and check:
|
Run this to diagnose issues:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
echo $SSH_AUTH_SOCK
|
cat > ~/ssh-diag.sh << 'DIAGEOF'
|
||||||
ssh-add -l
|
#!/bin/bash
|
||||||
|
echo "=== SSH Agent Diagnostic ==="
|
||||||
|
echo ""
|
||||||
|
echo "1. SSH_AUTH_SOCK: $SSH_AUTH_SOCK"
|
||||||
|
echo "2. Running agents: $(pgrep -u "$USER" ssh-agent | wc -l)"
|
||||||
|
echo "3. Loaded keys:"
|
||||||
|
ssh-add -l 2>&1
|
||||||
|
echo ""
|
||||||
|
echo "4. Systemd service:"
|
||||||
|
systemctl --user status ssh-agent 2>&1 | head -5
|
||||||
|
echo ""
|
||||||
|
echo "5. Shell RC has SSH code:"
|
||||||
|
grep -q "SSH Agent" ~/.bashrc && echo " ✓ Found" || echo " ✗ Not found"
|
||||||
|
DIAGEOF
|
||||||
|
|
||||||
|
chmod +x ~/ssh-diag.sh
|
||||||
|
bash ~/ssh-diag.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
Your key should be loaded without manual re-entry.
|
### Common Issues
|
||||||
|
|
||||||
## Troubleshooting Step 7
|
**"Could not open a connection to your authentication agent"**
|
||||||
|
|
||||||
If agent is still not persistent:
|
|
||||||
|
|
||||||
Make sure code is at the END of ~/.bashrc:
|
|
||||||
```bash
|
|
||||||
tail -20 ~/.bashrc | grep "SSH Agent"
|
|
||||||
```
|
|
||||||
|
|
||||||
If agent still dies, try this simpler version:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Simpler version - add to end of ~/.bashrc
|
# Check if service is running
|
||||||
if [ -z "$SSH_AUTH_SOCK" ] ; then
|
systemctl --user status ssh-agent
|
||||||
eval "$(ssh-agent -s)" > /dev/null
|
|
||||||
ssh-add ~/.ssh/id_ed25519 2>/dev/null
|
# If stopped, start it
|
||||||
fi
|
systemctl --user start ssh-agent
|
||||||
|
|
||||||
|
# Then reload shell
|
||||||
|
source ~/.bashrc
|
||||||
```
|
```
|
||||||
|
|
||||||
Test with:
|
**"Permission denied (publickey)"**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bash
|
# Check key permissions
|
||||||
echo "Agent: $SSH_AUTH_SOCK"
|
ls -la ~/.ssh/id_ed25519
|
||||||
ssh-add -l
|
|
||||||
|
# Should be: -rw------- (600)
|
||||||
|
chmod 600 ~/.ssh/id_ed25519
|
||||||
|
|
||||||
|
# Try adding key manually
|
||||||
|
ssh-add ~/.ssh/id_ed25519
|
||||||
```
|
```
|
||||||
|
|
||||||
## Permissions Explained
|
**Agent running but key not loaded after reboot**
|
||||||
|
|
||||||
- chmod 600 = rw------- (you only)
|
```bash
|
||||||
- chmod 700 = rwx------ (you only)
|
# Check if auto-add code is in ~/.bashrc
|
||||||
- SSH requires strict permissions for security
|
tail -10 ~/.bashrc | grep "ssh-add"
|
||||||
|
|
||||||
|
# If missing, add it:
|
||||||
|
echo 'if [ -z "$(ssh-add -l 2>/dev/null | grep id_ed25519)" ]; then ssh-add ~/.ssh/id_ed25519 2>/dev/null; fi' >> ~/.bashrc
|
||||||
|
```
|
||||||
|
|
||||||
|
**Systemd service fails to start**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check journal logs
|
||||||
|
journalctl --user -u ssh-agent
|
||||||
|
|
||||||
|
# Restart service
|
||||||
|
systemctl --user daemon-reload
|
||||||
|
systemctl --user restart ssh-agent
|
||||||
|
```
|
||||||
|
|
||||||
|
**Multiple ssh-agent processes running**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Kill all agents
|
||||||
|
pkill -u "$USER" ssh-agent
|
||||||
|
|
||||||
|
# Restart systemd service cleanly
|
||||||
|
systemctl --user restart ssh-agent
|
||||||
|
|
||||||
|
# Reload shell
|
||||||
|
source ~/.bashrc
|
||||||
|
```
|
||||||
|
|
||||||
## After SSH Works
|
## After SSH Works
|
||||||
|
|
||||||
|
Now you can clone from Gitea without passwords:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bash <(curl -s http://100.120.125.113:3000/pdm/homelab-agents/raw/branch/main/scripts/bootstrap-agents.sh)
|
git clone git@100.120.125.113:pdm/homelab-agents.git ~/.homelab-agents
|
||||||
init-project my-project
|
git clone git@100.120.125.113:pdm/vps-system-apps.git ~/projects/system-apps
|
||||||
```
|
```
|
||||||
|
|
||||||
Done! Now use Gitea without passwords.
|
Or use the bootstrap script:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash <(curl -s http://100.120.125.113:3000/pdm/homelab-agents/raw/branch/main/scripts/bootstrap-agents.sh)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Quick Reference
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check agent status
|
||||||
|
systemctl --user status ssh-agent
|
||||||
|
|
||||||
|
# Check loaded keys
|
||||||
|
ssh-add -l
|
||||||
|
|
||||||
|
# Manually add key
|
||||||
|
ssh-add ~/.ssh/id_ed25519
|
||||||
|
|
||||||
|
# Test Gitea connection
|
||||||
|
ssh -T git@100.120.125.113
|
||||||
|
|
||||||
|
# Restart agent service
|
||||||
|
systemctl --user restart ssh-agent
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**The systemd method should give you truly persistent SSH agent across all sessions, logouts, and reboots!**
|
||||||
|
|||||||
Reference in New Issue
Block a user