[Перевод] Кунг-фу стиля Linux: удобная работа с файлами по SSH
Если у вас имеется больше одного Linux-компьютера, то вы, вероятно, постоянно пользуетесь ssh
. Это — отличный инструмент, но мне всегда казалась в нём странной одна деталь. Несмотря на то, что ssh-соединения позволяют передавать файлы с применением scp
и sftp
, у нас нет возможности перемещать файлы между локальной и удалённой системой, не запуская программу на локальном хосте, или не подключаясь к локальной машине с удалённой.
Последнее — это настоящая проблема, так как к серверам часто подключаются, находясь в это время за файрволом или за NAT-маршрутизатором, то есть, не имея постоянного IP-адреса. В результате сервер, в любом случае, не сможет подключиться к локальной системе, с которой раньше к нему обращались. Если бы в ssh-сессии можно было бы просто взять локальный или удалённый файл и передать его туда, куда нужно, это было бы очень удобно.
Я, на самом деле, не вполне достиг этой цели, но подобрался к её достижению очень близко. В этом материале я расскажу вам о скрипте, который позволяет монтировать удалённые директории на локальном компьютере. На локальной машине надо будет установить sshfs
, но на удалённой, на которую вы, возможно, не можете устанавливать программы, ничего менять не придётся. Если же потратить на настройку систем некоторое время, и если на клиентском компьютере имеется работающий ssh-сервер, то можно будет ещё и монтировать локальные директории на удалённых системах. При этом не придётся беспокоиться о блокировке IP-адресов или портов. Фактически, если вы способны подключиться к удалённой машине, это означает, что вам удастся и то, о чём я хочу рассказать.
В результате, если это всё скомбинировать, оказывается, что я очень близок к цели. Я могу работать с командной оболочкой на клиенте или на сервере и имею возможность удобно читать и записывать файлы на обеих сторонах соединения. Для этого нужно лишь всё правильно настроить.
Нет ли тут подвоха?
Возможно, вы решите, что тут кроется какой-то подвох. Ведь речь, фактически, идёт об использовании двух ssh-соединений. Одно применяется для монтирования файловой системы, а другое — для входа на компьютер. И это, на самом деле, так и есть. Но если правильно настроить ssh
, то аутентификацию нужно будет выполнять лишь один раз, не тратя слишком много времени на организацию двух подключений.
Кроме того, работу значительно облегчает скрипт, о котором я расскажу. Он скрывает от пользователя детали, поэтому процедура подключения выглядит (почти) как обычно, а после этого всё работает как надо.
Пара слов о sshfs
Утилита sshfs
даёт возможность работать с файловой системой в пользовательском пространстве (filesystem in userspace, FUSE). То есть, речь идёт о том, что в пользовательском пространстве имеется слой, находящийся поверх базовой файловой системы. В данном случае такой файловой системой является ssh-сервер, поддерживающий sftp
. Это позволяет работать с файлами, находящимися на удалённой системе, воспринимая их так, будто они находятся в реальной файловой системе на локальном компьютере. Если вы ещё не пробовали sshfs
— попробуйте. Работает эта утилита очень хорошо.
Предположим, вы вошли на компьютер myserver
и выполнили с локальной машины следующую команду:
sshfs myserver:/home/admin ~/mounts/myserver
Это приведёт к тому, что директория удалённого компьютера /home/admin
будет доступна в локальной системе по пути ~/mounts/myserver
.
При использовании sshfs
можно пользоваться различными опциями. Например, можно сделать так, чтобы после потери соединения осуществлялось бы повторное подключение. Подробности о sshfs
ищите в справке.
Так как sshfs
использует удалённо смонтированную версию файла, то все изменения, внесённые в файл, сохраняются на удалённой машине. А после того, как sshfs-соединение закрывают, на локальной компьютере ничего не остаётся. Сейчас мы это исправим.
Предварительная подготовка
Прежде чем я перейду к описанию скрипта, о котором было упомянуто выше, хочу рассказать о некоторых настройках клиента, которые вы, если хотите, можете доработать под себя. Так, тут я создаю директорию ~/remote
, а в ней создаю поддиректории для каждого удалённого компьютера. Например — это могут быть директории ~/remote/fileserver
и ~/remote/lab
.
Скрипт называется sshmount
. Он принимает те же аргументы, что и ssh
. Для упрощения работы со скриптом сведения об удалённом хосте стоит хранить в файле ~/.ssh/config
, что позволит пользоваться простыми и короткими именами хостов. Например, сведения о компьютере lab
могут выглядеть так:
Host lab
Hostname lab.wd5gnr-dyn.net
Port 444
User alw
ForwardX11 yes
ForwardX11Trusted yes
TCPKeepAlive yes
Compression yes
ControlMaster auto
ControlPath ~/.ssh/master-%r@%h:%p
На самом деле, острой необходимости в этом нет, но при таком подходе в вашем распоряжении будет приятно выглядящая директория ~/remote/lab
, а не сложная конструкция вида ~/remote/alw@lab.wd5gnr-dyn.net:444
. Во всех этих параметрах нет ничего таинственного. Единственно, хочу обратить ваше внимание на то, что ControlMaster
и ControlPath
позволяют организовать более быструю работу с соединениями, что, в нашем случае, очень важно.
Кроме того, можно организовать автоматическое подключение к удалённой системе с использованием сертификата. Вот материал об этом.
Скрипт
Наш скрипт можно использовать двумя способами. Так, если его вызывают через ссылку к sshunmount
, то он размонтирует файловую систему, связанную с указанным удалённым хостом. Если его вызывают иначе (обычно — как sshmount
), то он выполняет следующие три действия:
- Он проверяет, есть ли в директории
~/remote
поддиректория, имя которой совпадает с именем хоста (например —lab
). Если такой директории нет — он выводит сообщение об ошибке и продолжает работу. - Если такая директория существует — скрипт просматривает список смонтированных файловых систем на тот случай, если нужная файловая система уже смонтирована. Если это так — он продолжает работу.
- Если директория не смонтирована — он вызывает
sshfs
и продолжает работу.
Этот скрипт можно найти на GitHub. А вот его код, из которого убраны некоторые комментарии:
#!/bin/bash
if [ "$1" == "" ]
then
echo Usage: sshmount host [ssh_options] - Mount remote home folder on ~/remote/host and log in
echo or: sshunmount host - Remove mount from ~/remote/host
exit 1
fi
# Если вызван как sshunmount...
if [ $(basename "$0") == sshunmount ]
then
echo Unmounting... 1>&2
fusermount -u "$HOME/remote/$1"
exit $?
fi
# Обычный вызов...
if [ -d "$HOME/remote/$1" ] # Существует ли директория?
then
if mount | grep "$HOME/remote/$1 " # Файловая система уже смонтирована?
then
echo Already mounted 1>&2
else
sshfs -o reconnect $1: $HOME/remote/$1 # mount
fi
else
echo No remote directory ~/remote/$1 exists 1>&2
fi
ssh $@ # выполнить вход
Этот скрипт даёт мне половину того, что мне нужно. А именно, позволяет удобно работать с удалёнными файлами на локальном компьютере, к которому я подключён. Но сделать так, чтобы с удалённого компьютера можно было бы работать с файлами, расположенными на локальной машине, немного сложнее.
Решаем обратную задачу
Если вы хотите поэкспериментировать с монтированием на сервере папок, находящихся на локальной машине, то нужно будет, чтобы на локальной машине работал бы ssh-сервер. Конечно, если ваш локальный компьютер видим и доступен серверу, то это просто: достаточно запустить на удалённом компьютере sshfs
и смонтировать на нём папку с локального компьютера. Но во многих случаях у нас нет доступа к локальной системе, которая может быть расположена за файрволами или маршрутизаторами. Особенно это актуально в том случае, если роль локальной системы выполняет ноутбук, который может подключаться к сети из разных мест.
Но нашу задачу, несмотря на все эти сложности, всё же, можно решить. Её решение состоит из двух частей.
Во-первых — надо, при вызове sshmount
, указать дополнительный аргумент (файл можно отредактировать в том случае, если вам нужно будет постоянно выполнять подобную команду):
sshmount MyServer -R 5555:localhost:22
Во-вторых — после подключения к хосту нужно выполнить такую команду:
sshfs -p 5555 localhost:/home/me ~/local
Благодаря опции -R
на удалённой машине создаётся сокет на порте 5555
(который, естественно, должен быть свободным) и осуществляется его связь с портом 22
локальной машины. Если исходить из предположения о том, что ssh-сервер работает на порте 22
, то это позволит серверу подключиться к локальной машине по тому же соединению. Ему не нужно знать наш IP-адрес или иметь открытый порт.
Команда sshfs
, которую можно выполнять при запуске системы, связывает локальную директорию /home/me
с директорией ~/local
удалённого сервера. Если, вдобавок, войти в систему локально, то можно будет взглянуть на переменные окружения, имена которых начинаются с SSH_
, и узнать подробности о SSH-соединении. Например, это переменные $SSH_CLIENT
и $SSH_TTY
.
Конечно, вам, чтобы вышеприведённые команды заработали бы у вас, нужно будет поменять имена хостов и директорий, а так же — адреса портов на те, которые используются в ваших системах. Но после того, как всё будет настроено, все нужные вам файлы будут доступны и на локальной, и на удалённой машинах. Я, кстати, не пытался организовать циклическое монтирование директорий. Если попытаться это сделать — может получиться нечто очень странное.
Итоги
Полагаю, нужно с осторожностью выполнять одновременное монтирование удалённых папок на локальной машине и локальных папок на удалённой машине. Например, утилиты, занимающиеся сканированием всей файловой системы, могут в таких конфигурациях запутаться. Кроме того, я всё ещё ищу ответ на вопрос о том, как правильно отключаться от серверной файловой системы при выходе из последней сессии.
Но и сейчас всё это даёт нам хорошие инструменты для организации удобной и надёжной работы с файлами по ssh
. Надо отметить, что ещё одним вариантом решения задачи по работе с файлами удалённых систем может стать синхронизация папок и использование их для передачи файлов между компьютерами.
Чем вы пользуетесь для работы с файлами удалённых Linux-систем?