Quick Links

Scripting repetitive tasks improves the efficiency of system administration. That's great for local machines, but what if you oversee remote servers? Can you run a local script on a remote computer? Yes!

Remote Connections

Remote system administration usually involves making a connection to the remote computer over a secure shell connection. The SSH connection provides you with a command prompt on the remote computer. You can then go right ahead and perform whatever system maintenance is required.

Shell scripting helps by letting you wrap a sequence of commands into a script that can be run as though they were a program, combining many actions into one command line instruction.

As time goes by, you'll tweak and improve your scripts. If you have many remote machines to administer, keeping the copy of each script on each server up to date and current is a pain, and an irksome overhead. It becomes an administrative task in itself and eats into the time savings that using scripts is supposed to deliver.

The ideal solution would let you keep your scripts on your local machine and run them on the remote computers over the SSH connection. That would give you simplified management with a centralized collection of scripts, and the same up-to-date script runs on all computers.

Bash and SSH provide a way to do just that.

Passwordless SSH Connections

The best way to do this is with passwordless connections, using SSH keys. By generating SSH keys on your local computer and sending them to each of the remote computers, you can connect to the remote computers securely and conveniently, without being prompted for a password each time.

Related: How to Create and Install SSH Keys From the Linux Shell

Although they can be intimidating for first-time users, SSH keys are really not difficult. They're easy to generate, simple to install on the remote servers, and frictionless when you use them with SSH. The only prerequisites are that the remote computers have the SSH daemon

        sshd
    

running, and that you have a user account on the remote computer.

If you're already doing remote system administration on them, both of these requirements must already be satisfied.

To generate an SSH key pair, type:

ssh-keygen

If you have an account called "dave" on a computer called "fedora-36.local", you could send and install your SSH public key to it with this command:

ssh-copy-id dave@fedora-36.local

Now, making an SSH connection in the usual way will authenticate using the SSH keys. You're dropped onto a command prompt on the remote server without being prompted for a password.

ssh dave@fedora-36.local

Running a Local Script Remotely

For these tests, our remote server is a Linux computer called "fedora-36.local." We've set up SSH keys and we have tested our passwordless connection to the remote server from our local computer.

Our script is very simple. It writes a timestamp into a file called "timestamp.txt", on the remote server. Note that the script concludes with the exit command. This is important, on some older systems it is possible for a script to run to completion, but the SSH connection is held open.

#!/bin/bash

date >> timestamp.txt

exit 0

Copy this text into an editor, save it as "local.sh", and then use chmod to make it executable.

chmod +x local.sh

Using chmod to make a script executable

On our local machine, we'll launch the script like this:

ssh dave@fedora-36.local 'bash -s' < local.sh

launching a local script to run on a remote server over SSH

Here's how this works.

  • ssh dave@fedora-36.local: The SSH connection we're making to the remote machine. This uses the ssh command, the pre-existing user account on the remote server, and the address of the remote server.
  • 'bash -s': This causes Bash to read commands from the standard input stream. It lets Bash read redirected or piped input.
  • < local.sh: We're redirecting the script into Bash.

When the script runs we're returned to the command prompt of the local machine. Hopping over to our remote machine, we can use cat to look inside the "timestamp.txt" file.

cat timestamp.txt

Using cat to look inside the timestamp.txt file

We can see the timestamp of the last---and currently only---connection. Running the local script several more times adds corresponding timestamps to the remote file.

cat timestamp.txt

The contents of the timestamp.txt file after several runs of the script

Of course, in a real-world situation, your script would do something more useful. But even our trivial example does demonstrate that a local script is being executed on a remote server.

Passing Arguments to the Script

You can pass command line arguments to the script. We'll modify our script to expect three command line parameters. These are redirected into the "timestamp.txt" file along with the timestamp.

Save this script as "local2.sh", and make it executable with chmod.

#!/bin/bash

echo "$1 $2 $3" >> timestamp.txt

date >> timestamp.txt

exit 0

The command we need to use is similar to the previous example, with a few changes.

ssh dave@fedora-36.local "bash -s" -- < local2.sh "How-To\ Geek" "Linux" "Articles"

launching a local script with command line parameters to run on a remote server over SSH

The double-hyphen "--" tells Bash that what follows shouldn't be considered command line parameters for the ssh command. The three parameters for the script follow the script name, as usual. Note that we've used a backslash "\" to escape the space in the "How-To\ Geek" parameter.

We can check with cat that our parameters were received and handled correctly on the remote server.

cat timestamp.txt

Checking that parameters to the script were received and processed correctly on the remote server

Running a Section of a Script Remotely

If you have a script that needs to do some local processing in order to determine what actions might be required on the remote servers, you can add a section right into that script to perform the remote actions for you.

Related: How to Use "Here Documents" in Bash on Linux

We can achieve this by using here documents. Here documents allow us to redirect lines from a  labeled section of a script into a command.  Local processing can be performed above and below the here document.

This is script "local3.sh", which contains a here document.

#!/bin/bash

# local processing can done here

# remote processing is done here

ssh -T dave@fedora-36.local << _remote_commands

# commands to be run remotely would be added here

cd /home/dave/Documents

# etc.

# Finally, update the timestamp file

echo "Script3.sh:" $(date) >> /home/dave/timestamp.txt

# this is the label that marks the end of the redirection

_remote_commands

# more local processing can be done here

exit 0

We're using the ssh command with the same connection details as before. We're connecting as user "dave" on a remote server called "fedora-36.local." We're also using the -T (disable pseudo-terminal allocation) option. This prevents the remote server from providing an interactive terminal for this connection.

The redirection "<<" is followed by the name of a label. In this example, we're using "_remote_commands." There's nothing special about this label, it is simply a label.

All commands that appear on the lines following the redirection are sent over the SSH connection. The redirection stops when the label is encountered. The execution of the script then continues with the line following the label.

Let's run our mixed local/remote processing script.

./local3.sh

Launching script3.sh with a mix of local and remote processing

As expected, we see a new entry in the "timestamp.txt" file.

cat timestamp.txt

The timestamp entry from script3.sh in the timestamp.txt file on the remote server

Extend Your Reach

Being able to run scripts remotely---that are written, stored, and maintained locally---provides a convenient administration tool. Knowing that exactly the same version of a script runs on all of your remote servers makes management much easier.

Related: How to Manage Linux Servers with the Cockpit Web Interface