When ssh'ing, how can I set an environment variable on the server that changes from session to session?

95

29

When I ssh into a server, how can I pass an environment variable from the client to the server? This environment variable changes between different invocations of ssh so I don't want to overwrite $HOME/.ssh2/environment every time I do an ssh call. How can I do this?

Ross Rogers

Posted 2010-07-13T16:59:57.873

Reputation: 3 025

2

Possible duplicate of how can I pass an environment variable through an ssh command?

– Tonin – 2015-12-21T12:32:43.027

1Other way round, as this is already more popular. It doesn't matter it's older. – kenorb – 2015-12-23T10:10:05.563

2You question needs to be a liiittle more specific. – Ignacio Vazquez-Abrams – 2010-07-13T17:09:24.637

3The question was clear enough to me. However, from the ssh man page, I don't see any way to do that other than setting the variable manually once you've logged in to the server, unless you modify ~/.ssh2/environment. – garyjohn – 2010-07-13T17:23:24.493

Is it a different variable each time? Or a different value? – Paused until further notice. – 2010-07-13T17:52:39.883

Different value each time. – Ross Rogers – 2010-07-13T20:37:01.163

Answers

116

Of course, you can set the environment variable inside the command, however you'll have to be careful about quoting: remember that your shell is going to parse your local command line, and then the remote shell will have a go on the string it receives.

If you want a variable to get the same value on the server that it has on the client, try the SendEnv option:

ssh -o SendEnv=MYVAR server.example.com mycommand

This requires support from the server, though. With OpenSSH, the variable name has to be authorized in /etc/sshd_config.

If the server only allows certain specific variable names, you can work around that; for example a common setup allows LC_* through, and you can do the following:

ssh -o SendEnv=LC_MYVAR server.example.com 'MYVAR=$LC_MYVAR; unset LC_MYVAR; export MYVAR; mycommand'

If even LC_* is not an option, you can pass information in the TERM environment variable, which is always copied (there may be a length limit however). You'll still have to make sure that the remote shell doesn't restrict the TERM variable to designate a known terminal type. Pass the -t option to ssh if you're not starting a remote interactive shell.

env TERM="extra information:$TERM" ssh -t server.example.com 'MYVAR=${TERM%:*}; TERM=${TERM##*:}; export MYVAR; mycommand'

Another possibility is to define the variable directly in the command:

ssh -t server.example.com 'export MYVAR="extra information"; mycommand'

Thus, if passing a local variable:

ssh -t server.example.com 'export MYVAR='"'$LOCALVAR'"'; mycommand'

