En corto

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# ~/.config/systemd/user/ssh-agent.service
[Unit]
Description=SSH authentication agent

[Service]
ExecStart=/usr/bin/ssh-agent -a %t/ssh-agent.socket -D
Type=simple

[Install]
WantedBy=default.target
1
2
systemctl --user daemon-reload
systemctl --user enable --now ssh-agent

Y en tu ~/.bashrc o ~/.zshrc:

1
2
3
4
5
export SSH_AUTH_SOCK="$XDG_RUNTIME_DIR/ssh-agent.socket"
if ! ssh-add -l &>/dev/null; then
  echo "Adding keys..."
  ssh-add -t 1d ~/.ssh/id_ed25519
fi

Cierra sesión y vuelve a entrar. Ahora todas tus shells comparten un solo agente con un socket estable, y no arrancas un ssh-agent nuevo por cada terminal.

El patrón clásico (eval "$(ssh-agent)" en el .bashrc) levanta un agente por shell, deja procesos huérfanos y pierde las llaves entre terminales. Dejar que systemd posea el agente resuelve las tres cosas: un proceso, un socket, un ciclo de vida.

Requisitos

openssh (trae ssh-agent y ssh-add) y una sesión de systemd de usuario (cualquier distro moderna con logind). Verifica:

1
ssh-agent -V 2>/dev/null; ssh-add -l; echo "XDG_RUNTIME_DIR=$XDG_RUNTIME_DIR"

Si $XDG_RUNTIME_DIR está vacío no tienes una sesión de usuario real (por ejemplo entraste con su); entra por SSH o en consola como tu usuario.

1. Crea el servicio de usuario

Un servicio --user vive en ~/.config/systemd/user/ y corre con tu cuenta, sin root:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
mkdir -p ~/.config/systemd/user
cat > ~/.config/systemd/user/ssh-agent.service <<'EOF'
[Unit]
Description=SSH authentication agent

[Service]
ExecStart=/usr/bin/ssh-agent -a %t/ssh-agent.socket -D
Type=simple

[Install]
WantedBy=default.target
EOF
  • %t se expande al runtime dir del usuario ($XDG_RUNTIME_DIR, típicamente /run/user/<uid>), así que el socket queda en /run/user/<uid>/ssh-agent.socket.
  • -a fija esa ruta de socket (en vez de una aleatoria en /tmp), que es lo que luego exportamos.
  • -D deja el agente en primer plano; es lo correcto para Type=simple.

Si prefieres que aplique a todos los usuarios de la máquina, pon el archivo en /etc/systemd/user/ssh-agent.service (requiere root). Para tu cuenta, ~/.config/systemd/user/ es lo más limpio. Elige una ubicación, no las dos.

2. Exporta el socket y carga la llave al entrar

Agrega esto a tu ~/.bashrc o ~/.zshrc:

1
2
3
4
5
export SSH_AUTH_SOCK="$XDG_RUNTIME_DIR/ssh-agent.socket"
if ! ssh-add -l &>/dev/null; then
  echo "Adding keys..."
  ssh-add -t 1d ~/.ssh/id_ed25519
fi
  • El export tiene que ir antes del ssh-add, o el cliente no sabrá con qué agente hablar.
  • ssh-add -l sale con código 1 si el agente no tiene llaves y 2 si no puede conectarse al socket; el if ! cubre ambos casos y (re)carga.
  • -t 1d hace que la llave expire en un día. Quita el -t si quieres que dure hasta que reinicies el agente.

3. Habilita y verifica

1
2
3
systemctl --user daemon-reload
systemctl --user enable --now ssh-agent
systemctl --user status ssh-agent   # active (running)

Abre una terminal nueva (o source ~/.bashrc) y comprueba que la llave esté cargada:

1
ssh-add -L   # lista las llaves públicas en el agente

Qué mueve cada pieza

PiezaQué hace
ssh-agent.service (--user)Mantiene un agente vivo, dueño de systemd
-a %t/ssh-agent.socketSocket en una ruta fija y predecible
SSH_AUTH_SOCK en el rcApunta cada shell a ese socket
ssh-add -t 1d id_ed25519Carga la llave al entrar, con caducidad opcional

Trampas

  • Usa el nombre real de tu llave. Muchas guías dicen id_rsa; las llaves modernas son id_ed25519. Si el archivo no existe, ssh-add falla en silencio dentro del if.
  • Lingering: por defecto el servicio de usuario muere cuando cierras la última sesión. Si necesitas que el agente siga vivo sin login activo (cron, un runner de CI en la máquina), habilita el lingering: loginctl enable-linger $USER.
  • El socket debe coincidir. El -a %t/ssh-agent.socket de la unit y el SSH_AUTH_SOCK="$XDG_RUNTIME_DIR/ssh-agent.socket" del rc apuntan al mismo archivo. Si cambias uno, cambia el otro.
  • &>/dev/null es de bash/zsh. En un /bin/sh estricto (dash) usa >/dev/null 2>&1.
  • Passphrase: si tu llave tiene passphrase, el ssh-add del login te la pedirá una vez por caducidad. Con -t 1d, una vez al día.
  • No mezcles agentes. Si algún profile hacía eval "$(ssh-agent)", quítalo; si no, tendrás dos agentes y un SSH_AUTH_SOCK que baila entre ellos.

Ver también