Perl で、ssh でリモートのサーバにアクセスしてファイルをアップロード(SCP)する方法 (Net::SSH2)

バックアップのためにリモートのサーバにファイルをコピー(アップロード)したい。

そんな欲求が私の中に生まれた。Linux ではファイルを ssh でコピーするのに scp というコマンドがあるので、早速試してみたのは Net::SCP という Perl のモジュールなのだが、なぜかこのモジュールのメソッドにはパスワードを指定するものがない。ホスト名とユーザー名しか指定しないのだ。ではパスワードはどこにいった?

Net::SCPに書いてあるように、どうやら ssh の手動コマンドのようにユーザー名とパスワードを指定するのではなく、パスワードは ssh-keygen -t rsa または dsa として、できた公開鍵をリモートサーバの ~/.ssh/authorized_key というところに置くことによって、セキュリティを高めるとともにパスワードが要らない、ということらしいのだ。うーんめんどい。しかし仕方がない、やってみようということで実際に私は試してみたのだが、いろいろ試してみてうまくいかなかった。ソースはこんな感じ。

use Net::SCP; our $HOSTNAME = 'yourdomain.com'; our $USERNAME = 'yourname'; our $REMOTE_DIR = 'path_to_remote_dir'; our $FILENAME = 'filename_to_put'; $scp = Net::SCP->new($HOSTNAME, $USERNAME) or die $scp->{errstr}; $scp->login($USERNAME) or die $scp->{errstr}; $scp->cwd($REMOTE_DIR) or die $scp->{errstr}; $scp->put($FILENAME) or die $scp->{errstr}; $scp->quit;

仕方がないので Net::SSH::Expect モジュールを試してみるとことにした。

use Net::SSH::Expect; our $HOSTNAME = 'yourdomain.com'; our $USERNAME = 'yourname'; our $PASSWORD = 'yourpassword'; our $LOCAL_FILE = 'filename_to_put'; our $REMOTE_FILE = 'path_to_remote_file'; my $scp = Net::SCP::Expect->new(); $scp->host($HOSTNAME); $scp->login($USERNAME, $PASSWORD); $scp->scp($LOCAL_FILE, $REMOTE_FILE);

しかしこれでも成功しない。ほんじゃあ Net::SFTP はどうだ?

use Net::SFTP; our $HOSTNAME = 'yourdomain.com'; our $USERNAME = 'yourname'; our $PASSWORD = 'yourpassword'; our $LOCAL_FILE = 'filename_to_put'; our $REMOTE_FILE = 'path_to_remote_file'; my %arg = ('user'=>$USERNAME, 'password'=>$PASSWORD, 'debug'=>true, 'Passive'=>true); my $sftp = Net::SFTP->new($HOSTNAME, %arg); $sftp->put($LOCAL_FILE, $REMOTE_FILE);

うわ、ダメだ orz。そもそも FTP はできるのだろうか?

use Net::FTP; our $HOSTNAME = 'yourdomain.com'; our $USERNAME = 'yourname'; our $PASSWORD = 'yourpassword'; our $LOCAL_FILE = 'filename_to_put'; our $REMOTE_DIR = 'path_to_remote_dir'; $ftp = Net::FTP->new($HOSTNAME, Debug => 1); $ftp->login($USERNAME, $PASSWORD); $ftp->cwd($REMOTE_DIR); $ftp->put($LOCAL_FILE); $ftp->quit;

今度はうまくいった。しかし!!! 2度実行させると

553 Could not create file.

となりエラー。もちろんディレクトリやファイルのパーミッション、所有権もチェックした。いろいろ権限を変えてみたものの、同じエラーでつまずく。うーんじゃあ、Net::SSH2 モジュールはどうだ?

use Net::SSH2; our $HOSTNAME = 'yourdomain.com'; our $USERNAME = 'yourname'; our $PASSWORD = 'yourpassword'; our $LOCAL_FILE = 'filename_to_put'; our $REMOTE_FILE = 'path_to_remote_file'; my $ssh2 = Net::SSH2->new(); $ssh2->connect($HOSTNAME) or die; if ($ssh2->auth_keyboard($USERNAME, $PASSWORD)) { $ssh2->scp_put($LOCAL_FILE, $REMOTE_FILE); }

成功!何度でもコピーできる。しかも FTP と違ってセキュアだ。めでたしめでたし。