However, beware of quoting issues: the value of the variable will be interpolated directly into the shell snippet executed on the remote side. The last example above assumes that $LOCALVAR does not contain any single quotes (').

Gilles 'SO- stop being evil'

Posted 2010-07-13T16:59:57.873

Reputation: 58 319

Security concern: be thoughtful when passing variables via command-line, if they contain sensitive info (like ID number, sensitive key, filename), as the value may be read by other users (via ps, for example). – Wirawan Purwanto – 2016-06-01T14:54:04.630

@Crossfit_and_Beer You aren't addressing the asker. – Gilles 'SO- stop being evil' – 2018-10-17T16:50:01.153

2Thanks much, I was in a rage that the stupid LC_* variables are exported on ssh and your answer directed me where to look. I just have to disable that in ~/.ssh/config – akostadinov – 2012-10-09T16:37:10.417

1I'm in the situation of the original poster, but the variable that I wanted forwarded is TERM, so I'm a bit puzzled by your answer. Has this automatic forwarding of TERM been disabled by recent OpenSSH versions? – Doub – 2012-11-20T18:15:21.643

1@Doub The default is to refuse all environment variables on the server side, with AcceptEnv directives in sshd_config as desired by the administrator. But TERM is treated specially, as far as I know there is no way to filter it on the server side (it is set in the environment of the shell regardless of any configuration setting). Are you sure there isn't a profile script overriding it (like /etc/profile or ~/.profile or ~/.bashrc)? – Gilles 'SO- stop being evil' – 2012-11-20T18:24:20.357

2@Gilles: I tested it again, and unless I explicitly add TERM to my AcceptEnv directive, the TERM is not passed on. I not opening a shell, but running a command directly, for example: "ssh -o SendEnv=TERM shell.example.com env". That prints all environment variable, and TERM only appears if it's in SendEnv on the client and AcceptEnv on the server. If I run "ssh -o SendEnv=TERM shell.example.com echo ${TERM}" withoug the AcceptEnv or SendEnv, it prints "dumb", which I'm not sure where it comes from (env doesn't even list TERM in that case). – Doub – 2012-11-27T14:37:01.427

7@Doub Oh, I see. TERM is only transmitted if the client requests the server to allocate a tty. If there's no terminal on the remote side, it would be useless to transmit TERM. When you specify a command, if you want to have a terminal on the remote side, you need the -t command line option (or RequestTTY in ~/.ssh/config). – Gilles 'SO- stop being evil' – 2012-11-27T15:28:54.767

@Gilles: I see. My problem was that the Mercurial colour output was broken, and I assumed that it was because my xterm-256color TERM was not sent properly, but it's probably because of the lack of a tty. – Doub – 2012-11-27T19:25:51.730

@Doub The lack of a tty is what caused Mercurial not to use colors (like ls, grep, git and just about any other program with optional coloring). Either use ssh -t or hg --config color.mode=ansi (I think). – Gilles 'SO- stop being evil' – 2012-11-27T19:34:48.350

12

If you can administrate the target host you can configure sshd to allow passing your local environment variables along to the target host.

From the sshd_config man page:

 PermitUserEnvironment
     Specifies whether ~/.ssh/environment and environment= options in
     ~/.ssh/authorized_keys are processed by sshd.  The default is
     "no".  Enabling environment processing may enable users to bypass
     access restrictions in some configurations using mechanisms such
     as LD_PRELOAD.

sshd configuration typically lives at /etc/ssh/sshd_config

Duncan Beevers

Posted 2010-07-13T16:59:57.873

Reputation: 261

7It's very useful to know that this is set to "no" by default! – jathanism – 2013-10-04T22:59:35.340

6

So, on your client, you have some environment variable, and you want that to be available to the remote command? I don't think there's a way to have ssh magically pass it along, but you can probably do something like this. Instead of using, say:

ssh remote.host my_command

You can do this:

ssh remote.host env ENV_VAR=$ENV_VAR my_command

pioto

Posted 2010-07-13T16:59:57.873

Reputation: 504

"probably"? I wish I read that before actually trying this answer. Didn't work for me. – tishma – 2017-01-04T23:54:00.563

1Care to elaborate on any errors received, etc? – pioto – 2017-01-30T02:30:19.020

1@pioto Might be quoting, e.g. if ENV_VAR has spaces in it – Martin C. Martin – 2017-04-11T13:32:19.783

On Mac you have to have -t option for an interactive version, otherwise it looks stuck. So this might work: $ ssh -t remote.host env ENV_VAR=$ENV_VAR my_command – muenalan – 2018-01-11T09:53:20.910

4

On your local client, in your ~/.ssh/config you can add SetEnv, e.g.

Host myhost
  SetEnv FOO=bar

Note: Check man ssh_config.

Then on the server, make sure to allow client to pass certain environment variables in your /etc/ssh/sshd_config config file:

AcceptEnv LANG LC_* FOO BAR*

Note: Check man sshd_config.

kenorb

Posted 2010-07-13T16:59:57.873

Reputation: 16 795

3

@emptyset's response (which didn't work for me) led me to this answer:

You can add this command to your ~/.ssh/authorized_keys file:

command="/usr/bin/env VARIABLE=<something> $SHELL" ssh-rsa <key>

export VARIABLE=<something> was immediately exiting, and the SSH connection was closed (locking me out of the server), whereas /usr/bin/env ... $SHELL will run your default shell with a modified environment.

madprog

Posted 2010-07-13T16:59:57.873

Reputation: 31

This just hangs when logging in for me. When I remove it SSH returns to normal and I get my usual login shell. – Nick Sweeting – 2018-05-15T03:16:39.543

@NickSweeting have you tried maybe replacing $SHELL with an actual shell? Also check that /usr/bin/env exists on the server. However the solution is not perfect: I have noticed that it hang when I wanted to use scp or an inline command. – madprog – 2018-05-15T15:50:30.177

Yes, that was the first thing I tried. Unfortunately never got it to work, ended up enabling PermitUserEnvironment yes and using environment="..." instead of command="...". – Nick Sweeting – 2018-05-16T17:59:23.723

This is working nicely for me. – Mr. Tao – 2019-04-16T11:40:44.043

1

You could try invoking a custom command, assuming you have password-less ssh login setup. On the server, edit your ~/.ssh/authorized_keys entry that corresponds to the key from you client:

command="export VARIABLE=<something>" ssh-rsa <key>

Look at this link in the section Forced Command for a little more detail.

emptyset

Posted 2010-07-13T16:59:57.873

Reputation: 421

1I tried this, but it doesn't work. It runs the command and exits, so there's no interactive session. Is that the normal behavior? If so, that could be useful if all you want to do is allow a specific key to trigger a specific command, but if you want to pass info that is used in a session (as the question states) then it is useless for that purpose. There IS no session. – iconoclast – 2011-11-07T22:17:48.647

1

I was making a custom build of OpenSSH for a device with a cramfs in the home directory and /etc (Cram FS is read-only) so ~/.ssh/environment would not work not without rebuilding the entire FS and these were field deployed devices(Embedded Systems Hence the use of CRAMFS). You can specify in the sshd_config the location of the authroized_keys file but for some reason the environment= only work for environment variables in the ~/.ssh/authroized_keys. Editing the /etc/profile wasn't an option and I had to load ssh in a non-standard directory. In session.c after the child_set_env(..."MAIL"...) just add the enviroment variables you need(This is a hack I know...) but just incase someone needs some hardcoded envs for a session if you are compiling from source you can do this. TGI-FLOSS

Will

Posted 2010-07-13T16:59:57.873

Reputation: 11

0

just one simple command :

ssh -t your_host_or_ip 'export some_var_name=whatever_you_want; bash'

grepit

Posted 2010-07-13T16:59:57.873

Reputation: 133