scpコマンドとは?基本的な使い方とオプションを解説


scpコマンドとは?ファイル転送の強力なツール、基本的な使い方から応用、セキュリティまで徹底解説

はじめに

インターネットや企業内ネットワークが普及し、コンピュータ間でファイルをやり取りすることは日常的に行われています。ローカルマシンからリモートサーバーへファイルをアップロードしたり、リモートサーバーからローカルマシンへファイルをダウンロードしたり、あるいはリモートサーバー間で直接ファイルをコピーしたりと、様々なシナリオが存在します。

このようなファイル転送を実現するための方法はいくつか存在しますが、その中でも特にシンプルでありながら、高いセキュリティを備えているコマンドが「scp」です。scpはSecure Copyの略で、その名の通り、安全な方法でファイルをコピーするためのコマンドです。

scpは、多くのLinuxやmacOSシステムに標準で搭載されているコマンドであり、SSH(Secure Shell)プロトコルを利用してデータの暗号化とユーザー認証を行います。これにより、ネットワーク上でデータが盗聴されたり、第三者によって改ざんされたりするリスクを大幅に軽減できます。FTP(File Transfer Protocol)のような従来のファイル転送プロトコルが、特に認証情報やデータ転送において平文で情報をやり取りする脆弱性を持っていたのに対し、scpはSSHの堅牢なセキュリティ基盤の上で動作するため、より安全な選択肢として広く利用されています。

この記事では、scpコマンドの基本的な使い方から、ファイル転送をより柔軟かつ効率的に行うための様々なオプション、具体的な使用例、セキュリティに関する注意点、そしてscpの制限と他のファイル転送コマンド(sftp, rsyncなど)との比較について、詳細かつ網羅的に解説していきます。この記事を読むことで、あなたはscpコマンドを自信を持って使いこなし、安全なファイル転送を実現できるようになるでしょう。

scpコマンドの基本

scpとは何か?

scpは、Secure Shell (SSH) プロトコルを利用して、ホスト間でファイルを安全にコピーするためのコマンドラインユーティリティです。SSHはリモートマシンへの安全なログインやコマンド実行を可能にするプロトコルですが、scpはこのSSHの機能を利用して、暗号化されたチャネルを通じてファイルを転送します。

SSHプロトコル上で動作することの主な利点は以下の通りです。

  1. 暗号化: 転送されるファイルデータおよび認証情報(パスワードなど)はすべて暗号化されます。これにより、中間者攻撃(Man-in-the-Middle Attack)によるデータの盗聴や改ざんを防ぐことができます。
  2. 認証: SSHは公開鍵認証やパスワード認証など、様々な強力な認証メカニズムを提供します。scpはこの認証を利用して、正当なユーザーのみがファイル転送を行えるようにします。
  3. 既存インフラの利用: SSHサーバーが動作している環境であれば、追加のファイル転送サーバー(FTPサーバーなど)をセットアップする必要なく、すぐにscpを利用できます。多くのサーバーはデフォルトでSSHを有効にしています。

基本的な構文

scpコマンドの基本的な構文は、コピー元(SOURCE)とコピー先(DESTINATION)を指定するという点で、ローカルでのファイルコピーに使う cp コマンドと似ています。しかし、scpの場合はリモートホストを指定するための書式が加わります。

基本的な書式は以下の通りです。

bash
scp [オプション] コピー元 コピー先

コピー元とコピー先は、以下のいずれかの形式で指定します。

  • ローカルファイル/ディレクトリ: /path/to/local/file_or_directory
  • リモートファイル/ディレクトリ: [ユーザー名@]ホスト名またはIPアドレス:/path/to/remote/file_or_directory

[ユーザー名@] の部分は、リモートホストにログインするユーザー名を指定します。コピー元またはコピー先のホストで現在ログインしているユーザー名と同じ場合は省略可能です。ホスト名は、IPアドレスでもドメイン名でも構いません。

基本的なファイル転送のシナリオは以下の3つです。

  1. ローカルからリモートへのコピー: ローカルマシンのファイルをリモートサーバーへ送る。
    bash
    scp /path/to/local/file user@remote_host:/path/to/destination

    この場合、コピー元はローカルパス、コピー先はリモートパスになります。リモートパスでディレクトリを指定した場合、ファイル名はそのままでディレクトリ内にコピーされます。ファイル名を変更してコピーしたい場合は、コピー先パスに新しいファイル名を指定します。例: user@remote_host:/path/to/destination/new_file_name.

  2. リモートからローカルへのコピー: リモートサーバーのファイルをローカルマシンへ持ってくる。
    bash
    scp user@remote_host:/path/to/remote/file /path/to/local/destination

    この場合、コピー元はリモートパス、コピー先はローカルパスになります。同様に、コピー先でディレクトリを指定するとそのディレクトリ内に元のファイル名でコピーされ、ファイル名を指定するとその名前でコピーされます。

  3. リモートからリモートへのコピー: リモートサーバーAのファイルをリモートサーバーBへ直接送る。
    bash
    scp user1@remote_host1:/path/to/file user2@remote_host2:/path/to/destination

    このシナリオは少し特殊です。多くの場合、このコマンドを実行しているローカルマシンが、データ転送の中継役となります。つまり、remote_host1からローカルマシンへファイルがダウンロードされ、その後ローカルマシンからremote_host2へファイルがアップロードされます。ただし、SSHの設定によっては、ローカルマシンを介さずに直接リモートホスト間でデータが転送されるように構成することも可能です(これについては後述の応用例で触れます)。

簡単な実行例

具体的な例を見てみましょう。

例1: ローカルのファイルをリモートのホームディレクトリにコピー

ローカルにある my_document.txt というファイルを、ユーザー johndoe として server.example.com のホームディレクトリ (~) にコピーします。

bash
scp my_document.txt [email protected]:~

実行すると、 server.example.comjohndoe ユーザーのパスワード(または公開鍵認証の設定がされていれば不要)が求められます。

例2: リモートのファイルをローカルのカレントディレクトリにコピー

server.example.comjohndoe ユーザーのホームディレクトリにある important_data.zip というファイルを、ローカルマシンのカレントディレクトリ (.) にコピーします。

