Category Archives: ssh

SSH trick: temporarily return to your local shell

If you are using SSH to access a command shell on a remote system and you would like to temporarily return to a shell on your local system, there is an easy way to do so.

Simply type a tilda (“~”) and control-z.

This will place your SSH session into the background. You will be in a shell on your local system.

You can get the job number of the SSH session with:

jobs

Then, to return to the remote session (assuming that the job number you saw when you entered the above command was “1”), enter:

fg 1

Note that the remote shell will not print the prompt, press enter once to see the remote session prompt again.

My remote MySQL backup script in Perl – rtar_mysql.pl

Before you can use this script, you need to set up SSH so your local cron can access the remote servers without a password.

One thing to note about this script is that it automatically rotates the archived dump files; keeping a fie for the 1st of the week on a month, 1st of the month and 1st of the year.

see: Using Public/Private Key Pairs with SSH

Then, just modify the script for your database/servers (the block @ line 22).

This will create a series of files over time with daily/weekly/monthly MySQL dump backups.

#!/usr/bin/perl -w
# rtar_mysql.pl
#
# No arguments. The program is to be modified to include each database to be archived.
#
# Saves a tar of a remote mysql dump in a rotating file.
#
# This is used on Andrew's workstation to automatically grab a sql dump tar of each database daily.
#
use strict;
use warnings;

use DateTime;

my $fileError;
my $jobError  = 0;
my $jobErrors = "";
my $result;

# Specify a data block for each remote database to be archived.
my %dumpJobs = (
				 'db1' => {
							'remoteServer' => 'server_1',
							'database'     => 'database_name_1',
							'dbUser'       => 'database_username_1',
							'dbPassword'   => 'database_password_1',
							'dumpFilename' => 'server_1-database_name_1.dump.sql',
							'mysqlDumpCmd' => '/usr/bin/mysqldump',
							'tarCmd'       => '/bin/tar',
				 },
				 'db2' => {
							'remoteServer' => 'server_2',
							'database'     => 'database_name_2',
							'dbUser'       => 'database_username_1',
							'dbPassword'   => 'database_password_2',
							'dumpFilename' => 'server_2-database_name_2.dump.sql',
							'mysqlDumpCmd' => '/usr/bin/mysqldump',
							'tarCmd'       => '/bin/tar',
				 },
);

# Process each specified database dump/archive job.
for my $dumpJob ( sort keys %dumpJobs ) {
	$fileError = 0;
	my $tarballFilename = "$dumpJobs{$dumpJob}{'dumpFilename'}-" . tarDateSegment() . ".tgz";
	my $mysqlDumpCmd    = $dumpJobs{$dumpJob}{'mysqlDumpCmd'};
	my $tarCmd          = $dumpJobs{$dumpJob}{'tarCmd'};
	print "$dumpJob\n";

	my $dumpCommand = "ssh $dumpJobs{$dumpJob}{'remoteServer'} '$mysqlDumpCmd ";
	$dumpCommand .= "--user=$dumpJobs{$dumpJob}{'dbUser'} --password=$dumpJobs{$dumpJob}{'dbPassword'} ";
	$dumpCommand .= "$dumpJobs{$dumpJob}{'database'} > $dumpJobs{$dumpJob}{'dumpFilename'}'";
	print $dumpCommand . "\n";
	$result = system($dumpCommand );
	if ($result) { $fileError = 1; }

	if ( !$fileError ) {
		my $remoteMakeTarball = "ssh $dumpJobs{$dumpJob}{'remoteServer'} '$tarCmd ";
		$remoteMakeTarball .= "cvfz $tarballFilename $dumpJobs{$dumpJob}{'dumpFilename'}'";
		print $remoteMakeTarball . "\n";
		$result = system($remoteMakeTarball );
		if ($result) { $fileError = 1; }
	}

	if ( !$fileError ) {

		# using a more flexible naming scheme now
		my $downloadCommand = "scp $dumpJobs{$dumpJob}{'remoteServer'}:$tarballFilename .";
		print $downloadCommand . "\n";
		$result = system($downloadCommand );
		if ($result) { $fileError = 1; }
	}

	if ($fileError) {
		$jobError = 1;
		$jobErrors .= "$dumpJob ";
	}
}
if ($jobError) {
	warn "Errors were encountered: $jobErrors\n";
	exit(1);
}


