0

I want to run a local bash script on a remote machine to install and sets up dokku and its plugins. (ssh root@remotehost 'bash -s' < dokku.sh) The script requires a few config values like AWS_BACKUP_ACCESS etc. Those variables are stored in a separate json file, like this:

/home/project/env.json

{
  "DB_NAME": "mydb",
  "APP_NAME": "web",
  "AWS_BACKUP_ACCESS": "xxx",
  "AWS_BACKUP_SECRET": "yyy",
}

dokku.sh

#!/bin/bash

json_file="/home/project/env.json"
# export all key values from env.json to globa env
for s in $(cat $json_file | jq -r "to_entries|map(\"\(.key)=\(.value|tostring)\")|.[]" ); do
    export $s;
done

wget https://raw.githubusercontent.com/dokku/dokku/v0.25.7/bootstrap.sh;
sudo DOKKU_TAG=v0.25.7 bash bootstrap.sh
sudo dokku plugin:install https://github.com/dokku/dokku-postgres.git postgres
dokku postgres:create "$DB_NAME"
dokku postgres:link "$DB_NAME" "$APP_NAME"
# use the Backup IAM profile
dokku postgres:backup-auth "$DB_NAME" "$AWS_BACKUP_ACCESS" "$AWS_BACKUP_SECRET" "$AWS_DEFAULT_REGION"

My question is how to make the following part works when running the script on a remote server since the file /home/project/env.json is stored locally:

json_file="/home/project/env.json"
# export all key values from env.json to globa env
for s in $(cat $json_file | jq -r "to_entries|map(\"\(.key)=\(.value|tostring)\")|.[]" ); do
    export $s;
done

2 Answers 2

1

Read the JSON file locally, and then make the SSH connection. This would additionally no longer require jq to be available on the remote system.

Your script:

#!/bin/sh

set -u -e

wget 'https://raw.githubusercontent.com/dokku/dokku/v0.25.7/bootstrap.sh'

sudo DOKKU_TAG=v0.25.7 bash bootstrap.sh
sudo dokku plugin:install 'https://github.com/dokku/dokku-postgres.git' postgres

dokku postgres:create "$DB_NAME"
dokku postgres:link "$DB_NAME" "$APP_NAME"

# use the Backup IAM profile
dokku postgres:backup-auth \
    "$DB_NAME" \
    "$AWS_BACKUP_ACCESS" \
    "$AWS_BACKUP_SECRET" \
    "$AWS_DEFAULT_REGION"

Running it:

ssh root@remotehost "env $( jq -r 'to_entries | map("\(.key)=\(.value)") | @sh' /home/project/env.json ) sh -s" <dokku.sh

This calls env on the remote system, with a list of environment variables and their values as arguments. At the end of the argument list is sh -s which will read your dokku.sh script and execute it (the script uses no bashisms, so there's no need to invoke a more advanced shell).

I'm also using set -u in the script to make it terminate if it encounters an unset variable, and set -e to terminate on any error.

You could obviously wrap the ssh-calling bit in a local script, or use something like Ansible to do the whole thing more reliably.

1

The easiest way would be to just scp the env.json file from the local machine to the remote, use it in your script, and delete it afterwards.

Alternatively, you can write a script that sets/exports the variables it needs, and scp the script to the remote server before running it.

In fact, a lot of PITA problems with ssh involving quoting and white-space and variables can be eliminated just by scp-ing a script and/or data files to the remote server and running the script instead of trying to do it in a one-liner with multiple levels of nested quoting.

Note that it's pretty common for sshd to be configured with PermitUserEnvironment no (it's usually compiled in as one of sshd's default settings), so the user's environment is not passed from the client machine to the ssh server. So setting the env vars on your local machine is not likely to work.

1
  • 2
    BTW, if you need to do things like this on lots of machines, you should probably look into tools like ansible, puppet, or chef
    – cas
    Oct 18, 2021 at 5:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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