bash
scp [email protected]:~/important_data.zip .

例3: リモートホストAからリモートホストBにファイルをコピー

serverA.example.comuserA のホームディレクトリにある config.yml を、serverB.example.comuserB/etc/app/ ディレクトリにコピーします。

bash
scp [email protected]:~/config.yml [email protected]:/etc/app/

このコマンドを実行しているローカルマシンが中継役となります。実行時には、serverA.example.comuserA のパスワードと、serverB.example.comuserB のパスワードの両方が求められる可能性があります(公開鍵認証が設定されていれば不要)。

例4: ディレクトリをコピー(再帰コピー)

デフォルトでは、scpはファイルをコピーします。ディレクトリをコピーするには、再帰コピーオプション -r が必要です。

ローカルにある my_project というディレクトリとその内容全てを、リモートの /var/www/ ディレクトリにコピーします。

bash
scp -r my_project [email protected]:/var/www/

このコマンドは、my_project ディレクトリ自体と、その中のすべてのファイルおよびサブディレクトリを、リモートの /var/www/ ディレクトリの下にコピーします (/var/www/my_project としてコピーされます)。

これらの基本的な例からわかるように、scpは非常に直感的に使用できます。しかし、より詳細な制御や特定のシナリオに対応するためには、様々なオプションを理解することが重要です。

scpコマンドの主要オプション

scpコマンドには、ファイル転送の挙動を制御するための多くのオプションが用意されています。ここでは、よく使用される主要なオプションを詳しく解説します。

-r (Recursive)

ディレクトリを再帰的にコピーします。サブディレクトリとその中のファイルもすべてコピー対象に含まれます。ディレクトリをコピーする場合、このオプションは必須です。

bash
scp -r /path/to/local/directory user@remote_host:/path/to/destination/

コピー先のパスがディレクトリで終わるスラッシュ / で終わっている場合、コピー元ディレクトリは指定されたディレクトリの下にコピーされます。例えば、ローカルの /home/user/data をリモートの /backup/-r 付きでコピーすると、リモートには /backup/data というディレクトリが作成され、その中に /home/user/data の内容がコピーされます。コピー先パスが /backup/data_new のようにディレクトリ名まで指定されている場合は、その名前でディレクトリが作成され、その中にコピー元ディレクトリの内容がコピーされます。

-p (Preserve)

元のファイルの更新日時 (modification time)、アクセス日時 (access time)、およびパーミッション (mode) を保持してコピーします。このオプションを使わない場合、コピーされたファイルのタイムスタンプはコピーを実行した時刻になり、パーミッションはコピー先システムでの新しいファイルの作成時のデフォルト設定やumaskに依存します。

bash
scp -p /path/to/local/file user@remote_host:/path/to/destination/

ディレクトリを -r オプションと共にコピーする場合にも -p オプションは有効です。これにより、ディレクトリのタイムスタンプやパーミッションも保持されます。

注意点として、-p オプションはファイルの所有者 (owner) やグループ (group) は通常保持しません。これらの属性を保持するには、コピーを実行するユーザーがコピー先ホストでファイルの所有者やグループを設定する権限(通常はroot権限)を持っている必要があります。rsyncコマンドの -a オプション(アーカイブモード)は、これらの属性も含めて可能な限り保持しようとしますが、scpの -p はタイムスタンプとパーミッションに限定されます。

-v (Verbose)

詳細な実行過程を表示します。SSH接続の確立過程、認証の試行、ファイル転送の進捗などが細かく出力されます。エラー発生時のデバッグに非常に役立ちます。

bash
scp -v /path/to/local/file user@remote_host:/path/to/destination/

出力例:

Executing: program /usr/bin/ssh host server.example.com, user johndoe, command scp -v -t /path/to/destination/
OpenSSH_8.2p1, OpenSSL 1.1.1f 31 Mar 2020
debug1: Reading configuration data /etc/ssh/ssh_config
... (SSH接続確立のログ) ...
debug1: Authentication succeeded (publickey).
debug1: channel 0: new [client-session]
debug1: Requesting subsystem sftp
debug1: channel 0: connected to subsystem sftp
debug1: fd 3 setting TCP_NODELAY
debug1: SSH2_MSG_SERVICE_ACCEPT received
debug1: Legacy scp protocol not supported in strict mode
debug1: channel 0: free: client-session, nchannels 1
debug1: fd 0 is not O_NONBLOCK
debug1: fd 1 is not O_NONBLOCK
Transferred: sent 3480, received 3072 bytes, in 0.1 seconds
Bytes per second: 28089.8
debug1: Exit status 0

-v オプションは、接続がうまくいかない場合や、予想外の挙動が発生した場合に、問題の切り分けに役立ちます。

-q (Quiet)

進捗表示やエラー以外の診断メッセージを抑制します。スクリプト内でscpを使用する際などに、余分な出力があるとパースの邪魔になる場合に便利です。

bash
scp -q /path/to/local/file user@remote_host:/path/to/destination/

通常表示されるファイル名、転送量、転送速度、残り時間などの情報は表示されなくなります。ただし、重大なエラーが発生した場合は標準エラー出力にメッセージが表示されます。

-C (Compression)

ファイル転送時に圧縮を有効にします。帯域幅が狭いネットワーク環境などで、転送効率を向上させるのに役立つことがあります。ただし、CPU負荷は増加するため、高速なネットワーク環境や、すでに圧縮されているファイル(ZIP, JPEGなど)の転送にはあまり効果がないか、かえって遅くなる可能性もあります。

bash
scp -C /path/to/local/large_text_file user@remote_host:/path/to/destination/

このオプションを指定すると、SSHプロトコルレベルでGzip圧縮が適用されます。圧縮率は転送するデータの内容に依存します。テキストファイルやログファイルなど、重複が多いデータには効果的です。

-P port (Port)

リモートホストのSSHサーバーが標準の22番ポート以外で待機している場合に、そのポート番号を指定します。-p オプション(パーミッション保持)と混同しないように注意が必要です。オプション名は大文字の -P です。

bash
scp -P 2222 /path/to/local/file user@remote_host:/path/to/destination/

