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.
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
On our local machine, we’ll launch the script like this:
ssh dave@fedora-36.local 'bash -s' < local.sh
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
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
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"
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
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.
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
As expected, we see a new entry in the “timestamp.txt” file.
cat timestamp.txt
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