Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

Is there a convenient way to ensure that all logins from a given user (ie me) use the same ssh-agent? I hacked out a script to make this work most of the time, but I suspected all along that there was some way to do it that I had just missed. Additionally, since that time there have been amazing advances in computing technology, like for example this website.

So the goal here is that

  • whenever I log in to the box, regardless of whether it's via SSH, or in a graphical session started from gdm/kdm/etc, or at a console:
    • if my username does not currently have an ssh-agent running, one is started, the environment variables exported, and ssh-add called.
    • otherwise, the existing agent's coordinates are exported in the login session's environment variables.

This facility is especially valuable when the box in question is used as a relay point when sshing into a third box. In this case it avoids having to type in the private key's passphrase every time you ssh in and then want to, for example, do git push or something.

The script given below does this mostly reliably, although it botched recently when X crashed and I then started another graphical session. There might have been other screwiness going on in that instance.

Here's my bad-is-good script. I source this from my .bashrc.

# ssh-agent-procure.bash
# v0.6.4
# ensures that all shells sourcing this file in profile/rc scripts use the same ssh-agent.
# copyright me, now; licensed under the DWTFYWT license.

mkdir -p "$HOME/etc/ssh";

function ssh-procure-launch-agent {
    eval `ssh-agent -s -a ~/etc/ssh/ssh-agent-socket`;

if [ ! $SSH_AGENT_PID ]; then
  if [ -e ~/etc/ssh/ssh-agent-socket ] ; then
    SSH_AGENT_PID=`ps -fC ssh-agent |grep 'etc/ssh/ssh-agent-socket' |sed -r 's/^\S+\s+(\S+).*$/\1/'`; 
    if [[ $SSH_AGENT_PID =~ [0-9]+ ]]; then
      # in this case the agent has already been launched and we are just attaching to it. 
      ##++  It should check that this pid is actually active & belongs to an ssh instance
      export SSH_AGENT_PID;
      SSH_AUTH_SOCK=~/etc/ssh/ssh-agent-socket; export SSH_AUTH_SOCK;
      # in this case there is no agent running, so the socket file is left over from a graceless agent termination.
      rm ~/etc/ssh/ssh-agent-socket;

Please tell me there's a better way to do this. Also please don't nitpick the inconsistencies/gaffes ( eg putting var stuff in etc ); I wrote this a while ago and have since learned many things.

share|improve this question
KeyError: 'DWTFYWT' not found; did you mean WTFPLv2? – grawity May 14 '10 at 18:53
@grawity: thanks for that link, their FAQs made my day: By the way, with the WTFPL, can I also… Oh but yes, of course you can. But can I… Yes you can. Can… Yes! hahahahahaha – quack quixote May 14 '10 at 19:06
@grawity: No, that's just what I wanted you to think, mwahahaha. – intuited May 14 '10 at 20:58

11 Answers 11

up vote 18 down vote accepted

I might as well throw my own variation into the mix:

function sshagent_findsockets {
    find /tmp -uid $(id -u) -type s -name agent.\* 2>/dev/null

function sshagent_testsocket {
    if [ ! -x "$(which ssh-add)" ] ; then
        echo "ssh-add is not available; agent testing aborted"
        return 1

    if [ X"$1" != X ] ; then
        export SSH_AUTH_SOCK=$1

    if [ X"$SSH_AUTH_SOCK" = X ] ; then
        return 2

    if [ -S $SSH_AUTH_SOCK ] ; then
        ssh-add -l > /dev/null
        if [ $? = 2 ] ; then
            echo "Socket $SSH_AUTH_SOCK is dead!  Deleting!"
            rm -f $SSH_AUTH_SOCK
            return 4
            echo "Found ssh-agent $SSH_AUTH_SOCK"
            return 0
        echo "$SSH_AUTH_SOCK is not a socket!"
        return 3

function sshagent_init {
    # ssh agent sockets can be attached to a ssh daemon process or an
    # ssh-agent process.


    # Attempt to find and use the ssh-agent in the current environment
    if sshagent_testsocket ; then AGENTFOUND=1 ; fi

    # If there is no agent in the environment, search /tmp for
    # possible agents to reuse before starting a fresh ssh-agent
    # process.
    if [ $AGENTFOUND = 0 ] ; then
        for agentsocket in $(sshagent_findsockets) ; do
            if [ $AGENTFOUND != 0 ] ; then break ; fi
            if sshagent_testsocket $agentsocket ; then AGENTFOUND=1 ; fi

    # If at this point we still haven't located an agent, it's time to
    # start a new one
    if [ $AGENTFOUND = 0 ] ; then
        eval `ssh-agent`

    # Clean up
    unset AGENTFOUND
    unset agentsocket

    # Finally, show what keys are currently in the agent
    ssh-add -l

alias sagent="sshagent_init"

And then every time I log in, if I want an agent attached (which I don't always), I just type sagent.

share|improve this answer
if [ ! -x "$(which ssh-add)" ]; should be replaced with if ! which ssh-add; or if ! command -v ssh-add. (Remember, [ is just a command) – grawity May 14 '10 at 19:13
Well, you can do that, but it would actually need to be if ! which ssh-add > /dev/null to prevent the path from being printed, at which point I'm not really sure it's any clearer, though I suppose it does save you one extra command invocation. – Zed May 14 '10 at 20:32
so basically the answer is no, then. crap. Well this looks to be more evolved than my hack, so probably it will be useful. Weird that there's not a more structured way of doing this though, it seems like something that would be quite useful. – intuited May 14 '10 at 20:56
I'm in a fit of repositorifying everything these days, so I set up a github repo for your script. Thanks again. I hope I was formal enough with the licensing :~/ – intuited Jul 27 '10 at 2:03
I don't mind. Please comment here if someone submits improvements to it, though. – Zed Aug 27 '10 at 19:37

ssh -A [user@]remotehost

I think this might be what you're looking for. Use the -A switch when running ssh forward your ssh-agent. Here's a usecase:

I have a remote server that has some git repos on it with a remote pointing to github. Without an ssh-agent running in a screen session, I have to enter the passphrase for my key in order to do a "git pull origin master". Booo! In addition, I must have my private key installed on the remote server - more Boooo!

Instead, simply using ssh -A [user@]remotehost passes along my locally running ssh-agent. Now, I no longer need my private key to even exist on the remote host. I don't believe you need to do any scripting at all with ssh-agent.

share|improve this answer
This is what I was looking for, thx! – tmow Aug 18 '11 at 7:26
Did not know about this, but it turned out to be exactly what I was looking for when I made my way to this question. – Will McCutchen Nov 17 '11 at 14:34
This is even better than what I was looking for! Great answer! – Hugo Jan 28 '13 at 5:30
See also man 5 ssh_config for the ForwardAgent config setting. It enables agent forwarding by default, removing the need for the -A argument. Before using agent forwarding be aware that there is a security risk where other privileged users on the remote machine could access the forwarded agent socket. This is also mentioned on the man page. This is explained well here. – starfry Jun 23 '14 at 10:00

Here's a pretty nice one that works in Cygwin as well:


function start_agent {
     echo "Initialising new SSH agent..."
     /usr/bin/ssh-agent | sed 's/^echo/#echo/' > ${SSH_ENV}
     echo succeeded
     chmod 600 ${SSH_ENV}
     . ${SSH_ENV} > /dev/null

# Source SSH settings, if applicable

if [ -f "${SSH_ENV}" ]; then
     . ${SSH_ENV} > /dev/null
     #ps ${SSH_AGENT_PID} doesn't work under cywgin
     ps -efp ${SSH_AGENT_PID} | grep ssh-agent$ > /dev/null || {

Add it to your .bash_profile or .bashrc


share|improve this answer
Also works fine with Git Bash (mingw64) for windows – Dolphin May 4 at 16:39

Try using keychain, its made for that.

share|improve this answer

I prefer to keep things as simple as possible: (snippet from ~/.profile)

check-ssh-agent() {
    [ -S "$SSH_AUTH_SOCK" ] && { ssh-add -l >& /dev/null || [ $? -ne 2 ]; }

# attempt to connect to a running agent
check-ssh-agent || export SSH_AUTH_SOCK="$(< ~/.tmp/ssh-agent.env)"
# if agent.env data is invalid, start a new one
check-ssh-agent || {
    eval "$(ssh-agent -s)" > /dev/null
    echo "$SSH_AUTH_SOCK" > ~/.tmp/ssh-agent.env

I didn't think of using -a before, but it might be easier:

check-ssh-agent || export SSH_AUTH_SOCK=~/.tmp/ssh-agent.sock
check-ssh-agent || eval "$(ssh-agent -s -a ~/.tmp/ssh-agent.sock)" > /dev/null
share|improve this answer
Nice. I've simplified it somewhat in my answer (below). – Ether Mar 6 '15 at 20:15

I have recently started using:

All I have to do is add:

  alias ssh=/path/to/ssh-ident

In my .bashrc file. The script takes care of:

  • creating an agent when it is first needed
  • load the necessary keys on demand
  • share agents across multiple login sessions
  • manage multiple agents, one for each 'identity' that I use online, and use the right agent based on the host I'm connecting to or the current working directory.
share|improve this answer

Again an example to put in your .bash_profile immediately and asking to add your default key at logon. Forwarding was not an option in my case.

do-ssh-agent() {
  # function to start the ssh-agent and store the agent details for later logon
  ssh-agent -s > ~/.ssh-agent.conf 2> /dev/null
  . ~/.ssh-agent.conf > /dev/null

# set time a key should be kept in seconds

if [ -f ~/.ssh-agent.conf ] ; then
  . ~/.ssh-agent.conf > /dev/null
  ssh-add -l > /dev/null 2>&1
  # $?=0 means the socket is there and it has a key
  # $?=1 means the socket is there but contains no key
  # $?=2 means the socket is not there or broken
  if [ $stat -eq 1 ] ; then
    ssh-add -t $keyage > /dev/null 2>&1
  elif [ $stat -eq 2 ] ; then
    rm -f $SSH_AUTH_SOCK
    ssh-add -t $keyage > /dev/null 2>&1
  ssh-add -t $keyage > /dev/null 2>&1
share|improve this answer

This is my solution, adapted from (in this thread):

# attempt to connect to a running agent - cache SSH_AUTH_SOCK in ~/.ssh/
    [ -S "$SSH_AUTH_SOCK" ] || export SSH_AUTH_SOCK="$(< ~/.ssh/ssh-agent.env)"

    # if cached agent socket is invalid, start a new one
    [ -S "$SSH_AUTH_SOCK" ] || {
        eval "$(ssh-agent)"
        ssh-add -t 25920000 -K ~/.ssh/id_rsa
        echo "$SSH_AUTH_SOCK" > ~/.ssh/ssh-agent.env
share|improve this answer

In my case I have posh-git setup in PowerShell and wanted cygwin to use the same ssh-agent. I had to do some path manipulation since they use different tmp folders, and the .env file created was UTF16 with BOM and CR\LF so that was fun to deal with. Adding the following to the .bashrc used by cygwin should work:

# Connect to ssh-agent started by posh-git
if [ -z $SSH_AUTH_SOCK ] && [ -z $SSH_TTY ]; then  # if no agent & not in ssh
  if [ -f "$SSH_AGENT_ENV/.ssh/SSH_AUTH_SOCK.env" ]; then
    AUTH_SOCK=$(iconv -c -f UTF-16LE -t US-ASCII "$SSH_AGENT_ENV/.ssh/SSH_AUTH_SOCK.env" | tr -d '\r\n')
    export SSH_AUTH_SOCK="${AUTH_SOCK/\/tmp/$SSH_AGENT_ENV}"
    ssh-add -l > /dev/null
    if [ $? = 2 ] ; then
      echo "Failed to setup posh-git ssh-agent using $AUTH_SOCK"
      unset SSH_AUTH_SOCK
      echo "Found posh-git ssh-agent $AUTH_SOCK"
  else #Start new agent if you want (not shared by posh-git)
    echo "failed to setup posh-git ssh-agent"
    #eval `ssh-agent -s` > /dev/null
share|improve this answer

create file ~/


function initialize {
    pgrep ssh-agent && kill $(pgrep ssh-agent)
    ssh-agent -s > $agent_out_file 
    . $agent_out_file

pgrep ssh-agent
if [ $? -eq 0 ]; then # ssh agent running
    ssh-add -l > /dev/null 2>&1
    if [ $status -eq 0 ]; then # can connect to ssh agent and keys available
        echo nothing to do
    elif [ $status -eq 1 ]; then # can connect to ssh agent and no keys available
        echo nothing to do
    elif [ $status -eq 2 ]; then # cannot connect to ssh agent
        . $agent_out_file
else # ssh agent not running

include the file in .bashrc

. ~/
share|improve this answer

This is something I've added which works for me. It first checks to see if you have an agent running, if yes it'll set the proper environments for it, if not it'll create it. Also eliminates creating extra agents:

Just put it in your .bashrc

function start_agent() {
    killall ssh-agent  2> /dev/null
    ssh-agent | sed 's/ Agent pid//' > $SSH_ENV
    ssh-add ~/.ssh/bb_readonly_rsa 2> /dev/null

mkdir -p "$HOME/.ssh/agent"

if [[ -e $SSH_PID_FILE ]]; then
    PROCESS=$(ps -p $SSH_PID -o comm=)

    if [[ $PROCESS == 'ssh-agent' ]]; then
        . $SSH_ENV > $SSH_PID_FILE
share|improve this answer

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.