上記例では、リモートホストのSSHポートとして2222番を指定しています。SSHの設定ファイル (~/.ssh/config/etc/ssh/ssh_config) でホスト名に対してポート番号を定義している場合は、このオプションを省略できることもあります。

scpコマンドの書式として、ホスト名の後ろにコロン : を付けてポート番号を指定する形式を見かけることがありますが、これは非標準または古い形式であり、推奨されません。標準的なSSHクライアントのオプション指定方法である -P を使用するべきです。例えば、scp user@remote_host:2222:/path/to/file のような書き方は、SSHサーバーにポート番号をパスの一部として解釈させてしまい、期待通りに動作しない可能性があります。

-l limit (Limit)

ファイル転送に使用する帯域幅をキロビット/秒 (Kbit/s) 単位で制限します。大規模なファイルを転送する際に、他のネットワーク通信(Web閲覧や他のアプリケーション)への影響を最小限に抑えたい場合に利用できます。

bash
scp -l 1000 /path/to/local/large_file user@remote_host:/path/to/destination/

上記例では、帯域幅を約1Mbps (1000 Kbit/s) に制限しています。これは、ファイル転送の速度を制御したい場合に便利です。

-c cipher (Cipher)

ファイル転送に使用する暗号アルゴリズムを指定します。SSHでは複数の暗号化方式をサポートしており、クライアントとサーバー間で利用可能な方式の中から最適なものがネゴシエーションによって選択されます。特定の暗号方式を指定することで、パフォーマンスを向上させたり、特定のセキュリティ要件を満たしたりすることができます。

bash
scp -c aes128-ctr /path/to/local/file user@remote_host:/path/to/destination/

指定できる暗号方式は、使用しているSSHクライアントとサーバーの実装に依存します。利用可能な暗号方式のリストは、多くのシステムで ssh -c help コマンドで確認できます。

例:
aes128-cbc, aes192-cbc, aes256-cbc, aes128-ctr, aes192-ctr, aes256-ctr, [email protected], blowfish-cbc, 3des-cbc, arcfour, arcfour128, arcfour256 など。

古い暗号方式(例: 3des-cbc, arcfour)はセキュリティ上の脆弱性が指摘されているため、特別な理由がない限り、より安全で高速な新しい暗号方式(例: aes*-ctr, [email protected])を選択することが推奨されます。特に [email protected] は、比較的新しい暗号方式で、パフォーマンスが高いとされています。

-i identity_file (Identity file)

公開鍵認証で使用する秘密鍵ファイルを指定します。デフォルトでは、ユーザーのホームディレクトリの .ssh ディレクトリにある標準の秘密鍵ファイル(例: id_rsa, id_dsa, id_ecdsa, id_ed25519)が試行されますが、異なる秘密鍵を使用したい場合にこのオプションを使います。

bash
scp -i ~/.ssh/my_custom_key /path/to/local/file user@remote_host:/path/to/destination/

これは、複数の秘密鍵を持っている場合や、デフォルト以外の場所に秘密鍵を保存している場合に便利です。セキュリティ上の理由から、多くのシステムではパスワード認証を無効にし、公開鍵認証のみを許可しています。-i オプションは、このような環境で特定のキーペアを使って認証を行う際に不可欠です。

-o ssh_option (SSH option)

SSH設定ファイル (ssh_config) で指定できる任意のオプションをコマンドラインから指定します。これにより、scpコマンドの挙動をSSHクライアントレベルで細かく制御できます。複数の -o オプションを指定することで、複数のSSHオプションを適用できます。

bash
scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null /path/to/local/file user@remote_host:/path/to/destination/

上記例は、ホスト鍵の検証を無効にし、known_hosts ファイルを使用しない設定ですが、これはセキュリティリスクを高めるため、特別な理由がない限り行うべきではありません。

-o オプションで指定できるSSHオプションの例:

  • ConnectTimeout=seconds: 接続試行時のタイムアウト時間を秒単位で指定します。
  • ProxyCommand command: リモートホストへの接続を確立するために実行するプロキシコマンドを指定します。踏み台サーバーを経由して接続する場合などに使用します。
    bash
    scp -o "ProxyCommand ssh -W %h:%p bastion_host" /path/to/local/file user@target_host:/path/to/destination/

    この例では、bastion_host を経由して target_host に接続しています。%h はターゲットホスト名、%p はポート番号に置き換えられます。
  • IdentityFile=identity_file: これは -i オプションと同じ機能ですが、-o 形式でも指定できます。
  • Port=port: これは -P オプションと同じ機能ですが、-o 形式でも指定できます。

SSH設定ファイル (~/.ssh/config) でホストごとに詳細な設定を行っておくと、これらの -o オプションをコマンドラインで毎回指定する必要がなくなり、便利です。例えば、.ssh/config に以下のように設定しておけば、

config
Host my_remote_server
Hostname server.example.com
Port 2222
User johndoe
IdentityFile ~/.ssh/my_custom_key
Compression yes

scpコマンドは単に scp /path/to/local/file my_remote_server:/path/to/destination/ と記述するだけで、設定ファイルで定義されたオプションが自動的に適用されます。これは可読性とメンテナンス性を向上させる強力な方法です。

その他のオプション

  • -4 (IPv4 only): IPv4アドレスのみを使用するように強制します。
  • -6 (IPv6 only): IPv6アドレスのみを使用するように強制します。
  • -B (Batch mode): パスワードやパスフレーズの入力を対話的に求めないようにします。スクリプトで使用する際に便利ですが、パスワード認証の場合は別途パスワード入力の方法(例: ssh-pass コマンドなど)を考慮する必要があります。公開鍵認証が設定されていれば、パスフレーズなしの鍵を使用するか、ssh-agent を利用することで非対話的な認証が可能です。
  • -S program (Ssh program): SSHクライアントプログラムとして ssh 以外のプログラムを使用する場合に指定します。

具体的な使用例と応用

scpコマンドは様々なシナリオで活用できます。ここでは、より実践的な使用例や応用方法を紹介します。

複数のファイルを同時にコピー