sub tarDateSegment {
	my $dt = DateTime->now();

	my ( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst ) = localtime(time);
	$year += 1900;
	my $dateTime = sprintf "%4d-%02d-%02d %02d:%02d:%02d", $year, $mon + 1, $mday, $hour, $min, $sec;
	my $date     = sprintf "%4d-%02d-%02d",                $year, $mon + 1, $mday;
	my @weekdays = qw( sun mon tue wed thu fri sat );
	my $weekday  = $weekdays[$wday];
	my @months   = qw( jan feb mar apr may jun jul aug sep oct nov dec );
	my $month    = $months[$mon];

	my $weekOfMonth = $dt->week_of_month;

	my $dateTar = "";

	# if the first day of the year, set $dateTar like: 2009-1st
	if ( $yday == 1 ) {
		$dateTar = "$year-1st";
	}

	# if the first day of the month, set $dateTar like: feb-1st
	elsif ( $mday == 1 ) {
		$dateTar = "$month-1st";
	}

	# if the first day of the week, set $dateTar like: mon-1
	# where the number is the week of the month number
	elsif ( $wday == 1 ) {
		$dateTar = "$weekday-$weekOfMonth";
	}

	# otherwise, set the $dateTar like: mon
	else {
		$dateTar = "$weekday";
	}

	# $sec      seconds          54
	# $min      monutes          37
	# $hour     hour             11
	# $mon      month            4
	# $year     year             2009
	# $wday     weekday          3
	# $yday     day of the year  146
	# $isdst    is DST           1
	# $weekday  day of the week  wed
	# $month    month            may
	# $dateTime date and time    2009-05-27 11:37:54
	# $date     date             2009-05-27
	return $dateTar;
}

=head1 NAME

rtar_mysql.pl - Andrew's remote MySQL archive program.

=head1 SYNOPSIS

    use: rtar_mysql.pl

=head1 DESCRIPTION

This is a program I wrote to SSH/dump/tar/download/rotate archives of MySQL databases.

=over

=back

=head1 LICENSE

None.

=head1 AUTHOR

Andrew Ault 

=cut

Using Public/Private Key Pairs with SSH

This is one of those subjects that is a little difficult to convey clearly. It is a logical process and not difficult…but it is precise in the sense that certain files must be correct, be in the right places and have correct permissions. I’ve organized these instructions in three parts, key generation; local (client) side setup; remote(server) side setup.

For more information about public/private keys, see the Wikipedia article.

1. Generating a Public/Private key Pair

The private key will be named whatever you specified and the public key will have that name appended with “.pub”. These keys will be located in the ~.ssh directory. For example, using the default name for a dsa key pair, the files will be “id_dsa” and “id_dsa.pub”. Always keep the private key private. The public key is not secret and can be put in unsecure locations.

You need to generate the correct type of key for the remote system you are dealing with. In this article, we are using a dsa type key as an example. If the remote system requires an rsa key pair, generate an rsa pair instead.

To generate dsa key pair:


ssh-keygen -t dsa

The program will ask a series of prompted questions. For our purposes, it is Ok to just keep pressing the enter key for the defaults. The generated keys will be stored in your ~/.ssh directory. See the generated keys with:


ls -l ~/.ssh

2. Setup on the Local Side

Ensure Correct Permissions


chmod 700 ~/.ssh
chmod 600 ~/.ssh/*

If directory or filename permissions are not correct, ssh will fail to use the keys.

Create a config File

For each remote system, create a multi-line entry in the ~.ssh/config text file. You can create this file using your favorite editor, vi for example. File contents (one group per server, one group shown):


Host friendly_server_name_here
HostName ip_number_here
IdentityFile ~/.ssh/id_dsa
PasswordAuthentication no
Port 22
User your_username_on_remote_here

Of course, replace the three bolded items with your information for your accounts.

Give the config file the correct permissions:


chmod 600 ~/.ssh/config

3. Setup on the Remote Side

Copy the public key file you generated from your local machine to the remote machine’s .ssh directory:


scp ~/.ssh/id_dsa.pub username@servername:~/.ssh

Log in the remote machine for the next operations:


ssh username@servername

Append the contents of your public key file to ~/.ssh/the authorized_keys file:


cat ~/.ssh/id_dsa.pub >> ~/.ssh/authorized_keys

Actually, the ~/.ssh/id_dsa.pub file does not need to be there, just appended to the ~/.ssh/authorized_keys file. It was just convenient to do it this way.

Ensure Correct Permissions


chmod 700 ~/.ssh
chmod 600 ~/.ssh/*

Done!

Now you can login to the remote system with:


ssh username@servername

…and not need to enter a password!