複数のファイルを一度にコピーしたい場合は、コピー元のパスに複数のファイル名をスペース区切りで指定するか、ワイルドカードやブレース展開を利用します。

複数のファイル名を列挙:

bash
scp file1.txt file2.log user@remote_host:/path/to/destination/

このコマンドは file1.txtfile2.log の両方をリモートの /path/to/destination/ ディレクトリにコピーします。

ワイルドカード (*, ?) の使用:

カレントディレクトリにあるすべての .txt ファイルをコピーする場合:

bash
scp *.txt user@remote_host:/path/to/destination/

a または b で始まる4文字のファイルをコピーする場合:

bash
scp {a,b}??? user@remote_host:/path/to/destination/

ブレース展開はローカルシェルによって解釈されるため、リモートにコピー元ファイルが存在する場合は、まずローカルに展開されてから転送されます。リモートのワイルドカードを展開したい場合は、クォートで囲む必要があります。

リモート上のワイルドカードの展開:

リモートサーバーの /var/log/ ディレクトリにある app_*.log ファイル全てをローカルのカレントディレクトリにコピーする場合:

bash
scp user@remote_host:"/var/log/app_*.log" .

リモートのシェルがワイルドカードを展開するように、リモートパスをクォートで囲みます。

リモートホスト間で直接ファイルを転送する

前述の通り、scp user1@host1:/path/to/file user2@host2:/path/to/destination の形式は、通常コマンドを実行しているローカルマシンを中継します。しかし、ローカルマシンが低速なネットワーク環境にあったり、単に中継したくない場合もあります。SSHの設定によっては、ローカルマシンを介さずにリモートホスト間で直接データが転送されるように構成できます。これは、リモートホスト1がリモートホスト2にSSH接続する許可を持っており、かつ ssh -W オプションなどが利用可能な場合に可能です。

OpenSSHの新しいscp実装(SFTPプロトコルを使用するもの)や、一部の古いscp実装では、この形式でコマンドを実行した際に、ローカルを中継せずにリモート間で直接ファイル転送を試みる場合があります。これは内部的に、ローカルマシンからリモートホスト1へSSH接続し、リモートホスト1上で scp または sftp クライアントを実行してリモートホスト2へ接続し直す、といった仕組みで行われます。

より確実にローカルを介さずにリモート間で転送したい場合は、片方のリモートホストにSSHでログインし、そこから別のリモートホストへscpコマンドを実行するのが最も確実です。

“`bash

ローカルから remote_host1 にログイン

ssh user1@remote_host1

remote_host1 上で、remote_host1 から remote_host2 へ scp を実行

user1@remote_host1$ scp /path/on/host1 user2@remote_host2:/path/on/host2
“`

この方法であれば、データ転送は remote_host1 と remote_host2 間でのみ行われます。

また、SSHのProxyCommandとnetcat (nc) などを利用して、リモートホスト1からリモートホスト2への直接的なSSHトンネルを構築し、その上でscpを実行するという高度な方法もありますが、これは設定が複雑になります。

コピー元・コピー先のパス指定の様々な書き方

パスを指定する際には、絶対パス、相対パス、ホームディレクトリの略記 (~) を使用できます。

  • 絶対パス: /home/user/documents/file.txt のように、ファイルシステムのルート (/) から始まるパスです。
  • 相対パス: カレントディレクトリ (./file.txt または単に file.txt) や親ディレクトリ (../file.txt) からの相対的なパスです。
    ローカルパス、リモートパスのいずれでも相対パスを使用できます。リモートパスで相対パスを指定した場合、それはリモートユーザーのホームディレクトリからの相対パスとして解釈されることが多いです。
    例: scp file.txt user@remote_host:../documents/ (リモートユーザーのホームディレクトリの一つ上のディレクトリにある documents ディレクトリへコピー)
  • ホームディレクトリ (~): ユーザーのホームディレクトリを表します。ローカルパスでもリモートパスでも使用できます。
    例: scp ~/my_file user@remote_host:~/remote_files/

パスにスペースや特殊文字が含まれる場合:

パスにスペースやシェルが特殊な意味を持つ文字(例: $, &, ;, <, >, |, (, ), [, ], {, }, *, ? など)が含まれる場合は、パスをクォート(シングルクォート ' またはダブルクォート ")で囲む必要があります。

bash
scp "/path/to/my document.txt" user@remote_host:"/path/to/remote destination/"

リモートパスはリモートシェルの影響を受ける可能性があるため、特にワイルドカードなどとして解釈されないようにダブルクォートで囲むのが安全です。

上書きの挙動

scpは、コピー先に同名のファイルやディレクトリが存在する場合、デフォルトで確認なしに上書きします。これは、rsyncのように差分を検出して部分的に転送したり、上書き前に確認を求めたりする機能は基本的にありません。ファイルが存在する場合はそのままコピーして置き換え、ディレクトリが存在する場合はそのディレクトリの中に内容をコピーします。

上書きを避けたい場合は、事前にコピー先のファイルやディレクトリが存在しないことを確認するか、他のコマンド(sftpやrsync)の使用を検討する必要があります。あるいは、シェルスクリプトなどで事前にコピー先のファイルが存在するかチェックし、存在する場合はコピーを実行しない、というロジックを組むことも可能です。

コピー中のキャンセル

scpコマンドでファイル転送中に処理を中断したい場合は、通常 Ctrl + C キーを押します。これにより、scpプロセスが終了し、転送が停止します。ただし、転送中のファイルは途中で途切れた状態になるため、後で再開する機能はscpにはありません。中断した場合は、最初から再度転送を行う必要があります。

scpのセキュリティと注意点

scpはSSHプロトコルを使用するため、高いセキュリティを提供しますが、利用にあたってはいくつかの注意点があります。

SSHプロトコルによる暗号化と認証

scpの最大の利点は、SSHによる暗号化と認証です。

  • 暗号化: 転送されるファイルデータは、SSHによって確立された暗号化されたチャネルを通過します。これにより、ネットワーク上で第三者にデータを盗聴されるリスクを防ぎます。パスワードや秘密鍵などの認証情報も安全に交換されます。
  • 認証: SSHは、パスワード認証、公開鍵認証、GSSAPI認証など、様々な認証方法をサポートしています。scpはこれらの認証方法を利用して、正当なユーザーだけがファイル転送を実行できるようにします。

パスワード認証と公開鍵認証

SSHの認証方法として最も一般的なのはパスワード認証と公開鍵認証です。

  • パスワード認証: リモートホストのユーザー名とパスワードを入力して認証を行います。手軽ですが、パスワードを推測されたり、ブルートフォース攻撃に弱かったりする可能性があります。また、スクリプトから自動でscpを実行する際に、パスワードを埋め込むのはセキュリティ上の大きなリスクとなります。
  • 公開鍵認証: ローカルマシンに生成した秘密鍵と、リモートホストに配置した公開鍵のペアを使って認証を行います。秘密鍵はローカルマシンに厳重に保管し、公開鍵をリモートホストのユーザーのホームディレクトリにある .ssh/authorized_keys ファイルに追加します。認証時には、秘密鍵に対応するチャレンジ応答を行うことで、パスワードをネットワーク上に流すことなく認証が完了します。公開鍵認証はパスワード認証よりもはるかに安全であり、自動化を行う際にもパスフレーズなしの鍵を使用したり、ssh-agentを利用したりすることで、パスワードを扱わずに安全に非対話的な認証が可能になります。 可能な限り公開鍵認証を利用することを強く推奨します。

公開鍵認証の設定手順は以下の通りです(簡潔に記述):
1. ローカルマシンで鍵ペアを生成: ssh-keygen コマンドを実行します。通常はRSAまたはEd25519方式が推奨されます。パスフレーズを設定することも可能ですが、自動化の場合はパスフレーズなしが一般的です(セキュリティリスクを理解して使用)。
2. 公開鍵をリモートホストにコピー: 生成された公開鍵ファイル(例: ~/.ssh/id_rsa.pub)の内容を、リモートホストのユーザーのホームディレクトリにある ~/.ssh/authorized_keys ファイルに追加します。ssh-copy-id user@remote_host コマンドを使用すると、この作業を簡単かつ安全に行えます。
3. リモートホスト側の ~/.ssh ディレクトリと authorized_keys ファイルのパーミッションが正しく設定されていることを確認します (chmod 700 ~/.ssh, chmod 600 ~/.ssh/authorized_keys)。

パーミッションの問題

scp -p オプションはコピー元のファイルのパーミッションを保持しようとしますが、いくつかの注意点があります。

  • 実行ユーザーの権限: コピー先のファイルやディレクトリのパーミッションを設定できるのは、そのファイルを操作しているユーザー自身です。リモートホストにログインしたユーザーの権限によっては、コピー元のファイルのパーミッションを完全に再現できない場合があります。特に、特定の所有者やグループへの変更は、root権限がなければ通常は不可能です。
  • ACL (Access Control List): -p オプションは基本的なUNIXパーミッション(所有者、グループ、その他の読み取り/書き込み/実行権限)のみを対象とし、ACLは保持しません。ACLを含めて正確なパーミッション情報をコピーしたい場合は、より高度なツール(rsyncなど)を検討する必要があります。
  • umask: コピー先のシステムにおけるユーザーの umask 設定は、-p オプションを使用した場合でも最終的なパーミッションに影響を与える可能性があります。

シンボリックリンクの扱い

scpコマンドは、デフォルトではシンボリックリンク自体をコピーします。つまり、コピー先のパスには、コピー元と同じターゲットを指す新しいシンボリックリンクが作成されます。リンク先のファイルの実体はコピーされません。

もしシンボリックリンクではなく、そのリンクが指しているファイル(実体)をコピーしたい場合は、-L オプション (Follow symbolic links) を使用します。

“`bash

デフォルトの挙動: シンボリックリンク自体をコピー

scp /path/to/local/symlink user@remote_host:/path/to/destination/

-L オプション: シンボリックリンクが指すファイルの実体をコピー

scp -L /path/to/local/symlink user@remote_host:/path/to/destination/
“`

リモートホストからファイルをコピーする場合も同様で、-L オプションを付けると、リモートのシンボリックリンクが指すファイルの実体がローカルにコピーされます。

エラーハンドリング

scpコマンドは、ファイル転送が成功した場合は終了コード0を返します。失敗した場合は、0以外の終了コードを返します。シェルスクリプトなどで自動化を行う際には、この終了コードをチェックすることで、転送が成功したかどうかを確認できます。

bash
scp /path/to/local/file user@remote_host:/path/to/destination/
if [ $? -eq 0 ]; then
echo "ファイル転送に成功しました。"
else
echo "ファイル転送に失敗しました。"
# エラー処理
fi

よくあるエラーとしては、以下のようなものがあります。

  • Permission denied: リモートホストでのファイルやディレクトリへの書き込み権限がない、またはSSH認証に失敗した。
  • No such file or directory: コピー元またはコピー先のパスが存在しない。
  • Connection refused: リモートホストのSSHポートが開いていない、またはファイアウォールによってブロックされている。
  • Connection timed out: ネットワークの遅延や障害により、リモートホストに接続できない。
  • Host key verification failed: リモートホストのホスト鍵が、ローカルの known_hosts ファイルに記録されているものと異なる。SSHに対する中間者攻撃の可能性を示す警告であり、不用意に進めてはならない。

中間者攻撃 (Man-in-the-Middle) に対するSSHの対策

SSHは、初回接続時にリモートホストの「ホスト鍵」を取得し、ローカルマシンの ~/.ssh/known_hosts ファイルに記録します。2回目以降の接続では、リモートホストが提示するホスト鍵が known_hosts に記録されているものと一致するかどうかを確認します。もし一致しない場合は、警告が表示され、接続が中断されます。

この仕組みは、悪意のある第三者が正規のリモートホストになりすまして接続してくる中間者攻撃を防ぐための重要なセキュリティ対策です。ホスト鍵不一致の警告が表示された場合は、安易に接続を続行せず、リモートホストの正当性を別の手段(例: 管理者に確認する)で確認する必要があります。

スクリプトなどで StrictHostKeyChecking=noUserKnownHostsFile=/dev/null オプションを -o で指定すると、このホスト鍵検証が無効になります。これは中間者攻撃のリスクを劇的に高めるため、非常に危険であり、絶対に避けるべきです。 自動化したい場合は、事前に手動で接続してホスト鍵を known_hosts に登録しておくか、安全な鍵配布方法を利用してください。

scpの制限と代替手段

scpはシンプルで安全なファイル転送コマンドですが、いくつかの制限事項があります。これらの制限のために、他のコマンドがより適しているケースも存在します。

scpの制限事項

  1. 転送の中断・再開ができない: scpはファイル全体を一度に転送します。転送中にネットワークが切断されたり、ユーザーがキャンセルしたりした場合、転送は中断され、再開機能はありません。再度同じファイルを転送しようとすると、最初からやり直しになります。大きなファイルの転送には不向きです。
  2. 差分転送ができない: コピー先に同じファイルが存在する場合、scpはファイルの更新日時や内容に関わらず、常にファイル全体を転送して上書きします。ファイルの一部だけが変更された場合でも、変更されていない部分も含めて全て転送するため、効率が悪くなることがあります。
  3. ファイル削除や同期機能がない: scpはあくまで「コピー」コマンドであり、コピー元のファイルを転送後に削除したり、コピー先をコピー元と完全に一致させる(コピー元にないファイルをコピー先から削除する)といった同期機能は持っていません。
  4. 複雑なファイル選択や除外が難しい: 特定のパターンに一致するファイルを除外してコピーしたい、特定のディレクトリ以下はコピーしたくない、といった複雑なルールに基づいたファイル選択や除外は、scpの標準機能だけでは困難です。シェル側のワイルドカードや find コマンドなどと組み合わせる必要が出てきます。

他のファイル転送コマンド/プロトコルとの比較

scpの制限を補うため、あるいは異なる要件に対応するために、他のファイル転送方法が利用されます。

  • sftp (SSH File Transfer Protocol):

    • 特徴: SSH上で動作するファイル転送プロトコルです。ftpに似た対話的なインターフェース(get, put, ls, cd, mkdir, rm などのコマンド)を提供します。SSHを使用するため、scpと同様に安全です。
    • scpとの比較: scpはコマンドラインでコピー元とコピー先を指定して一度に転送するのに対し、sftpは接続を確立して対話的に複数のファイル操作を行います。単一または少数のファイルをコピーするだけならscpが簡単ですが、リモートのファイルシステムをブラウズしたり、複数のファイル操作を連続して行ったり、リモートでディレクトリを作成・削除したりする場合はsftpが便利です。scpの新しい実装は内部的にsftpプロトコルを使用することがあります。
    • ユースケース: 対話的にリモートサーバーのファイルシステムを操作したい場合、複数のファイルやディレクトリを段階的にアップロード/ダウンロードしたい場合。
  • rsync:

    • 特徴: 差分検出アルゴリズム(Rsyncアルゴリズム)を使用して、コピー元とコピー先の間で異なる部分のみを効率的に転送するコマンドです。ローカル間、ローカル-リモート間(SSH経由)、リモート-リモート間(SSH経由)、rsyncデーモン経由など、様々な方法で利用できます。
    • scpとの比較: rsyncはscpよりも高機能です。最大の強みは差分転送による効率性で、一度コピーしたファイルの一部だけが変更された場合に威力を発揮します。また、転送の中断・再開(一部対応)、柔軟なファイル選択・除外ルール、多様な属性(パーミッション、タイムスタンプ、所有者、グループ、シンボリックリンクなど)の保持、転送後のコピー元ファイル削除(同期的な挙動)など、多くの機能を持ちます。設定オプションが豊富で、より複雑なシナリオに対応できます。
    • ユースケース: 大量のファイルやディレクトリの同期、定期的なバックアップ、低帯域幅環境での効率的な転送、転送の中断・再開が必要な場合、複雑なファイル選択・除外が必要な場合。scpよりも学習コストはやや高いですが、使いこなせば非常に強力です。特に rsync -avz オプションはよく使用されます(アーカイブモード、詳細表示、圧縮)。
  • ftp (File Transfer Protocol), tftp (Trivial File Transfer Protocol):

    • 特徴: 非常に古くから使われているファイル転送プロトコルです。
    • scpとの比較: ftpやtftpは認証情報やファイルデータを平文でネットワーク上に流すため、セキュリティ上の問題が大きく、インターネット経由での使用は非推奨です。 sshやscpが利用可能な環境では、特別な理由がない限り使用すべきではありません。FTPにはFTPSやSFTP(SSHとは別)といったセキュリティ強化版もありますが、一般的にFTPは安全ではないと認識されています。

どのコマンドをいつ使うべきか

これらのファイル転送ツールは、それぞれ得意な状況が異なります。

  • scp:
    • 単一または少数のファイルを素早くコピーしたい。
    • ディレクトリを再帰的にコピーしたいが、差分転送や中断・再開は不要。
    • シンプルさとセキュリティを重視する。
    • SSHが利用できる環境であれば、特別な設定なしにすぐに使える。
  • sftp:
    • リモートサーバーのファイルシステムを対話的にブラウズしたり操作したりしたい。
    • 複数のファイルやディレクトリをコピー・移動・削除するなど、FTPクライアントのような感覚で使いたい。
  • rsync:
    • 大量のファイルやディレクトリを効率的に同期したい(差分転送)。
    • 頻繁なバックアップやミラーリングを行いたい。
    • 転送中に中断しても後で再開したい。
    • ファイル属性(所有者、グループなど)を含めて正確にコピーしたい。
    • 特定のファイルやディレクトリを除外してコピーしたい。

多くの場合、簡単なコピーにはscp、同期やバックアップにはrsync、対話的な操作にはsftp、という使い分けが適切です。

シェルスクリプトでの活用

scpコマンドは、そのシンプルさからシェルスクリプトによる自動化に非常に適しています。定期的なファイル取得やデプロイ作業などで活躍します。

自動化のためのscpの利用例

例: リモートサーバーのログファイルを毎日ローカルにバックアップするスクリプト

“`bash

!/bin/bash

REMOTE_USER=”backupuser”
REMOTE_HOST=”server.example.com”
REMOTE_LOG_DIR=”/var/log/myapp”
LOCAL_BACKUP_DIR=”/home/user/backups/logs”
DATE=$(date +%Y%m%d)
LOG_FILE_PATTERN=”app_log_${DATE}*.log” # 今日の日付のログファイル

ローカルのバックアップディレクトリが存在しない場合は作成

mkdir -p $LOCAL_BACKUP_DIR

リモートからログファイルをコピー

パスワード認証の場合は対話入力が必要になるため、公開鍵認証を前提とする

-q で進捗表示を抑制

リモートのワイルドカードを展開させるためにクォートを使用

scp -q ${REMOTE_USER}@${REMOTE_HOST}:”${REMOTE_LOG_DIR}/${LOG_FILE_PATTERN}” ${LOCAL_BACKUP_DIR}/

scpの終了コードをチェック

if [ $? -eq 0 ]; then
echo “${DATE} のログファイルのバックアップに成功しました。”
else
echo “エラー: ${DATE} のログファイルのバックアップに失敗しました。” >&2
exit 1
fi

exit 0
“`

パスワードなしで実行する方法(公開鍵認証の活用)

スクリプトでscpを非対話的に実行するには、パスワード入力を不要にする必要があります。最も安全で一般的な方法は、公開鍵認証を利用することです。

  1. ローカルマシンでパスフレーズなしの秘密鍵/公開鍵ペアを生成します (ssh-keygen 実行時にパスフレーズを空にする)。
  2. 生成した公開鍵をリモートホストのユーザーの ~/.ssh/authorized_keys ファイルに追加します (ssh-copy-id を利用)。
  3. ローカルマシンからリモートホストへのSSH接続(およびscp)がパスワード入力なしで行えることを確認します。

セキュリティ上の理由から、パスフレーズなしの秘密鍵を使用する場合は、その秘密鍵ファイルへのアクセス権限を厳重に管理する必要があります(通常は所有者のみ読み書き可能 chmod 600 ~/.ssh/id_rsa)。また、この鍵ペアは特定の用途(例: このバックアップスクリプト専用)に限定し、その鍵でログインできるリモートユーザーの権限を必要最小限に絞る(例: ファイル転送のみ可能なユーザー)といった対策も有効です。

もう一つの方法として、ssh-agent を利用する方法があります。ssh-agent は秘密鍵をメモリ上にロードし、パスフレーズで保護された鍵であっても、一度パスフレーズを入力すれば以降は入力なしで認証を可能にします。スクリプトの実行前に ssh-agent を起動し、ssh-add で秘密鍵を登録しておくことで、スクリプト内でのscp実行時にパスワードやパスフレーズの入力を不要にできます。この方法は、鍵ファイル自体をパスフレーズなしにするよりも安全です。

エラーチェックの方法

シェルスクリプト内でコマンドを実行した後、特殊変数 $? を参照することで、そのコマンドの終了コードを取得できます。前述のバックアップスクリプト例のように、$? が0であれば成功、0以外であれば失敗と判断できます。これにより、エラーが発生した場合に適切な処理(ログ出力、通知、リトライなど)を行うことができます。

進捗表示を抑制 (-q)

スクリプト実行時にscpの進捗表示や詳細なメッセージが標準出力に出力されると、スクリプトの出力処理やログ解析が難しくなることがあります。このような場合は、-q オプションを使用して余分な出力を抑制することが推奨されます。エラーメッセージは通常標準エラー出力に出力されるため、-q を付けても重要なエラーを見逃すことはありません。

トラブルシューティング

scpを使用する際に遭遇しがちな問題とその原因、解決策について解説します。

“Permission denied” エラー

  • 原因:
    • リモートホストで指定したユーザー名/パスワードまたは秘密鍵による認証に失敗した。
    • リモートホストで、コピー先のディレクトリにファイルを書き込む権限がない。
    • リモートホストで、コピー元のファイルを読み取る権限がない(リモートからローカルへコピーする場合)。
    • リモートホストのSSHサーバー設定で、指定したユーザーでのログインが許可されていない。
    • リモートホスト側のSELinuxやAppArmorといったセキュリティモジュールがファイル操作をブロックしている。
  • 解決策:
    • ユーザー名、パスワード、秘密鍵ファイル、およびリモートホストの authorized_keys ファイルの設定を確認します。
    • リモートホストにSSHでログインし、対象のディレクトリに対するユーザーのパーミッションを確認します (ls -l, id コマンドなど)。必要に応じてパーミッションを変更します (chmod)。
    • リモートホストの /etc/ssh/sshd_config ファイルで、AllowUsers, DenyUsers, AllowGroups, DenyGroups などの設定を確認します。
    • リモートホストでSELinuxなどの監査ログを確認し、ファイル操作が拒否されていないか確認します。

“No such file or directory” エラー

  • 原因:
    • コピー元またはコピー先として指定したパスが存在しない。
    • ローカルパスを指定したが、カレントディレクトリからの相対パスが間違っている。
    • リモートパスを指定したが、リモートユーザーのホームディレクトリからの相対パスが間違っている、または絶対パスが間違っている。
    • パスにスペースや特殊文字が含まれており、適切にクォートされていないためにシェルが誤って解釈した。
    • リモートホストで、指定したユーザーにコピー元ファイルやディレクトリへの読み取り権限(または親ディレクトリへの実行権限)がないため、存在しないかのように表示されている(セキュリティ上の理由で隠蔽されることがある)。
  • 解決策:
    • コピー元とコピー先のパスを再度確認します。絶対パスで指定してみるのが確実です。
    • リモートホストにSSHでログインし、指定したパスが実際に存在し、ユーザーがアクセスできるか確認します。
    • パスにスペースや特殊文字が含まれている場合は、必ずダブルクォート (") で囲みます。特にリモートパスは、リモートシェルの解釈を防ぐためにクォートが重要です。

“Connection refused” / “Connection timed out” エラー

  • 原因:
    • リモートホストのSSHサーバーが起動していない。
    • リモートホストのSSHポート(デフォルト22番)が、ファイアウォールによってブロックされている(ローカル側、リモート側、または中間ネットワーク機器)。
    • リモートホストが指定されたポート番号でSSHを受け付けていない(ssh_config/sshd_config 設定ミス)。
    • リモートホストがネットワーク上に存在しないか、IPアドレスが間違っている。
    • ネットワークの混雑や障害。
  • 解決策:
    • リモートホストにSSHでログインできるか、ssh user@remote_host を試します。
    • リモートホストのSSHサーバーの状態を確認します(例: systemctl status sshd)。
    • 指定しているポート番号が正しいか確認します。デフォルト以外の場合は -P オプションで正しく指定します。
    • ローカルマシンとリモートホストの間のファイアウォール設定を確認し、SSHポート(通常TCP 22番)が許可されているか確認します。
    • リモートホストがネットワーク上で到達可能か、ping remote_host コマンドなどで確認します。

“Host key verification failed” エラー

  • 原因:
    • リモートホストのホスト鍵が変更された(サーバーの再インストール、IPアドレスの変更、DNS変更など)。
    • 中間者攻撃を受けている可能性がある。
  • 解決策:
    • リモートホストのホスト鍵が本当に変更されたのか、信頼できる別の方法で確認します(例: 管理者に問い合わせる、別のネットワークから接続してみる)。
    • もしホスト鍵の変更が正当なものであれば、ローカルマシンの ~/.ssh/known_hosts ファイルから該当するエントリを削除します。警告メッセージに削除すべき行番号が示されていることがあります。ssh-keygen -R remote_host コマンドを使うと安全に削除できます。
    • その後の接続で新しいホスト鍵が登録されます。
    • ホスト鍵の変更に心当たりがない場合は、中間者攻撃の可能性を疑い、ネットワーク環境のセキュリティを確認します。安易に StrictHostKeyChecking=no を設定して回避してはいけません。

コピー速度が遅い場合の対応

  • 原因:
    • ネットワーク帯域幅の制限。
    • ネットワークの遅延(レイテンシ)が大きい。
    • 転送元のディスクI/Oが遅い。
    • 転送先のディスクI/Oが遅い。
    • CPU負荷が高い(特に圧縮オプション使用時や、古い/非力なマシン)。
    • SSHのネゴシエーションや暗号化処理に時間がかかっている。
    • デフォルトの暗号方式がパフォーマンスに影響している。
  • 解決策:
    • -C オプションによる圧縮を試す(ただし、CPU負荷やデータタイプによっては逆効果)。
    • -c オプションでより高速な暗号方式を指定してみる(例: [email protected], aes128-ctr)。
    • -l オプションで帯域制限をしていないか確認します(意図せず設定されている場合)。
    • 転送元/先のサーバーのディスクI/O性能やCPU負荷を確認します。
    • ネットワーク環境自体に問題がないか確認します(他の通信速度、tracerouteなど)。
    • 非常に大きなファイルを頻繁に転送する場合は、差分転送が可能なrsyncへの移行を検討します。

-v オプションを使ったデバッグ方法

問題が発生した場合、最も基本的なデバッグ方法は -v オプションを使用することです。-v を複数重ねることで、より詳細なデバッグ情報を表示できます (-vv, -vvv)。

bash
scp -vvv /path/to/local/file user@remote_host:/path/to/destination/

-v オプションの出力には、SSH接続の確立、認証方式の試行、暗号化アルゴリズムのネゴシエーション、ファイル転送のステータスなど、多くの情報が含まれています。特にエラーメッセージの前後のログを確認することで、問題がどの段階(接続、認証、ファイル操作など)で発生しているのか、より正確に特定する手がかりを得られます。例えば、認証が成功しているのに Permission denied が出る場合は、SSH接続自体は問題なく、リモートでのファイル操作権限に問題がある可能性が高い、といった判断ができます。

まとめ

scpコマンドは、Secure Shell (SSH) プロトコルを利用した、シンプルかつ安全なファイル転送ツールです。データの暗号化と強力な認証メカニズムにより、従来のFTPのようなプロトコルに比べて高いセキュリティを提供します。

基本的な使い方は非常に直感的で、scp コピー元 コピー先 の形式で、ローカルとリモートホスト間、あるいはリモートホスト間でのファイルやディレクトリのコピーを実行できます。

本記事では、ファイル転送をより柔軟かつ効率的に行うための様々な主要オプションを詳しく解説しました。ディレクトリを再帰的にコピーする -r、タイムスタンプやパーミッションを保持する -p、詳細な情報を表示する -v、特定のポートを指定する -P、公開鍵認証で秘密鍵を指定する -i、そしてSSHクライアントオプションを細かく指定できる -o など、これらのオプションを理解し使いこなすことで、多様なファイル転送ニーズに対応できます。

また、具体的な使用例として、複数のファイルのコピー方法やリモートホスト間での転送について触れ、スクリプトでの活用例やエラーチェックの方法も紹介しました。シェルスクリプトと組み合わせることで、定期的なバックアップや自動デプロイなどのタスクを安全に自動化することが可能です。

セキュリティ面では、SSHの暗号化と認証の重要性、特に公開鍵認証の利用を強く推奨しました。ホスト鍵の検証による中間者攻撃対策についても触れ、その重要性と安易な無効化の危険性を説明しました。

最後に、scpが持つ制限(中断・再開不可、差分転送不可など)と、それらを補う代替手段としてsftpやrsyncを紹介し、それぞれの特徴と使い分けについて解説しました。簡単なコピーにはscp、対話的な操作にはsftp、効率的な同期やバックアップにはrsyncというように、目的に応じて適切なツールを選択することが重要です。

scpは、UNIX/Linuxシステム管理者や開発者にとって必要不可欠なコマンドの一つです。そのシンプルさとセキュリティは、日常的なファイル転送タスクにおいて強力な味方となるでしょう。本記事が、scpコマンドの理解を深め、安全で効率的なファイル転送を実現するための一助となれば幸いです。

さらに学習を進めるためには、man scpman ssh_config コマンドで詳細なマニュアルを参照したり、SSHプロトコル全般に関する知識を深めたりすることをお勧めします。


コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

上部へスクロール